use chess::{Board, Piece, EMPTY};
use rustc_hash::{FxHashMap, FxHashSet};
use crate::{
deduction::{is_statically_unwinnable, Analysis},
search::{
check_chain_search, compute_bishop_distances, compute_punishable, iterative_deepening,
play_forced_moves, probe_non_pawn_moves, Search,
},
winnability::fast::exhaustively_unwinnable,
Winnability,
};
pub(crate) fn analysis(board: &Board) -> Option<Winnability> {
let mut search = Search::new();
let mut pos = *board;
pos = play_forced_moves(&pos, &mut search);
if search.interrupted {
return Some(Winnability::Unwinnable);
}
search.depth_node_limit = 1000;
search.transposition_table = None;
search.reset_global_nodes();
let result = iterative_deepening(&pos, &mut search, 1..=1);
if let Some(result) = result {
return Some(result);
}
let has_queens_rooks_or_knights =
(pos.pieces(Piece::Queen) | pos.pieces(Piece::Rook) | pos.pieces(Piece::Knight)) != EMPTY;
if !has_queens_rooks_or_knights && is_statically_unwinnable(&pos) {
return Some(Winnability::Unwinnable);
}
search.depth_node_limit = 7000;
search.transposition_table =
Some(FxHashMap::with_capacity_and_hasher(1_000, Default::default()));
search.reset_global_nodes();
let result = iterative_deepening(&pos, &mut search, 2..=128);
if let Some(result) = result {
return Some(result);
}
if has_queens_rooks_or_knights && is_statically_unwinnable(&pos) {
return Some(Winnability::Unwinnable);
}
let mut non_pawn_seen = [false; 2];
probe_non_pawn_moves(&pos, &mut non_pawn_seen, &mut 0, 1_000);
if non_pawn_seen.iter().any(|&seen| !seen) && exhaustively_unwinnable(&pos) {
return Some(Winnability::Unwinnable);
}
let mut visited: FxHashSet<Board> = FxHashSet::with_capacity_and_hasher(64, Default::default());
let result = check_chain_search(&pos, &mut visited, 0);
if let Some(result) = result {
return Some(result);
}
let mut analysis = Analysis::new(pos);
analysis.saturate();
search.bishop_distances = Some(compute_bishop_distances(&pos, analysis.steady));
search.punishable = Some(compute_punishable(&pos));
search.depth_node_limit = u64::MAX;
search.global_node_limit = 1 << 24;
search.transposition_table =
Some(FxHashMap::with_capacity_and_hasher(1 << 16, Default::default()));
search.reset_global_nodes();
iterative_deepening(&pos, &mut search, 2..=128)
}