Files
zeal/src/search/iterative_deepening.rs

108 lines
3.2 KiB
Rust

use crate::{
board::game::Game,
evaluation::{MAX_SCORE, MIN_SCORE},
interface::uci::Response,
movegen::r#move::Move,
};
use super::{
negamax, time::TimeInfo, ASPIRATION_WINDOW_DEPTH_THRESHOLD, ASPIRATION_WINDOW_EXPANSION,
ASPIRATION_WINDOW_INITIAL,
};
pub fn iterative_deepening(
game: &mut Game,
max_depth: u8,
time: &TimeInfo,
) -> anyhow::Result<Option<Move>> {
let mut best_move = None;
let mut best_score = MIN_SCORE;
'iterative_deepening: for depth in 1..=max_depth {
if time.exceed_soft_limit() {
println!("Soft limit exceeded in negamax");
return Ok(best_move);
}
let mut nodes = 0;
let mut score;
if depth < ASPIRATION_WINDOW_DEPTH_THRESHOLD {
score = negamax::negamax(game, MIN_SCORE, MAX_SCORE, depth, 0, time, &mut nodes, true);
} else {
let mut window_size = ASPIRATION_WINDOW_INITIAL;
let mut alpha = (best_score - window_size).max(MIN_SCORE);
let mut beta = (best_score + window_size).min(MAX_SCORE);
'aspiration_windows: loop {
score = negamax::negamax(game, alpha, beta, depth, 0, time, &mut nodes, true);
let score = match score {
Ok(score) => score,
Err(ref e) => {
println!("Error: {}", Response::Info(e.to_string()));
break 'iterative_deepening;
}
};
if score >= beta {
beta = MAX_SCORE.min(beta.saturating_add(window_size));
window_size = window_size.saturating_mul(ASPIRATION_WINDOW_EXPANSION);
} else if score <= alpha {
alpha = MIN_SCORE.max(alpha.saturating_sub(window_size));
window_size = window_size.saturating_mul(ASPIRATION_WINDOW_EXPANSION);
} else {
best_score = score;
break 'aspiration_windows;
}
}
}
if let Err(e) = score {
println!("Error: {}", Response::Info(e.to_string()));
break;
}
best_move = game.tt.lookup(game.hash).and_then(|entry| entry.mv);
println!(
"info depth {} ms {} nodes {} nps {} eval {} bestmove {}",
depth,
time.instant.elapsed().as_millis(),
nodes,
time.nps(nodes),
score?,
best_move.expect("No best move found")
);
}
Ok(best_move)
}
#[cfg(test)]
mod tests {
use crate::{
board::fen::from_fen,
movegen::attack_generator::init_attacks,
search::{iterative_deepening, time::TimeInfo, INC, MAX_DEPTH, TIME},
};
const FEN: &str = "1r2k2r/2P1pq1p/2npb3/1p3ppP/p3P3/P2B1Q2/1P1PNPP1/R3K2R w KQk g6 0 1";
#[test]
fn test_iterative_deepening() -> anyhow::Result<()> {
init_attacks();
let mut game = from_fen(FEN).unwrap();
let instant = std::time::Instant::now();
iterative_deepening::iterative_deepening(
&mut game,
MAX_DEPTH,
&TimeInfo::new(instant, TIME, INC),
)?;
dbg!(instant.elapsed());
Ok(())
}
}