Yet another chess crate for Rust, with emphasis on speed and safety. Primarily designed for various chess GUIs and tools, it's also possible to use Owlchess to build a fast chess engine.
The code is mostly derived from my chess engine SoFCheck, but rewritten in Rust with regard to safety.
This crate supports core chess functionality:
- generate moves
- make moves
- calculate game outcome
- parse and format boards in FEN
- parse and format moves in UCI and SAN
Fast: chessboard is built upon Magic Bitboards, which is a fast way to generate moves and determine whether the king is in check.
Safe: the library prevents you from creating an invalid board or making an invalid move. While such
safety is usually a good thing, it is enforces by runtime checks, which can slow down your program. For
example, validation in owlchess::Move::make
makes this function about 30-50% slower. So, if performance
really matters, you may use unsafe APIs for speedup.
use owlchess::{Board, movegen::legal};
fn main() {
// Create a board from FEN
let board = Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
.unwrap();
// Generate legal moves
let moves = legal::gen_all(&board);
assert_eq!(moves.len(), 20);
}
use owlchess::{Board, Move};
fn main() {
// Create a board with initial position
let board = Board::initial();
// Create a legal move from UCI notation
let mv = Move::from_uci_legal("e2e4", &board).unwrap();
// Create a new board with move `mv` made on it
let board = board.make_move(mv).unwrap();
assert_eq!(
board.as_fen(),
"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"
.to_string(),
);
}
The example below illustrates a MoveChain
, which represents a chess game. Unlike Board
, MoveChain
keeps
the history of moves and is able to detect draw by repetitions.
use owlchess::{Outcome, moves::make::Uci, types::OutcomeFilter, Color, WinReason, MoveChain};
fn main() {
// Create a `MoveChain` from initial position
let mut chain = MoveChain::new_initial();
// Push the moves into `MoveChain` as UCI strings
chain.push(Uci("g2g4")).unwrap();
chain.push(Uci("e7e5")).unwrap();
chain.push(Uci("f2f3")).unwrap();
chain.push(Uci("d8h4")).unwrap();
// Calculate current game outcome
chain.set_auto_outcome(OutcomeFilter::Strict);
assert_eq!(
chain.outcome(),
&Some(Outcome::Win {
side: Color::Black,
reason: WinReason::Checkmate,
}),
);
}
Some examples are located in the chess/examples
directory and crate documentation.
They may give you more ideas on how to use the crate.
This crate is currently tested only with Rust 1.71 or higher, but can possibly work with older versions. Rust versions before 1.64 are not supported.
There are two well-known chess crates in Rust: chess
and
shakmaty
. These crates are compared with owlchess
below.
Compared to chess
, owlchess
provides more features:
- distinction between various game outcomes
- draw by insufficient material
- formatting SAN moves
- more safety: the board is guaranteed to be valid, as you cannot make an illegal move without
unsafe
- more detailed errors in case of failures
Still, chess
has some advantages:
- faster legal move generator (
owlchess
relies on fast semilegal move generator instead) - more mature code base
But, in many applications, it's enough to have a fast semilegal move generator and fast move validation, so real difference in performance may be less than expected.
Compared to shakmaty
, owlchess
has the following advantages:
- more safety: the board is guaranteed to be valid, as you cannot make an illegal move without
unsafe
- has support for draw by repetitions
- uses more liberal MIT license instead of GPLv3
Still, shakmaty
has some advantages:
- faster legal move generator
- moves are applied faster (especially if Zobrist hashing is not used)
- supports many chess variants
There is a separate repo with benchmarks for different chess implementations in Rust.
This repository is licensed under the MIT License. See LICENSE
for more details.