use chess::{Board, Color, MoveGen, Piece, EMPTY};
use rustc_hash::FxHashSet;
use crate::{deduction::is_statically_unwinnable, Winnability};
pub(crate) fn probe_non_pawn_moves(
board: &Board,
non_pawn_seen: &mut [bool; 2],
nodes: &mut u64,
max_nodes: u64,
) {
for m in MoveGen::new_legal(board) {
let color_idx = board.side_to_move().to_index();
if board.piece_on(m.get_source()) != Some(Piece::Pawn) {
non_pawn_seen[color_idx] = true;
}
*nodes += 1;
if *nodes >= max_nodes || non_pawn_seen.iter().all(|&s| s) {
return;
}
let new_board = board.make_move_new(m);
probe_non_pawn_moves(&new_board, non_pawn_seen, nodes, max_nodes);
if *nodes >= max_nodes || non_pawn_seen.iter().all(|&s| s) {
return;
}
}
}
pub(crate) fn check_chain_search(
board: &Board,
visited: &mut FxHashSet<Board>,
depth: u32,
) -> Option<Winnability> {
if depth > 16 {
return None;
}
visited.insert(*board);
let mut legal_moves = MoveGen::new_legal(board).peekable();
if legal_moves.peek().is_none() {
if board.side_to_move() == Color::Black && *board.checkers() != EMPTY {
return Some(Winnability::Winnable { helpmate: vec![] });
}
return Some(Winnability::Unwinnable);
}
for m in legal_moves {
let new_board = board.make_move_new(m);
if visited.contains(&new_board) {
continue;
}
if *new_board.checkers() != EMPTY || depth == 0 {
match check_chain_search(&new_board, visited, depth + 1) {
w @ Some(Winnability::Winnable { .. }) => return w,
None => return None,
Some(Winnability::Unwinnable) => continue,
}
}
if !is_statically_unwinnable(&new_board) {
return None;
}
}
Some(Winnability::Unwinnable)
}