67 lines
No EOL
2.3 KiB
Rust
67 lines
No EOL
2.3 KiB
Rust
use crate::board::*;
|
|
use crate::eval::piece_square_tables::PSQT;
|
|
|
|
pub fn evaluate_board(board: &Board) -> i32 {
|
|
let mut mg_score = 0_i32;
|
|
let mut eg_score = 0_i32;
|
|
let mut phase = 0_i32;
|
|
|
|
// We use a macro to force loop unrolling.
|
|
// This enables the compiler to use constant offsets for PSQT access
|
|
// instead of calculating addresses at runtime based on a loop variable.
|
|
macro_rules! score_piece {
|
|
($pt:expr, $phase_weight:expr) => {
|
|
// --- WHITE ---
|
|
let mut pieces = board.pieces[$pt][Color::White as usize];
|
|
if pieces > 0 {
|
|
// Phase calculation uses count_ones (POPPCNT) which is very fast
|
|
phase += (pieces.count_ones() as i32) * $phase_weight;
|
|
|
|
while pieces > 0 {
|
|
let sq = pieces.trailing_zeros() as usize;
|
|
pieces &= pieces - 1; // Clear LS1B
|
|
|
|
// Material is already baked into PSQT, so we just add the table value
|
|
// Since $pt is a const literal here, this compiles to a direct memory access
|
|
mg_score += PSQT[$pt][Color::White as usize][0][sq];
|
|
eg_score += PSQT[$pt][Color::White as usize][1][sq];
|
|
}
|
|
}
|
|
|
|
// --- BLACK ---
|
|
let mut pieces = board.pieces[$pt][Color::Black as usize];
|
|
if pieces > 0 {
|
|
phase += (pieces.count_ones() as i32) * $phase_weight;
|
|
|
|
while pieces > 0 {
|
|
let sq = pieces.trailing_zeros() as usize;
|
|
pieces &= pieces - 1;
|
|
|
|
mg_score -= PSQT[$pt][Color::Black as usize][0][sq];
|
|
eg_score -= PSQT[$pt][Color::Black as usize][1][sq];
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// Explicitly unrolled execution order
|
|
// Pawn (0), Weight 0
|
|
score_piece!(0, 0);
|
|
// Knight (1), Weight 1
|
|
score_piece!(1, 1);
|
|
// Bishop (2), Weight 1
|
|
score_piece!(2, 1);
|
|
// Rook (3), Weight 2
|
|
score_piece!(3, 2);
|
|
// Queen (4), Weight 4
|
|
score_piece!(4, 4);
|
|
// King (5), Weight 0 (Phase doesn't change)
|
|
score_piece!(5, 0);
|
|
|
|
// Tapered Evaluation
|
|
let phase = phase.min(24);
|
|
let mg_phase = phase;
|
|
let eg_phase = 24 - phase;
|
|
|
|
((mg_score * mg_phase) + (eg_score * eg_phase)) / 24
|
|
} |