Add minimax and adapt UCI tests

This commit is contained in:
stefiosif
2024-09-01 14:15:02 +03:00
parent e61d247411
commit ba0cbf4d7d
6 changed files with 123 additions and 58 deletions

87
src/search/minimax.rs Normal file
View File

@@ -0,0 +1,87 @@
use crate::{
board::{
board::Color,
game::Game,
history::{History, MoveParameters},
},
evaluation::evaluation::evaluate_position,
movegen::r#move::Move,
};
pub fn minimax(game: &mut Game, depth: u8) -> (Option<Move>, i32) {
let color = game.current_player();
if depth == 0 {
return (None, evaluate_position(&game.board, color));
}
let mut history = History::new();
let mut best_move: Option<Move> = None;
let (mut best_score, mate_score) = match color {
Color::White => (-100000, -49000 - depth as i32),
Color::Black => (100000, 49000 + depth as i32),
};
let moves = game.board.pseudo_moves_all(color);
let mut legal_moves = 0;
for mv in moves {
history.push_move_parameters(MoveParameters::build(&game.board, &mv));
game.board.make_move(&mv);
if !game.board.king_under_check(color) {
legal_moves += 1;
let (_, node_score) = minimax(game, depth - 1);
match color {
Color::White => {
if best_score < node_score {
best_score = node_score;
best_move = Some(mv);
}
}
Color::Black => {
if best_score > node_score {
best_score = node_score;
best_move = Some(mv);
}
}
}
}
game.board
.unmake_move(history.pop_move_parameters().expect("Empty history stack"));
}
if legal_moves == 0 {
if game.board.king_under_check(color) {
return (None, mate_score);
} else {
return (None, 0);
}
}
(best_move, best_score)
}
#[cfg(test)]
mod tests {
use crate::board::{fen::from_fen, square::Square};
use crate::movegen::attack::init_attacks;
use crate::movegen::r#move::Move;
use crate::search::minimax::minimax;
const FEN_MATE_IN_1: &str = "8/8/8/8/8/4q1k1/8/5K2 b - - 0 1";
#[test]
fn test_minimax() -> Result<(), String> {
init_attacks();
let mut game = from_fen(FEN_MATE_IN_1)?;
let e3f2 = Move::new(Square::E3, Square::F2);
assert_eq!(e3f2, minimax(&mut game, 2).0.unwrap());
assert_eq!(e3f2, minimax(&mut game, 3).0.unwrap());
assert_eq!(e3f2, minimax(&mut game, 4).0.unwrap());
assert_eq!(e3f2, minimax(&mut game, 5).0.unwrap());
Ok(())
}
}

View File

@@ -1,2 +1,2 @@
pub mod minimax;
pub mod perft;
pub mod search;

View File

@@ -1,42 +0,0 @@
use crate::board::game::Game;
pub fn search(game: &mut Game, depth: u8) {
if depth == 0 {
return;
}
let color = game.current_player();
let pseudo_moves = game.board.pseudo_moves_all(color);
for mv in pseudo_moves {
let original_board = game.board.clone();
game.board.make_move(&mv);
if game.board.king_under_check(color) {
game.board = original_board;
continue;
}
search(game, depth - 1);
game.board = original_board;
}
}
#[cfg(test)]
mod tests {
use crate::board::fen::from_fen;
const FEN_QUIET: [&str; 2] = [
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
"rnbqkbnr/ppp2ppp/4p3/3pN3/3P4/8/PPP1PPPP/RNBQKB1R w KQkq - 0 1",
];
#[test]
fn test_search() -> Result<(), String> {
let _game = from_fen(FEN_QUIET[0])?;
//TODO:
Ok(())
}
}