mod engine;
mod heuristics;
mod probes;
mod utils;
use std::ops::RangeInclusive;
use chess::{Board, MoveGen};
pub(crate) use engine::Search;
pub(crate) use probes::{check_chain_search, probe_non_pawn_moves};
use rustc_hash::FxHashSet;
pub(crate) use utils::{
compute_bishop_distances, compute_punishable, has_lonely_pawns, insufficient_white_material,
nb_blocked_pawns, only_pawns_and_bishops,
};
use crate::Winnability;
pub(crate) fn play_forced_moves(board: &Board, search: &mut Search) -> Board {
let mut board = *board;
let mut seen_positions: Option<FxHashSet<Board>> = None;
for _ in 0..16 {
let mut moves = MoveGen::new_legal(&board).peekable();
let Some(m) = moves.next() else { break };
if moves.peek().is_some() {
break;
}
let seen = seen_positions.get_or_insert_with(|| {
let mut set = FxHashSet::with_capacity_and_hasher(16, Default::default());
set.insert(board);
set
});
board = board.make_move_new(m);
search.moves.push(m);
search.iteration_nodes += 1;
if !seen.insert(board) {
search.reset_iteration();
search.interrupted = true;
return board;
}
}
if seen_positions.is_some() {
search.reset_iteration();
}
board
}
pub(crate) fn iterative_deepening(
board: &Board,
search: &mut Search,
depths_range: RangeInclusive<u8>,
) -> Option<Winnability> {
for depth in depths_range {
search.max_depth = depth;
search.reset_iteration();
match engine::helpmate(board, search, 0) {
Some(helpmate) => return Some(Winnability::Winnable { helpmate }),
None if !search.interrupted => return Some(Winnability::Unwinnable),
None => (),
}
}
None
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use chess::Board;
use super::*;
#[test]
fn test_play_forced_moves() {
let board = Board::from_str("7k/8/6K1/8/8/8/8/6Q1 b - -").unwrap();
let mut search = Search::new();
let result = play_forced_moves(&board, &mut search);
assert_ne!(result, board, "Should have made at least one forced move");
assert!(!search.interrupted);
let board = Board::from_str("k1b5/1p1p4/1P1P4/8/8/4p1p1/4P1P1/5B1K w - -").unwrap();
let mut search = Search::new();
play_forced_moves(&board, &mut search);
assert!(search.interrupted, "Should detect repetition");
}
}