use std::cmp;
use std::time::Instant;
use crate::coretypes::Color::*;
use crate::coretypes::{Cp, Move, PlyKind, Square};
use crate::eval::{evaluate_abs, terminal_abs};
use crate::movelist::Line;
use crate::search::SearchResult;
use crate::Position;
const WHITE: u8 = White as u8;
const BLACK: u8 = Black as u8;
pub fn minimax(position: Position, ply: PlyKind) -> SearchResult {
assert_ne!(ply, 0);
let instant = Instant::now();
let mut pv = Line::new();
let mut nodes = 0;
let (score, best_move) = minimax_root(position, ply, &mut nodes);
pv.push(best_move);
SearchResult {
player: position.player,
depth: ply,
best_move,
score,
pv,
nodes,
elapsed: instant.elapsed(),
stopped: false,
..Default::default()
}
}
fn minimax_root(mut position: Position, ply: PlyKind, nodes: &mut u64) -> (Cp, Move) {
*nodes += 1;
let cache = position.cache();
let legal_moves = position.get_legal_moves();
assert_ne!(ply, 0);
assert!(legal_moves.len() > 0);
let mut best_move = Move::new(Square::D2, Square::D4, None);
let mut best_cp;
if position.player == White {
best_cp = Cp::MIN;
for legal_move in legal_moves {
let move_info = position.do_move(legal_move);
let move_cp = minimax_impl::<BLACK>(&mut position, ply - 1, nodes);
position.undo_move(move_info, cache);
if move_cp > best_cp {
best_cp = move_cp;
best_move = legal_move;
}
}
} else {
best_cp = Cp::MAX;
for legal_move in legal_moves {
let move_info = position.do_move(legal_move);
let move_cp = minimax_impl::<WHITE>(&mut position, ply - 1, nodes);
position.undo_move(move_info, cache);
if move_cp < best_cp {
best_cp = move_cp;
best_move = legal_move;
}
}
}
(best_cp, best_move)
}
fn minimax_impl<const COLOR: u8>(position: &mut Position, ply: PlyKind, nodes: &mut u64) -> Cp {
*nodes += 1;
let cache = position.cache();
let legal_moves = position.get_legal_moves();
let num_moves = legal_moves.len();
if num_moves == 0 {
return terminal_abs(position);
} else if ply == 0 {
return evaluate_abs(position);
}
let mut best_cp;
if COLOR == White as u8 {
best_cp = Cp::MIN;
for legal_move in legal_moves {
let move_info = position.do_move(legal_move);
let move_cp = minimax_impl::<BLACK>(position, ply - 1, nodes);
position.undo_move(move_info, cache);
best_cp = cmp::max(best_cp, move_cp);
}
} else {
best_cp = Cp::MAX;
for legal_move in legal_moves {
let move_info = position.do_move(legal_move);
let move_cp = minimax_impl::<WHITE>(position, ply - 1, nodes);
position.undo_move(move_info, cache);
best_cp = cmp::min(best_cp, move_cp);
}
}
best_cp
}