You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

157 lines
4.6 KiB

use rand::prelude::*;
use std::f64::{INFINITY, NEG_INFINITY};
use chess::{Board, BoardStatus, ChessMove, Color, MoveGen, Piece};
fn static_board_eval(
mov: ChessMove,
board: Board,
playing_as: Color,
move_history: Vec<(ChessMove, Board)>,
) -> f64 {
if move_history.len() > 6 {
if move_history[move_history.len() - 1].0 == mov
&& move_history[move_history.len() - 2].0 == mov
{
return -666.0;
}
}
let mut current_eval = 0.0;
// basic material counting
board.color_combined(playing_as).for_each(|square| {
match board.piece_on(square) {
Some(Piece::Pawn) => current_eval += 1.0,
Some(Piece::Knight) => current_eval += 3.0,
Some(Piece::Bishop) => current_eval += 5.0,
Some(Piece::Rook) => current_eval += 5.0,
Some(Piece::Queen) => current_eval += 8.0,
_ => { /* do nothing */ }
}
});
board.color_combined(!playing_as).for_each(|square| {
match board.piece_on(square) {
Some(Piece::Pawn) => current_eval -= 1.0,
Some(Piece::Knight) => current_eval -= 3.0,
Some(Piece::Bishop) => current_eval -= 5.0,
Some(Piece::Rook) => current_eval -= 5.0,
Some(Piece::Queen) => current_eval -= 8.0,
_ => { /* do nothing */ }
}
});
// checking heuristic
let mut are_we_in_check = false;
let mut is_opponent_in_check = false;
board
.checkers()
.filter(|sq| board.color_on(*sq).unwrap() == playing_as)
.for_each(|_| {
if !are_we_in_check {
current_eval -= 66.6;
are_we_in_check = true;
} else {
current_eval -= 12.5;
}
});
board
.checkers()
.filter(|sq| board.color_on(*sq).unwrap() == !playing_as)
.for_each(|_| {
if !is_opponent_in_check
&& move_history.len()
> *vec![10, 11, 12, 13, 14, 15]
.choose(&mut rand::thread_rng())
.unwrap() as usize
{
current_eval += 17.5;
is_opponent_in_check = true;
} else {
current_eval += 3.5;
}
});
// deprioritize king movement
if board.piece_on(mov.get_source()).unwrap_or(Piece::Pawn) == Piece::King && !are_we_in_check {
current_eval -= 12.5;
}
current_eval
}
pub fn eval_board(
board: Board,
is_maximizing_player: bool,
depth: u8,
move_history: Vec<(ChessMove, Board)>,
last_move: Option<ChessMove>,
original_playing_as: Color,
mut alpha: f64,
mut beta: f64,
) -> f64 {
let moves_iter = MoveGen::new_legal(&board).into_iter();
if depth == 0 || board.status() == BoardStatus::Checkmate {
return static_board_eval(
last_move.unwrap_or(move_history.last().unwrap().0),
board,
original_playing_as,
move_history,
);
} else {
if is_maximizing_player {
let mut max_eval = NEG_INFINITY;
for mov in moves_iter {
let mut new_move_history = move_history.clone();
let new_board = board.make_move_new(mov);
new_move_history.push((mov, new_board));
let eval = eval_board(
new_board,
false,
depth - 1,
new_move_history,
Some(mov),
original_playing_as,
alpha,
beta,
);
max_eval = max_eval.max(eval);
alpha = alpha.max(eval);
if beta <= alpha {
break;
}
}
return max_eval;
} else {
let mut min_eval = INFINITY;
for mov in moves_iter {
let mut new_move_history = move_history.clone();
let new_board = board.make_move_new(mov);
new_move_history.push((mov, new_board));
let eval = eval_board(
new_board,
true,
depth - 1,
new_move_history,
Some(mov),
original_playing_as,
alpha,
beta,
);
min_eval = min_eval.min(eval);
beta = beta.min(eval);
if beta <= alpha {
break;
}
}
return min_eval;
}
}
}