A fast, UCI-compatible chess engine written in Rust. The engine uses a bitboard representation, iterative deepening with alpha-beta pruning, and a feature-rich evaluation function to provide strong play while remaining easy to hack on. It can be used as a library, driven from the command line, or plugged into any UCI-compatible GUI.
- Modern search: Negamax with alpha-beta pruning, iterative deepening, quiescence search, late-move pruning, and aspiration windows.
- Smart move ordering: Hash move, MVV-LVA captures, killer moves, and history heuristics to reach cutoffs quickly.
- Transposition table: Zobrist hashing with configurable table size and automatic re-initialization when the size changes.
- Evaluation: Material balance, piece-square tables, tempo bonuses, passed pawns, king safety, and mobility scoring.
- Protocols: First-class UCI support with options for hash size, thread
count, pondering, and configurable timing margins. XBoard hooks are available
via
src/xboard. - Position handling: FEN parsing/building, legal move generation, make/unmake with incremental hashing, and draw/stalemate detection.
- Parallel search: Optional symmetric multiprocessing (SMP) search to use multiple threads when configured.
- Extensibility: The
chess_enginecrate exposes the board, move generation, search, and transposition table APIs for embedding in other projects.
- Install Rust (stable) from rustup.rs.
- Build the engine:
cargo build --release
- Run the UCI console:
cargo run --release
From here you can issue standard UCI commands. A typical session looks like:
uci # Print engine id and available options
isready # Wait for the engine to finish initialization
position startpos moves e2e4 e7e5
setoption name Threads value 4
setoption name Hash value 1024
setoption name Move Overhead value 75
setoption name Ponder value true
isready
perft depth 4 # Verify move generation
go wtime 600000 btime 600000 winc 2000 binc 2000
Use the crate directly when you need programmatic access:
use chess_engine::board::{Board, find_best_move, SearchState};
use std::sync::atomic::AtomicBool;
let mut board = Board::new();
board.make_move_uci("e2e4").unwrap();
let mut state = SearchState::new(256); // transposition table size in MB
let stop = AtomicBool::new(false);
if let Some(best) = find_best_move(&mut board, &mut state, 6, &stop) {
println!("Best move: {}", best);
}- Hash / Threads:
setoption name Hash value <mb>andsetoption name Threads value <n>reconfigure the transposition table and SMP search. - Timing:
Move Overhead,Soft Time Percent, andHard Time Percentadjust how conservative the engine is with time usage. - Limits:
Max NodesandMultiPVcontrol search scope and number of principal variations returned. - Ponder: Enable with
setoption name Ponder value trueand useponderhitwhen the GUI transitions from pondering to actual search.
- Run tests:
cargo test - Property tests:
cargo test -- --ignored(for proptest-heavy cases) - Benchmarks:
cargo bench --bench engine_benchmarks(requires nightly for HTML reports) - Linting:
cargo clippy --all-targets --all-features