From aecc99493900c324db090ffbfa3159863505d3c9 Mon Sep 17 00:00:00 2001 From: Patrick Heck <49785565+FitzOReilly@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:53:42 +0100 Subject: [PATCH 1/3] Refactor pawn structure evaluation --- eval/src/hand_crafted_eval.rs | 345 +++++++++++++++++++++------------- 1 file changed, 215 insertions(+), 130 deletions(-) diff --git a/eval/src/hand_crafted_eval.rs b/eval/src/hand_crafted_eval.rs index 4072514..968d1c2 100644 --- a/eval/src/hand_crafted_eval.rs +++ b/eval/src/hand_crafted_eval.rs @@ -14,6 +14,37 @@ use movegen::position::Position; use movegen::queen::Queen; use movegen::rook::Rook; use movegen::side::Side; +use movegen::square::Square; + +#[derive(Debug)] +struct EvalData { + king_moved: bool, + kings: [Square; 2], + pawns_changed: [bool; 2], + pawns: [Bitboard; 2], +} + +impl EvalData { + pub fn new(prev_pos: &Position, pos: &Position) -> Self { + let prev_white_king = prev_pos.piece_occupancy(Side::White, piece::Type::King); + let white_king = pos.piece_occupancy(Side::White, piece::Type::King); + let prev_black_king = prev_pos.piece_occupancy(Side::Black, piece::Type::King); + let black_king = pos.piece_occupancy(Side::Black, piece::Type::King); + let prev_white_pawns = prev_pos.piece_occupancy(Side::White, piece::Type::Pawn); + let white_pawns = pos.piece_occupancy(Side::White, piece::Type::Pawn); + let prev_black_pawns = prev_pos.piece_occupancy(Side::Black, piece::Type::Pawn); + let black_pawns = pos.piece_occupancy(Side::Black, piece::Type::Pawn); + Self { + king_moved: prev_white_king != white_king || prev_black_king != black_king, + kings: [white_king.to_square(), black_king.to_square()], + pawns_changed: [ + prev_white_pawns != white_pawns, + prev_black_pawns != black_pawns, + ], + pawns: [white_pawns, black_pawns], + } + } +} #[derive(Debug, Clone)] pub struct HandCraftedEval { @@ -21,7 +52,9 @@ pub struct HandCraftedEval { game_phase: GamePhase, piece_counts: PieceCounts, pst_scores: ScorePair, - pawn_structure_scores: ScorePair, + passed_pawn_scores: ScorePair, + isolated_and_doubled_pawn_scores: [ScorePair; 2], + backward_pawn_scores: ScorePair, king_tropism: ScorePair, #[cfg(feature = "trace")] coeffs: HandCraftedEvalCoeffs, @@ -29,11 +62,15 @@ pub struct HandCraftedEval { impl Eval for HandCraftedEval { fn eval(&mut self, pos: &Position) -> Score { - self.update(pos); + let eval_data = EvalData::new(&self.current_pos, pos); + self.update(&eval_data, pos); let scores = self.pst_scores + self.tempo_scores(pos) - + self.pawn_structure_scores + + self.passed_pawn_scores + + self.isolated_and_doubled_pawn_scores[Side::White as usize] + - self.isolated_and_doubled_pawn_scores[Side::Black as usize] + + self.backward_pawn_scores + self.mobility_scores(pos) + self.bishop_pair_scores(pos) + self.king_tropism; @@ -108,7 +145,9 @@ impl HandCraftedEval { game_phase: Default::default(), piece_counts: Default::default(), pst_scores: Default::default(), - pawn_structure_scores: Default::default(), + passed_pawn_scores: Default::default(), + isolated_and_doubled_pawn_scores: Default::default(), + backward_pawn_scores: Default::default(), king_tropism: Default::default(), #[cfg(feature = "trace")] coeffs: Default::default(), @@ -120,17 +159,7 @@ impl HandCraftedEval { &self.coeffs } - fn update(&mut self, pos: &Position) { - let old_white_king = self - .current_pos - .piece_occupancy(Side::White, piece::Type::King); - let new_white_king = pos.piece_occupancy(Side::White, piece::Type::King); - let old_black_king = self - .current_pos - .piece_occupancy(Side::Black, piece::Type::King); - let new_black_king = pos.piece_occupancy(Side::Black, piece::Type::King); - let white_king = new_white_king.to_square(); - let black_king = new_black_king.to_square(); + fn update(&mut self, eval_data: &EvalData, pos: &Position) { for (piece_type, table, friendly_distance, enemy_distance) in [ ( piece::Type::Pawn, @@ -169,20 +198,28 @@ impl HandCraftedEval { ¶ms::DISTANCE_ENEMY_KING, ), ] { - let old_white = self.current_pos.piece_occupancy(Side::White, piece_type); - let new_white = pos.piece_occupancy(Side::White, piece_type); - let mut white_remove = old_white & !new_white; - let mut white_add = new_white & !old_white; + let prev_white = self.current_pos.piece_occupancy(Side::White, piece_type); + let current_white = pos.piece_occupancy(Side::White, piece_type); + let mut white_remove = prev_white & !current_white; + let mut white_add = current_white & !prev_white; while white_remove != Bitboard::EMPTY { let square = white_remove.square_scan_forward_reset(); self.pst_scores -= table[square.idx()]; self.game_phase.remove_piece(piece_type); let p = Piece::new(Side::White, piece_type); self.piece_counts.remove(p); - self.king_tropism -= friendly_distance[white_king.distance(square)]; - self.king_tropism += enemy_distance[black_king.distance(square)]; + self.king_tropism -= + friendly_distance[eval_data.kings[Side::White as usize].distance(square)]; + self.king_tropism += + enemy_distance[eval_data.kings[Side::Black as usize].distance(square)]; #[cfg(feature = "trace")] - self.coeffs.add_piece(p, square, white_king, black_king, -1); + self.coeffs.add_piece( + p, + square, + eval_data.kings[Side::White as usize], + eval_data.kings[Side::Black as usize], + -1, + ); } while white_add != Bitboard::EMPTY { let square = white_add.square_scan_forward_reset(); @@ -190,15 +227,23 @@ impl HandCraftedEval { self.game_phase.add_piece(piece_type); let p = Piece::new(Side::White, piece_type); self.piece_counts.add(p); - self.king_tropism += friendly_distance[white_king.distance(square)]; - self.king_tropism -= enemy_distance[black_king.distance(square)]; + self.king_tropism += + friendly_distance[eval_data.kings[Side::White as usize].distance(square)]; + self.king_tropism -= + enemy_distance[eval_data.kings[Side::Black as usize].distance(square)]; #[cfg(feature = "trace")] - self.coeffs.add_piece(p, square, white_king, black_king, 1); + self.coeffs.add_piece( + p, + square, + eval_data.kings[Side::White as usize], + eval_data.kings[Side::Black as usize], + 1, + ); } - let old_black = self.current_pos.piece_occupancy(Side::Black, piece_type); - let new_black = pos.piece_occupancy(Side::Black, piece_type); - let mut black_remove = old_black & !new_black; - let mut black_add = new_black & !old_black; + let prev_black = self.current_pos.piece_occupancy(Side::Black, piece_type); + let current_black = pos.piece_occupancy(Side::Black, piece_type); + let mut black_remove = prev_black & !current_black; + let mut black_add = current_black & !prev_black; while black_remove != Bitboard::EMPTY { let square = black_remove.square_scan_forward_reset(); let square_flipped = square.flip_vertical(); @@ -206,10 +251,18 @@ impl HandCraftedEval { self.game_phase.remove_piece(piece_type); let p = Piece::new(Side::Black, piece_type); self.piece_counts.remove(p); - self.king_tropism -= enemy_distance[white_king.distance(square)]; - self.king_tropism += friendly_distance[black_king.distance(square)]; + self.king_tropism -= + enemy_distance[eval_data.kings[Side::White as usize].distance(square)]; + self.king_tropism += + friendly_distance[eval_data.kings[Side::Black as usize].distance(square)]; #[cfg(feature = "trace")] - self.coeffs.add_piece(p, square, white_king, black_king, -1); + self.coeffs.add_piece( + p, + square, + eval_data.kings[Side::White as usize], + eval_data.kings[Side::Black as usize], + -1, + ); } while black_add != Bitboard::EMPTY { let square = black_add.square_scan_forward_reset(); @@ -218,27 +271,29 @@ impl HandCraftedEval { self.game_phase.add_piece(piece_type); let p = Piece::new(Side::Black, piece_type); self.piece_counts.add(p); - self.king_tropism += enemy_distance[white_king.distance(square)]; - self.king_tropism -= friendly_distance[black_king.distance(square)]; + self.king_tropism += + enemy_distance[eval_data.kings[Side::White as usize].distance(square)]; + self.king_tropism -= + friendly_distance[eval_data.kings[Side::Black as usize].distance(square)]; #[cfg(feature = "trace")] - self.coeffs.add_piece(p, square, white_king, black_king, 1); + self.coeffs.add_piece( + p, + square, + eval_data.kings[Side::White as usize], + eval_data.kings[Side::Black as usize], + 1, + ); } } - if old_white_king != new_white_king || old_black_king != new_black_king { + if eval_data.king_moved { // A king was moved, calculate king tropism for all pieces - self.update_king_tropism(pos); + self.update_king_tropism(eval_data, pos); } - self.update_pawn_structure_scores(pos); + self.update_pawn_structure_scores(eval_data); self.current_pos = pos.clone(); } - fn update_king_tropism(&mut self, pos: &Position) { - let white_king = pos - .piece_occupancy(Side::White, piece::Type::King) - .to_square(); - let black_king = pos - .piece_occupancy(Side::Black, piece::Type::King) - .to_square(); + fn update_king_tropism(&mut self, eval_data: &EvalData, pos: &Position) { self.king_tropism = ScorePair(0, 0); #[cfg(feature = "trace")] self.coeffs.clear_distance(); @@ -275,25 +330,39 @@ impl HandCraftedEval { let mut white_pieces = pos.piece_occupancy(Side::White, piece_type); while white_pieces != Bitboard::EMPTY { let square = white_pieces.square_scan_forward_reset(); - self.king_tropism += friendly_distance[white_king.distance(square)]; - self.king_tropism -= enemy_distance[black_king.distance(square)]; + self.king_tropism += + friendly_distance[eval_data.kings[Side::White as usize].distance(square)]; + self.king_tropism -= + enemy_distance[eval_data.kings[Side::Black as usize].distance(square)]; #[cfg(feature = "trace")] { let p = Piece::new(Side::White, piece_type); - self.coeffs - .add_distance(p, square, white_king, black_king, 1); + self.coeffs.add_distance( + p, + square, + eval_data.kings[Side::White as usize], + eval_data.kings[Side::Black as usize], + 1, + ); } } let mut black_pieces = pos.piece_occupancy(Side::Black, piece_type); while black_pieces != Bitboard::EMPTY { let square = black_pieces.square_scan_forward_reset(); - self.king_tropism += enemy_distance[white_king.distance(square)]; - self.king_tropism -= friendly_distance[black_king.distance(square)]; + self.king_tropism += + enemy_distance[eval_data.kings[Side::White as usize].distance(square)]; + self.king_tropism -= + friendly_distance[eval_data.kings[Side::Black as usize].distance(square)]; #[cfg(feature = "trace")] { let p = Piece::new(Side::Black, piece_type); - self.coeffs - .add_distance(p, square, white_king, black_king, 1); + self.coeffs.add_distance( + p, + square, + eval_data.kings[Side::White as usize], + eval_data.kings[Side::Black as usize], + 1, + ); } } } @@ -314,105 +383,88 @@ impl HandCraftedEval { bishop_pair_factor * params::BISHOP_PAIR } - fn update_pawn_structure_scores(&mut self, pos: &Position) { - let old_white_pawns = self - .current_pos - .piece_occupancy(Side::White, piece::Type::Pawn); - let white_pawns = pos.piece_occupancy(Side::White, piece::Type::Pawn); - let old_black_pawns = self - .current_pos - .piece_occupancy(Side::Black, piece::Type::Pawn); - let black_pawns = pos.piece_occupancy(Side::Black, piece::Type::Pawn); - - if old_white_pawns != white_pawns || old_black_pawns != black_pawns { - let passed_pawn_score = self.passed_pawn_scores(white_pawns, black_pawns); - let isolated_pawn_score = - Self::isolated_pawn_count(white_pawns, black_pawns) as i16 * params::ISOLATED_PAWN; - let backward_pawn_score = - Self::backward_pawn_count(white_pawns, black_pawns) as i16 * params::BACKWARD_PAWN; - let doubled_pawn_score = - Self::doubled_pawn_count(white_pawns, black_pawns) as i16 * params::DOUBLED_PAWN; - self.pawn_structure_scores = - passed_pawn_score + isolated_pawn_score + backward_pawn_score + doubled_pawn_score; - + fn update_pawn_structure_scores(&mut self, eval_data: &EvalData) { + if eval_data.pawns_changed[Side::White as usize] { + self.update_isolated_and_doubled_pawn_scores_one_side(eval_data, Side::White); + } + if eval_data.pawns_changed[Side::Black as usize] { + self.update_isolated_and_doubled_pawn_scores_one_side(eval_data, Side::Black); + } + if eval_data.pawns_changed[Side::White as usize] + || eval_data.pawns_changed[Side::Black as usize] + { + self.update_backward_pawn_scores(eval_data); #[cfg(feature = "trace")] { - *self.coeffs.isolated_pawn = Self::isolated_pawn_count(white_pawns, black_pawns); - *self.coeffs.backward_pawn = Self::backward_pawn_count(white_pawns, black_pawns); - *self.coeffs.doubled_pawn = Self::doubled_pawn_count(white_pawns, black_pawns); + *self.coeffs.isolated_pawn = + Self::isolated_pawn_count_one_side(eval_data.pawns[Side::White as usize]) + - Self::isolated_pawn_count_one_side(eval_data.pawns[Side::Black as usize]); + *self.coeffs.doubled_pawn = + Self::doubled_pawn_count_one_side(eval_data.pawns[Side::White as usize]) + - Self::doubled_pawn_count_one_side(eval_data.pawns[Side::Black as usize]); } } - } - - fn isolated_pawn_count(white_pawns: Bitboard, black_pawns: Bitboard) -> i8 { - Self::isolated_pawn_count_one_side(white_pawns) - - Self::isolated_pawn_count_one_side(black_pawns) - } - - fn backward_pawn_count(white_pawns: Bitboard, black_pawns: Bitboard) -> i8 { - Self::backward_pawn_count_one_side(white_pawns, black_pawns, Side::White) - - Self::backward_pawn_count_one_side(black_pawns, white_pawns, Side::Black) - } - - fn doubled_pawn_count(white_pawns: Bitboard, black_pawns: Bitboard) -> i8 { - let mut doubled_pawn_count = 0; - for file in [ - Bitboard::FILE_A, - Bitboard::FILE_B, - Bitboard::FILE_C, - Bitboard::FILE_D, - Bitboard::FILE_E, - Bitboard::FILE_F, - Bitboard::FILE_G, - Bitboard::FILE_H, - ] { - let white_pawns_on_file = (white_pawns & file).pop_count() as i8; - doubled_pawn_count += std::cmp::max(0, white_pawns_on_file - 1); - let black_pawns_on_file = (black_pawns & file).pop_count() as i8; - doubled_pawn_count -= std::cmp::max(0, black_pawns_on_file - 1); + if eval_data.king_moved + || eval_data.pawns_changed[Side::White as usize] + || eval_data.pawns_changed[Side::Black as usize] + { + self.update_passed_pawn_scores(eval_data); } - doubled_pawn_count } - fn passed_pawn_scores(&mut self, white_pawns: Bitboard, black_pawns: Bitboard) -> ScorePair { + fn update_passed_pawn_scores(&mut self, eval_data: &EvalData) { #[cfg(feature = "trace")] self.coeffs.passed_pawn.fill(Coeff(0)); - let mut scores = ScorePair(0, 0); + self.passed_pawn_scores = ScorePair(0, 0); // Ignore the rank just before promotion (7th for white, 2nd for black). // Pawns on these ranks are always passed, so they are already // considered by the pawn PSTs. - let mut white_passed = - Self::passed_pawns_one_side(white_pawns, black_pawns, Side::White) & !Bitboard::RANK_7; + let mut white_passed = Self::passed_pawns_one_side( + eval_data.pawns[Side::White as usize], + eval_data.pawns[Side::Black as usize], + Side::White, + ) & !Bitboard::RANK_7; while white_passed != Bitboard::EMPTY { let square = white_passed.square_scan_forward_reset(); - scores += params::PASSED_PAWN[square.idx()]; + self.passed_pawn_scores += params::PASSED_PAWN[square.idx()]; #[cfg(feature = "trace")] (*self.coeffs.passed_pawn[square.fold_to_queenside().idx()] += 1); } - let mut black_passed = - Self::passed_pawns_one_side(black_pawns, white_pawns, Side::Black) & !Bitboard::RANK_2; + let mut black_passed = Self::passed_pawns_one_side( + eval_data.pawns[Side::Black as usize], + eval_data.pawns[Side::White as usize], + Side::Black, + ) & !Bitboard::RANK_2; while black_passed != Bitboard::EMPTY { let square = black_passed.square_scan_forward_reset(); - scores -= params::PASSED_PAWN[square.flip_vertical().idx()]; + self.passed_pawn_scores -= params::PASSED_PAWN[square.flip_vertical().idx()]; #[cfg(feature = "trace")] (*self.coeffs.passed_pawn[square.flip_vertical().fold_to_queenside().idx()] -= 1); } - scores } - fn passed_pawns_one_side( - own_pawns: Bitboard, - opp_pawns: Bitboard, - side_to_move: Side, - ) -> Bitboard { + fn passed_pawns_one_side(own_pawns: Bitboard, opp_pawns: Bitboard, side: Side) -> Bitboard { let obstructed = Pawn::rear_span( own_pawns | opp_pawns | opp_pawns.east_one() | opp_pawns.west_one(), - side_to_move, + side, ); own_pawns & !obstructed } + fn update_isolated_and_doubled_pawn_scores_one_side( + &mut self, + eval_data: &EvalData, + side: Side, + ) { + let isolated_pawn_count = + Self::isolated_pawn_count_one_side(eval_data.pawns[side as usize]); + let doubled_pawn_count = Self::doubled_pawn_count_one_side(eval_data.pawns[side as usize]); + self.isolated_and_doubled_pawn_scores[side as usize] = isolated_pawn_count as i16 + * params::ISOLATED_PAWN + + doubled_pawn_count as i16 * params::DOUBLED_PAWN; + } + fn isolated_pawn_count_one_side(own_pawns: Bitboard) -> i8 { let occupied_files = own_pawns.file_fill(); let connected_files = occupied_files.east_one() | occupied_files.west_one(); @@ -420,16 +472,49 @@ impl HandCraftedEval { isolated_pawns.pop_count() as i8 } - fn backward_pawn_count_one_side( - own_pawns: Bitboard, - opp_pawns: Bitboard, - side_to_move: Side, - ) -> i8 { - let own_pawn_stops = Pawn::push_targets(own_pawns, Bitboard::EMPTY, side_to_move).0; - let own_front_attack_span = Pawn::front_attack_span(own_pawns, side_to_move); - let opp_attack_targets = Pawn::attack_targets(opp_pawns, !side_to_move); + fn doubled_pawn_count_one_side(own_pawns: Bitboard) -> i8 { + let mut doubled_pawn_count = 0; + for file in [ + Bitboard::FILE_A, + Bitboard::FILE_B, + Bitboard::FILE_C, + Bitboard::FILE_D, + Bitboard::FILE_E, + Bitboard::FILE_F, + Bitboard::FILE_G, + Bitboard::FILE_H, + ] { + let own_pawns_on_file = (own_pawns & file).pop_count() as i8; + doubled_pawn_count += (own_pawns_on_file - 1).max(0); + } + doubled_pawn_count + } + + fn update_backward_pawn_scores(&mut self, eval_data: &EvalData) { + let backward_pawn_count = Self::backward_pawn_count(eval_data); + self.backward_pawn_scores = backward_pawn_count as i16 * params::BACKWARD_PAWN; + #[cfg(feature = "trace")] + (*self.coeffs.backward_pawn = backward_pawn_count); + } + + fn backward_pawn_count(eval_data: &EvalData) -> i8 { + Self::backward_pawn_count_one_side( + eval_data.pawns[Side::White as usize], + eval_data.pawns[Side::Black as usize], + Side::White, + ) - Self::backward_pawn_count_one_side( + eval_data.pawns[Side::Black as usize], + eval_data.pawns[Side::White as usize], + Side::Black, + ) + } + + fn backward_pawn_count_one_side(own_pawns: Bitboard, opp_pawns: Bitboard, side: Side) -> i8 { + let own_pawn_stops = Pawn::push_targets(own_pawns, Bitboard::EMPTY, side).0; + let own_front_attack_span = Pawn::front_attack_span(own_pawns, side); + let opp_attack_targets = Pawn::attack_targets(opp_pawns, !side); let backward_pawn_targets = own_pawn_stops & !own_front_attack_span & opp_attack_targets; - let backward_pawns = Pawn::single_push_origins(backward_pawn_targets, side_to_move); + let backward_pawns = Pawn::single_push_origins(backward_pawn_targets, side); backward_pawns.pop_count() as i8 } From 1358a87357b927ef3c73c2e380d34deb2fb01e37 Mon Sep 17 00:00:00 2001 From: Patrick Heck <49785565+FitzOReilly@users.noreply.github.com> Date: Tue, 27 Jan 2026 22:03:43 +0100 Subject: [PATCH 2/3] Refactor eval for piece square tables and king tropism --- eval/src/hand_crafted_eval.rs | 259 ++++++++------------------- eval/src/hand_crafted_eval_coeffs.rs | 31 +--- eval/src/lib.rs | 1 + eval/src/piece_table_refs.rs | 65 +++++++ movegen/src/piece.rs | 8 +- 5 files changed, 157 insertions(+), 207 deletions(-) create mode 100644 eval/src/piece_table_refs.rs diff --git a/eval/src/hand_crafted_eval.rs b/eval/src/hand_crafted_eval.rs index 968d1c2..5e064b7 100644 --- a/eval/src/hand_crafted_eval.rs +++ b/eval/src/hand_crafted_eval.rs @@ -3,6 +3,7 @@ use crate::game_phase::{GamePhase, PieceCounts}; #[cfg(feature = "trace")] use crate::hand_crafted_eval_coeffs::{Coeff, HandCraftedEvalCoeffs}; use crate::params; +use crate::piece_table_refs::PIECE_TABLE_REFS; use crate::score_pair::ScorePair; use crate::{Eval, Score, EQ_POSITION}; use movegen::bishop::Bishop; @@ -160,129 +161,39 @@ impl HandCraftedEval { } fn update(&mut self, eval_data: &EvalData, pos: &Position) { - for (piece_type, table, friendly_distance, enemy_distance) in [ - ( - piece::Type::Pawn, - ¶ms::PST_PAWN, - ¶ms::DISTANCE_FRIENDLY_PAWN, - ¶ms::DISTANCE_ENEMY_PAWN, - ), - ( - piece::Type::Knight, - ¶ms::PST_KNIGHT, - ¶ms::DISTANCE_FRIENDLY_KNIGHT, - ¶ms::DISTANCE_ENEMY_KNIGHT, - ), - ( - piece::Type::Bishop, - ¶ms::PST_BISHOP, - ¶ms::DISTANCE_FRIENDLY_BISHOP, - ¶ms::DISTANCE_ENEMY_BISHOP, - ), - ( - piece::Type::Rook, - ¶ms::PST_ROOK, - ¶ms::DISTANCE_FRIENDLY_ROOK, - ¶ms::DISTANCE_ENEMY_ROOK, - ), - ( - piece::Type::Queen, - ¶ms::PST_QUEEN, - ¶ms::DISTANCE_FRIENDLY_QUEEN, - ¶ms::DISTANCE_ENEMY_QUEEN, - ), - ( - piece::Type::King, - ¶ms::PST_KING, - ¶ms::DISTANCE_FRIENDLY_KING, - ¶ms::DISTANCE_ENEMY_KING, - ), + for p in [ + Piece::WHITE_PAWN, + Piece::WHITE_KNIGHT, + Piece::WHITE_BISHOP, + Piece::WHITE_ROOK, + Piece::WHITE_QUEEN, + Piece::WHITE_KING, + Piece::BLACK_PAWN, + Piece::BLACK_KNIGHT, + Piece::BLACK_BISHOP, + Piece::BLACK_ROOK, + Piece::BLACK_QUEEN, + Piece::BLACK_KING, ] { - let prev_white = self.current_pos.piece_occupancy(Side::White, piece_type); - let current_white = pos.piece_occupancy(Side::White, piece_type); - let mut white_remove = prev_white & !current_white; - let mut white_add = current_white & !prev_white; - while white_remove != Bitboard::EMPTY { - let square = white_remove.square_scan_forward_reset(); - self.pst_scores -= table[square.idx()]; - self.game_phase.remove_piece(piece_type); - let p = Piece::new(Side::White, piece_type); + let prev = self + .current_pos + .piece_occupancy(p.piece_side(), p.piece_type()); + let current = pos.piece_occupancy(p.piece_side(), p.piece_type()); + let mut pieces_to_remove = prev & !current; + let mut pieces_to_add = current & !prev; + while pieces_to_remove != Bitboard::EMPTY { + let square = pieces_to_remove.square_scan_forward_reset(); + self.game_phase.remove_piece(p.piece_type()); self.piece_counts.remove(p); - self.king_tropism -= - friendly_distance[eval_data.kings[Side::White as usize].distance(square)]; - self.king_tropism += - enemy_distance[eval_data.kings[Side::Black as usize].distance(square)]; - #[cfg(feature = "trace")] - self.coeffs.add_piece( - p, - square, - eval_data.kings[Side::White as usize], - eval_data.kings[Side::Black as usize], - -1, - ); + self.add_pst(p, square, -1); + self.add_king_tropism(p, square, &eval_data.kings, -1); } - while white_add != Bitboard::EMPTY { - let square = white_add.square_scan_forward_reset(); - self.pst_scores += table[square.idx()]; - self.game_phase.add_piece(piece_type); - let p = Piece::new(Side::White, piece_type); + while pieces_to_add != Bitboard::EMPTY { + let square = pieces_to_add.square_scan_forward_reset(); + self.game_phase.add_piece(p.piece_type()); self.piece_counts.add(p); - self.king_tropism += - friendly_distance[eval_data.kings[Side::White as usize].distance(square)]; - self.king_tropism -= - enemy_distance[eval_data.kings[Side::Black as usize].distance(square)]; - #[cfg(feature = "trace")] - self.coeffs.add_piece( - p, - square, - eval_data.kings[Side::White as usize], - eval_data.kings[Side::Black as usize], - 1, - ); - } - let prev_black = self.current_pos.piece_occupancy(Side::Black, piece_type); - let current_black = pos.piece_occupancy(Side::Black, piece_type); - let mut black_remove = prev_black & !current_black; - let mut black_add = current_black & !prev_black; - while black_remove != Bitboard::EMPTY { - let square = black_remove.square_scan_forward_reset(); - let square_flipped = square.flip_vertical(); - self.pst_scores += table[square_flipped.idx()]; - self.game_phase.remove_piece(piece_type); - let p = Piece::new(Side::Black, piece_type); - self.piece_counts.remove(p); - self.king_tropism -= - enemy_distance[eval_data.kings[Side::White as usize].distance(square)]; - self.king_tropism += - friendly_distance[eval_data.kings[Side::Black as usize].distance(square)]; - #[cfg(feature = "trace")] - self.coeffs.add_piece( - p, - square, - eval_data.kings[Side::White as usize], - eval_data.kings[Side::Black as usize], - -1, - ); - } - while black_add != Bitboard::EMPTY { - let square = black_add.square_scan_forward_reset(); - let square_flipped = square.flip_vertical(); - self.pst_scores -= table[square_flipped.idx()]; - self.game_phase.add_piece(piece_type); - let p = Piece::new(Side::Black, piece_type); - self.piece_counts.add(p); - self.king_tropism += - enemy_distance[eval_data.kings[Side::White as usize].distance(square)]; - self.king_tropism -= - friendly_distance[eval_data.kings[Side::Black as usize].distance(square)]; - #[cfg(feature = "trace")] - self.coeffs.add_piece( - p, - square, - eval_data.kings[Side::White as usize], - eval_data.kings[Side::Black as usize], - 1, - ); + self.add_pst(p, square, 1); + self.add_king_tropism(p, square, &eval_data.kings, 1); } } if eval_data.king_moved { @@ -293,79 +204,65 @@ impl HandCraftedEval { self.current_pos = pos.clone(); } + fn add_pst(&mut self, p: Piece, square: Square, diff: i8) { + let pst = PIECE_TABLE_REFS[p.piece_type().idx()].pst; + match p.piece_side() { + Side::White => self.pst_scores += diff as Score * pst[square.idx()], + Side::Black => self.pst_scores -= diff as Score * pst[square.flip_vertical().idx()], + } + #[cfg(feature = "trace")] + self.coeffs.add_pst(p, square, diff); + } + fn update_king_tropism(&mut self, eval_data: &EvalData, pos: &Position) { self.king_tropism = ScorePair(0, 0); #[cfg(feature = "trace")] self.coeffs.clear_distance(); - for (piece_type, friendly_distance, enemy_distance) in [ - ( - piece::Type::Pawn, - ¶ms::DISTANCE_FRIENDLY_PAWN, - ¶ms::DISTANCE_ENEMY_PAWN, - ), - ( - piece::Type::Knight, - ¶ms::DISTANCE_FRIENDLY_KNIGHT, - ¶ms::DISTANCE_ENEMY_KNIGHT, - ), - ( - piece::Type::Bishop, - ¶ms::DISTANCE_FRIENDLY_BISHOP, - ¶ms::DISTANCE_ENEMY_BISHOP, - ), - ( - piece::Type::Rook, - ¶ms::DISTANCE_FRIENDLY_ROOK, - ¶ms::DISTANCE_ENEMY_ROOK, - ), - ( - piece::Type::Queen, - ¶ms::DISTANCE_FRIENDLY_QUEEN, - ¶ms::DISTANCE_ENEMY_QUEEN, - ), + for p in [ + Piece::WHITE_PAWN, + Piece::WHITE_KNIGHT, + Piece::WHITE_BISHOP, + Piece::WHITE_ROOK, + Piece::WHITE_QUEEN, + Piece::BLACK_PAWN, + Piece::BLACK_KNIGHT, + Piece::BLACK_BISHOP, + Piece::BLACK_ROOK, + Piece::BLACK_QUEEN, // No need to calculate this for kings: The distance to itself is // always 0 and the scores for the distance between each other // cancel each other out. ] { - let mut white_pieces = pos.piece_occupancy(Side::White, piece_type); - while white_pieces != Bitboard::EMPTY { - let square = white_pieces.square_scan_forward_reset(); - self.king_tropism += - friendly_distance[eval_data.kings[Side::White as usize].distance(square)]; - self.king_tropism -= - enemy_distance[eval_data.kings[Side::Black as usize].distance(square)]; - #[cfg(feature = "trace")] - { - let p = Piece::new(Side::White, piece_type); - self.coeffs.add_distance( - p, - square, - eval_data.kings[Side::White as usize], - eval_data.kings[Side::Black as usize], - 1, - ); - } + let mut pieces = pos.piece_occupancy(p.piece_side(), p.piece_type()); + while pieces != Bitboard::EMPTY { + let square = pieces.square_scan_forward_reset(); + self.add_king_tropism(p, square, &eval_data.kings, 1); } - let mut black_pieces = pos.piece_occupancy(Side::Black, piece_type); - while black_pieces != Bitboard::EMPTY { - let square = black_pieces.square_scan_forward_reset(); - self.king_tropism += - enemy_distance[eval_data.kings[Side::White as usize].distance(square)]; - self.king_tropism -= - friendly_distance[eval_data.kings[Side::Black as usize].distance(square)]; - #[cfg(feature = "trace")] - { - let p = Piece::new(Side::Black, piece_type); - self.coeffs.add_distance( - p, - square, - eval_data.kings[Side::White as usize], - eval_data.kings[Side::Black as usize], - 1, - ); - } + } + } + + fn add_king_tropism(&mut self, p: Piece, square: Square, kings: &[Square; 2], diff: i8) { + let piece_type = p.piece_type(); + if let piece::Type::King = piece_type { + return; + } + let piece_table = &PIECE_TABLE_REFS[piece_type.idx()]; + match p.piece_side() { + Side::White => { + self.king_tropism += diff as Score + * piece_table.friendly_distance[kings[Side::White as usize].distance(square)]; + self.king_tropism -= diff as Score + * piece_table.enemy_distance[kings[Side::Black as usize].distance(square)]; + } + Side::Black => { + self.king_tropism -= diff as Score + * piece_table.friendly_distance[kings[Side::Black as usize].distance(square)]; + self.king_tropism += diff as Score + * piece_table.enemy_distance[kings[Side::White as usize].distance(square)]; } } + #[cfg(feature = "trace")] + self.coeffs.add_distance(p, square, kings, diff); } fn tempo_scores(&mut self, pos: &Position) -> ScorePair { diff --git a/eval/src/hand_crafted_eval_coeffs.rs b/eval/src/hand_crafted_eval_coeffs.rs index 2fbded8..75da909 100644 --- a/eval/src/hand_crafted_eval_coeffs.rs +++ b/eval/src/hand_crafted_eval_coeffs.rs @@ -74,19 +74,7 @@ pub struct HandCraftedEvalCoeffs { } impl HandCraftedEvalCoeffs { - pub fn add_piece( - &mut self, - p: Piece, - square: Square, - white_king: Square, - black_king: Square, - diff: i8, - ) { - self.add_pst(p, square, diff); - self.add_distance(p, square, white_king, black_king, diff); - } - - fn add_pst(&mut self, p: Piece, square: Square, diff: i8) { + pub fn add_pst(&mut self, p: Piece, square: Square, diff: i8) { let pst = match p.piece_type() { piece::Type::Pawn => &mut self.pst_pawn, piece::Type::Knight => &mut self.pst_knight, @@ -116,14 +104,7 @@ impl HandCraftedEvalCoeffs { self.distance_enemy_king = Default::default(); } - pub fn add_distance( - &mut self, - p: Piece, - square: Square, - white_king: Square, - black_king: Square, - diff: i8, - ) { + pub fn add_distance(&mut self, p: Piece, square: Square, kings: &[Square; 2], diff: i8) { let (friendly_dist, enemy_dist) = match p.piece_type() { piece::Type::Pawn => ( &mut self.distance_friendly_pawn, @@ -152,12 +133,12 @@ impl HandCraftedEvalCoeffs { }; match p.piece_side() { Side::White => { - *friendly_dist[square.distance(white_king)] += diff; - *enemy_dist[square.distance(black_king)] -= diff; + *friendly_dist[square.distance(kings[Side::White as usize])] += diff; + *enemy_dist[square.distance(kings[Side::Black as usize])] -= diff; } Side::Black => { - *friendly_dist[square.distance(black_king)] -= diff; - *enemy_dist[square.distance(white_king)] += diff; + *friendly_dist[square.distance(kings[Side::Black as usize])] -= diff; + *enemy_dist[square.distance(kings[Side::White as usize])] += diff; } } } diff --git a/eval/src/lib.rs b/eval/src/lib.rs index 625adee..b9d7cab 100644 --- a/eval/src/lib.rs +++ b/eval/src/lib.rs @@ -15,3 +15,4 @@ pub mod score; pub mod score_pair; mod game_phase; +mod piece_table_refs; diff --git a/eval/src/piece_table_refs.rs b/eval/src/piece_table_refs.rs new file mode 100644 index 0000000..1dc10e8 --- /dev/null +++ b/eval/src/piece_table_refs.rs @@ -0,0 +1,65 @@ +use movegen::piece; + +use crate::{params, score_pair::ScorePair}; + +#[derive(Debug, Clone, Copy)] +pub struct PieceTableRefs<'a> { + pub pst: &'a [ScorePair], + pub friendly_distance: &'a [ScorePair], + pub enemy_distance: &'a [ScorePair], +} + +pub const PIECE_TABLE_REFS: [PieceTableRefs; 6] = { + let piece_types = [ + piece::Type::Pawn, + piece::Type::Knight, + piece::Type::Bishop, + piece::Type::Rook, + piece::Type::Queen, + piece::Type::King, + ]; + let mut piece_tables = [PieceTableRefs { + pst: &[], + friendly_distance: &[], + enemy_distance: &[], + }; 6]; + let mut i = 0; + while i < piece_types.len() { + let pt = piece_types[i]; + let tables = match pt { + piece::Type::Pawn => PieceTableRefs { + pst: ¶ms::PST_PAWN, + friendly_distance: ¶ms::DISTANCE_FRIENDLY_PAWN, + enemy_distance: ¶ms::DISTANCE_ENEMY_PAWN, + }, + piece::Type::Knight => PieceTableRefs { + pst: ¶ms::PST_KNIGHT, + friendly_distance: ¶ms::DISTANCE_FRIENDLY_KNIGHT, + enemy_distance: ¶ms::DISTANCE_ENEMY_KNIGHT, + }, + piece::Type::Bishop => PieceTableRefs { + pst: ¶ms::PST_BISHOP, + friendly_distance: ¶ms::DISTANCE_FRIENDLY_BISHOP, + enemy_distance: ¶ms::DISTANCE_ENEMY_BISHOP, + }, + piece::Type::Rook => PieceTableRefs { + pst: ¶ms::PST_ROOK, + friendly_distance: ¶ms::DISTANCE_FRIENDLY_ROOK, + enemy_distance: ¶ms::DISTANCE_ENEMY_ROOK, + }, + piece::Type::Queen => PieceTableRefs { + pst: ¶ms::PST_QUEEN, + friendly_distance: ¶ms::DISTANCE_FRIENDLY_QUEEN, + enemy_distance: ¶ms::DISTANCE_ENEMY_QUEEN, + }, + piece::Type::King => PieceTableRefs { + pst: ¶ms::PST_KING, + friendly_distance: &[], + enemy_distance: &[], + }, + }; + piece_tables[pt.idx()] = tables; + i += 1; + } + piece_tables +}; diff --git a/movegen/src/piece.rs b/movegen/src/piece.rs index 3c26484..76fec39 100644 --- a/movegen/src/piece.rs +++ b/movegen/src/piece.rs @@ -12,6 +12,12 @@ pub enum Type { King = 4, } +impl Type { + pub const fn idx(&self) -> usize { + *self as usize + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Piece(u8); @@ -45,7 +51,7 @@ impl Piece { unsafe { std::mem::transmute::(self.0 >> 1) } } - pub fn idx(&self) -> usize { + pub const fn idx(&self) -> usize { self.0 as usize } From 09761befef5bafb4a83c381a1d6925387f02f5d9 Mon Sep 17 00:00:00 2001 From: Patrick Heck <49785565+FitzOReilly@users.noreply.github.com> Date: Tue, 27 Jan 2026 22:08:32 +0100 Subject: [PATCH 3/3] Evaluate piece squares relative to king --- eval/src/hand_crafted_eval.rs | 63 +-- eval/src/hand_crafted_eval_coeffs.rs | 167 +++++--- eval/src/params.rs | 555 +++++++++++++++++---------- eval/src/piece_table_refs.rs | 32 +- movegen/src/square.rs | 19 + search/tests/search.rs | 2 +- tuner/src/eval_params.rs | 157 +++++--- tuner/src/feature_evaluator.rs | 29 +- 8 files changed, 659 insertions(+), 365 deletions(-) diff --git a/eval/src/hand_crafted_eval.rs b/eval/src/hand_crafted_eval.rs index 5e064b7..010574e 100644 --- a/eval/src/hand_crafted_eval.rs +++ b/eval/src/hand_crafted_eval.rs @@ -8,11 +8,13 @@ use crate::score_pair::ScorePair; use crate::{Eval, Score, EQ_POSITION}; use movegen::bishop::Bishop; use movegen::bitboard::Bitboard; +use movegen::file::File; use movegen::knight::Knight; use movegen::pawn::Pawn; use movegen::piece::{self, Piece}; use movegen::position::Position; use movegen::queen::Queen; +use movegen::rank::Rank; use movegen::rook::Rook; use movegen::side::Side; use movegen::square::Square; @@ -56,7 +58,7 @@ pub struct HandCraftedEval { passed_pawn_scores: ScorePair, isolated_and_doubled_pawn_scores: [ScorePair; 2], backward_pawn_scores: ScorePair, - king_tropism: ScorePair, + squares_relative_to_king: ScorePair, #[cfg(feature = "trace")] coeffs: HandCraftedEvalCoeffs, } @@ -74,7 +76,7 @@ impl Eval for HandCraftedEval { + self.backward_pawn_scores + self.mobility_scores(pos) + self.bishop_pair_scores(pos) - + self.king_tropism; + + self.squares_relative_to_king; let game_phase = self.game_phase.game_phase_clamped(); #[cfg(feature = "trace")] @@ -149,7 +151,7 @@ impl HandCraftedEval { passed_pawn_scores: Default::default(), isolated_and_doubled_pawn_scores: Default::default(), backward_pawn_scores: Default::default(), - king_tropism: Default::default(), + squares_relative_to_king: Default::default(), #[cfg(feature = "trace")] coeffs: Default::default(), } @@ -186,19 +188,19 @@ impl HandCraftedEval { self.game_phase.remove_piece(p.piece_type()); self.piece_counts.remove(p); self.add_pst(p, square, -1); - self.add_king_tropism(p, square, &eval_data.kings, -1); + self.add_squares_relative_to_king(p, square, &eval_data.kings, -1); } while pieces_to_add != Bitboard::EMPTY { let square = pieces_to_add.square_scan_forward_reset(); self.game_phase.add_piece(p.piece_type()); self.piece_counts.add(p); self.add_pst(p, square, 1); - self.add_king_tropism(p, square, &eval_data.kings, 1); + self.add_squares_relative_to_king(p, square, &eval_data.kings, 1); } } if eval_data.king_moved { // A king was moved, calculate king tropism for all pieces - self.update_king_tropism(eval_data, pos); + self.update_squares_relative_to_king(eval_data, pos); } self.update_pawn_structure_scores(eval_data); self.current_pos = pos.clone(); @@ -214,10 +216,10 @@ impl HandCraftedEval { self.coeffs.add_pst(p, square, diff); } - fn update_king_tropism(&mut self, eval_data: &EvalData, pos: &Position) { - self.king_tropism = ScorePair(0, 0); + fn update_squares_relative_to_king(&mut self, eval_data: &EvalData, pos: &Position) { + self.squares_relative_to_king = ScorePair(0, 0); #[cfg(feature = "trace")] - self.coeffs.clear_distance(); + self.coeffs.clear_squares_relative_to_king(); for p in [ Piece::WHITE_PAWN, Piece::WHITE_KNIGHT, @@ -229,40 +231,55 @@ impl HandCraftedEval { Piece::BLACK_BISHOP, Piece::BLACK_ROOK, Piece::BLACK_QUEEN, - // No need to calculate this for kings: The distance to itself is - // always 0 and the scores for the distance between each other - // cancel each other out. ] { let mut pieces = pos.piece_occupancy(p.piece_side(), p.piece_type()); while pieces != Bitboard::EMPTY { let square = pieces.square_scan_forward_reset(); - self.add_king_tropism(p, square, &eval_data.kings, 1); + self.add_squares_relative_to_king(p, square, &eval_data.kings, 1); } } } - fn add_king_tropism(&mut self, p: Piece, square: Square, kings: &[Square; 2], diff: i8) { + fn add_squares_relative_to_king( + &mut self, + p: Piece, + square: Square, + kings: &[Square; 2], + diff: i8, + ) { let piece_type = p.piece_type(); if let piece::Type::King = piece_type { return; } + const OFFSET: i8 = ((Rank::NUM_RANKS - 1) * File::NUM_FILES) as i8; let piece_table = &PIECE_TABLE_REFS[piece_type.idx()]; match p.piece_side() { Side::White => { - self.king_tropism += diff as Score - * piece_table.friendly_distance[kings[Side::White as usize].distance(square)]; - self.king_tropism -= diff as Score - * piece_table.enemy_distance[kings[Side::Black as usize].distance(square)]; + self.squares_relative_to_king += diff as Score + * piece_table.square_relative_to_friendly_king + [(OFFSET + square.relative_to(kings[Side::White as usize])) as usize]; + self.squares_relative_to_king -= diff as Score + * piece_table.square_relative_to_enemy_king[(OFFSET + + square + .flip_vertical() + .relative_to(kings[Side::Black as usize].flip_vertical())) + as usize]; } Side::Black => { - self.king_tropism -= diff as Score - * piece_table.friendly_distance[kings[Side::Black as usize].distance(square)]; - self.king_tropism += diff as Score - * piece_table.enemy_distance[kings[Side::White as usize].distance(square)]; + self.squares_relative_to_king -= diff as Score + * piece_table.square_relative_to_friendly_king[(OFFSET + + square + .flip_vertical() + .relative_to(kings[Side::Black as usize].flip_vertical())) + as usize]; + self.squares_relative_to_king += diff as Score + * piece_table.square_relative_to_enemy_king + [(OFFSET + square.relative_to(kings[Side::White as usize])) as usize]; } } #[cfg(feature = "trace")] - self.coeffs.add_distance(p, square, kings, diff); + self.coeffs + .add_squares_relative_to_king(p, square, kings, diff); } fn tempo_scores(&mut self, pos: &Position) -> ScorePair { diff --git a/eval/src/hand_crafted_eval_coeffs.rs b/eval/src/hand_crafted_eval_coeffs.rs index 75da909..ae749e9 100644 --- a/eval/src/hand_crafted_eval_coeffs.rs +++ b/eval/src/hand_crafted_eval_coeffs.rs @@ -4,7 +4,9 @@ use std::{ }; use movegen::{ + file::File, piece::{self, Piece}, + rank::Rank, side::Side, square::Square, }; @@ -40,7 +42,7 @@ impl From for Coeff { } } -#[derive(Debug, Clone, Default, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct HandCraftedEvalCoeffs { pub game_phase: usize, pub pst_pawn: [Coeff; 32], @@ -59,18 +61,52 @@ pub struct HandCraftedEvalCoeffs { pub rook_mobility: [Coeff; params::ROOK_MOB_LEN], pub queen_mobility: [Coeff; params::QUEEN_MOB_LEN], pub bishop_pair: Coeff, - pub distance_friendly_pawn: [Coeff; params::DISTANCE_LEN], - pub distance_enemy_pawn: [Coeff; params::DISTANCE_LEN], - pub distance_friendly_knight: [Coeff; params::DISTANCE_LEN], - pub distance_enemy_knight: [Coeff; params::DISTANCE_LEN], - pub distance_friendly_bishop: [Coeff; params::DISTANCE_LEN], - pub distance_enemy_bishop: [Coeff; params::DISTANCE_LEN], - pub distance_friendly_rook: [Coeff; params::DISTANCE_LEN], - pub distance_enemy_rook: [Coeff; params::DISTANCE_LEN], - pub distance_friendly_queen: [Coeff; params::DISTANCE_LEN], - pub distance_enemy_queen: [Coeff; params::DISTANCE_LEN], - pub distance_friendly_king: [Coeff; params::DISTANCE_LEN], - pub distance_enemy_king: [Coeff; params::DISTANCE_LEN], + pub pawn_square_relative_to_friendly_king: [Coeff; params::SQUARE_RELATIVE_TO_KING_LEN], + pub pawn_square_relative_to_enemy_king: [Coeff; params::SQUARE_RELATIVE_TO_KING_LEN], + pub knight_square_relative_to_friendly_king: [Coeff; params::SQUARE_RELATIVE_TO_KING_LEN], + pub knight_square_relative_to_enemy_king: [Coeff; params::SQUARE_RELATIVE_TO_KING_LEN], + pub bishop_square_relative_to_friendly_king: [Coeff; params::SQUARE_RELATIVE_TO_KING_LEN], + pub bishop_square_relative_to_enemy_king: [Coeff; params::SQUARE_RELATIVE_TO_KING_LEN], + pub rook_square_relative_to_friendly_king: [Coeff; params::SQUARE_RELATIVE_TO_KING_LEN], + pub rook_square_relative_to_enemy_king: [Coeff; params::SQUARE_RELATIVE_TO_KING_LEN], + pub queen_square_relative_to_friendly_king: [Coeff; params::SQUARE_RELATIVE_TO_KING_LEN], + pub queen_square_relative_to_enemy_king: [Coeff; params::SQUARE_RELATIVE_TO_KING_LEN], +} + +impl Default for HandCraftedEvalCoeffs { + fn default() -> Self { + Self { + game_phase: Default::default(), + pst_pawn: Default::default(), + pst_knight: Default::default(), + pst_bishop: Default::default(), + pst_rook: Default::default(), + pst_queen: Default::default(), + pst_king: Default::default(), + tempo: Default::default(), + passed_pawn: Default::default(), + isolated_pawn: Default::default(), + backward_pawn: Default::default(), + doubled_pawn: Default::default(), + knight_mobility: Default::default(), + bishop_mobility: Default::default(), + rook_mobility: Default::default(), + queen_mobility: Default::default(), + bishop_pair: Default::default(), + pawn_square_relative_to_friendly_king: [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN], + pawn_square_relative_to_enemy_king: [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN], + knight_square_relative_to_friendly_king: [Coeff(0); + params::SQUARE_RELATIVE_TO_KING_LEN], + knight_square_relative_to_enemy_king: [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN], + bishop_square_relative_to_friendly_king: [Coeff(0); + params::SQUARE_RELATIVE_TO_KING_LEN], + bishop_square_relative_to_enemy_king: [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN], + rook_square_relative_to_friendly_king: [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN], + rook_square_relative_to_enemy_king: [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN], + queen_square_relative_to_friendly_king: [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN], + queen_square_relative_to_enemy_king: [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN], + } + } } impl HandCraftedEvalCoeffs { @@ -89,56 +125,73 @@ impl HandCraftedEvalCoeffs { } } - pub fn clear_distance(&mut self) { - self.distance_friendly_pawn = Default::default(); - self.distance_enemy_pawn = Default::default(); - self.distance_friendly_knight = Default::default(); - self.distance_enemy_knight = Default::default(); - self.distance_friendly_bishop = Default::default(); - self.distance_enemy_bishop = Default::default(); - self.distance_friendly_rook = Default::default(); - self.distance_enemy_rook = Default::default(); - self.distance_friendly_queen = Default::default(); - self.distance_enemy_queen = Default::default(); - self.distance_friendly_king = Default::default(); - self.distance_enemy_king = Default::default(); + pub fn clear_squares_relative_to_king(&mut self) { + self.pawn_square_relative_to_friendly_king = + [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN]; + self.pawn_square_relative_to_enemy_king = [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN]; + self.knight_square_relative_to_friendly_king = + [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN]; + self.knight_square_relative_to_enemy_king = [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN]; + self.bishop_square_relative_to_friendly_king = + [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN]; + self.bishop_square_relative_to_enemy_king = [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN]; + self.rook_square_relative_to_friendly_king = + [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN]; + self.rook_square_relative_to_enemy_king = [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN]; + self.queen_square_relative_to_friendly_king = + [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN]; + self.queen_square_relative_to_enemy_king = [Coeff(0); params::SQUARE_RELATIVE_TO_KING_LEN]; } - pub fn add_distance(&mut self, p: Piece, square: Square, kings: &[Square; 2], diff: i8) { - let (friendly_dist, enemy_dist) = match p.piece_type() { + pub fn add_squares_relative_to_king( + &mut self, + p: Piece, + square: Square, + kings: &[Square; 2], + diff: i8, + ) { + let (friendly_square_relative, enemy_square_relative) = match p.piece_type() { piece::Type::Pawn => ( - &mut self.distance_friendly_pawn, - &mut self.distance_enemy_pawn, + &mut self.pawn_square_relative_to_friendly_king, + &mut self.pawn_square_relative_to_enemy_king, ), piece::Type::Knight => ( - &mut self.distance_friendly_knight, - &mut self.distance_enemy_knight, + &mut self.knight_square_relative_to_friendly_king, + &mut self.knight_square_relative_to_enemy_king, ), piece::Type::Bishop => ( - &mut self.distance_friendly_bishop, - &mut self.distance_enemy_bishop, + &mut self.bishop_square_relative_to_friendly_king, + &mut self.bishop_square_relative_to_enemy_king, ), piece::Type::Rook => ( - &mut self.distance_friendly_rook, - &mut self.distance_enemy_rook, + &mut self.rook_square_relative_to_friendly_king, + &mut self.rook_square_relative_to_enemy_king, ), piece::Type::Queen => ( - &mut self.distance_friendly_queen, - &mut self.distance_enemy_queen, - ), - piece::Type::King => ( - &mut self.distance_friendly_king, - &mut self.distance_enemy_king, + &mut self.queen_square_relative_to_friendly_king, + &mut self.queen_square_relative_to_enemy_king, ), + piece::Type::King => unreachable!(), }; + const OFFSET: i8 = ((Rank::NUM_RANKS - 1) * File::NUM_FILES) as i8; match p.piece_side() { Side::White => { - *friendly_dist[square.distance(kings[Side::White as usize])] += diff; - *enemy_dist[square.distance(kings[Side::Black as usize])] -= diff; + *friendly_square_relative + [(OFFSET + square.relative_to(kings[Side::White as usize])) as usize] += diff; + *enemy_square_relative[(OFFSET + + square + .flip_vertical() + .relative_to(kings[Side::Black as usize].flip_vertical())) + as usize] -= diff; } Side::Black => { - *friendly_dist[square.distance(kings[Side::Black as usize])] -= diff; - *enemy_dist[square.distance(kings[Side::White as usize])] += diff; + *friendly_square_relative[(OFFSET + + square + .flip_vertical() + .relative_to(kings[Side::Black as usize].flip_vertical())) + as usize] -= diff; + *enemy_square_relative + [(OFFSET + square.relative_to(kings[Side::White as usize])) as usize] += diff; } } } @@ -161,17 +214,15 @@ impl HandCraftedEvalCoeffs { .chain(self.rook_mobility.iter()) .chain(self.queen_mobility.iter()) .chain(iter::once(&self.bishop_pair)) - .chain(self.distance_friendly_pawn.iter()) - .chain(self.distance_enemy_pawn.iter()) - .chain(self.distance_friendly_knight.iter()) - .chain(self.distance_enemy_knight.iter()) - .chain(self.distance_friendly_bishop.iter()) - .chain(self.distance_enemy_bishop.iter()) - .chain(self.distance_friendly_rook.iter()) - .chain(self.distance_enemy_rook.iter()) - .chain(self.distance_friendly_queen.iter()) - .chain(self.distance_enemy_queen.iter()) - .chain(self.distance_friendly_king.iter()) - .chain(self.distance_enemy_king.iter()) + .chain(self.pawn_square_relative_to_friendly_king.iter()) + .chain(self.pawn_square_relative_to_enemy_king.iter()) + .chain(self.knight_square_relative_to_friendly_king.iter()) + .chain(self.knight_square_relative_to_enemy_king.iter()) + .chain(self.bishop_square_relative_to_friendly_king.iter()) + .chain(self.bishop_square_relative_to_enemy_king.iter()) + .chain(self.rook_square_relative_to_friendly_king.iter()) + .chain(self.rook_square_relative_to_enemy_king.iter()) + .chain(self.queen_square_relative_to_friendly_king.iter()) + .chain(self.queen_square_relative_to_enemy_king.iter()) } } diff --git a/eval/src/params.rs b/eval/src/params.rs index 1e50975..7b45140 100644 --- a/eval/src/params.rs +++ b/eval/src/params.rs @@ -11,6 +11,7 @@ pub const QUEEN_MOB_LEN: usize = 28; pub const MOB_LEN: usize = KNIGHT_MOB_LEN + BISHOP_MOB_LEN + ROOK_MOB_LEN + QUEEN_MOB_LEN; pub const DISTANCE_LEN: usize = 8; +pub const SQUARE_RELATIVE_TO_KING_LEN: usize = (2 * Rank::NUM_RANKS - 1) * File::NUM_FILES; // (middlegame, endgame) const MATERIAL_KING: ScorePair = ScorePair(0, 0); @@ -21,102 +22,272 @@ const MATERIAL_KNIGHT: ScorePair = ScorePair(0, 0); const MATERIAL_PAWN: ScorePair = ScorePair(0, 0); // The side to move gets a small bonus -pub const TEMPO: ScorePair = ScorePair(29, 27); +pub const TEMPO: ScorePair = ScorePair(30, 29); #[rustfmt::skip] const PASSED_PAWN_MG_EG: ([Score; 32], [Score; 32]) = ( [ 0, 0, 0, 0, 0, 0, 0, 0, - 13, 12, -11, -20, - 14, 21, 11, -2, - 20, -6, -16, -11, - 19, 19, 1, -25, - 12, 10, 7, -12, + 16, 8, -9, -17, + 19, 22, 15, 6, + 23, -3, -10, -7, + 18, 22, 5, -16, + 9, 11, 10, -11, 0, 0, 0, 0, ], [ 0, 0, 0, 0, 0, 0, 0, 0, - 144, 125, 111, 92, - 68, 67, 48, 51, - 33, 39, 25, 25, - 11, 13, 9, 9, - 12, 19, -1, -3, + 138, 121, 107, 82, + 64, 63, 43, 43, + 30, 35, 20, 18, + 10, 9, 4, 1, + 13, 18, -3, -4, 0, 0, 0, 0, ], ); -pub const ISOLATED_PAWN: ScorePair = ScorePair(-19, -6); -pub const BACKWARD_PAWN: ScorePair = ScorePair(-11, -4); -pub const DOUBLED_PAWN: ScorePair = ScorePair(-4, -12); +pub const ISOLATED_PAWN: ScorePair = ScorePair(-17, -8); +pub const BACKWARD_PAWN: ScorePair = ScorePair(-11, -3); +pub const DOUBLED_PAWN: ScorePair = ScorePair(-7, -9); -pub const BISHOP_PAIR: ScorePair = ScorePair(32, 44); +pub const BISHOP_PAIR: ScorePair = ScorePair(31, 41); const MOBILITY_KNIGHT_MG_EG: ([Score; KNIGHT_MOB_LEN], [Score; KNIGHT_MOB_LEN]) = ( - [-9, 20, 32, 36, 44, 45, 45, 46, 45], - [-15, -7, -11, -13, -13, -9, -7, -9, -9], + [19, 48, 59, 64, 70, 71, 73, 74, 73], + [-18, -24, -29, -32, -32, -29, -30, -34, -33], ); const MOBILITY_BISHOP_MG_EG: ([Score; BISHOP_MOB_LEN], [Score; BISHOP_MOB_LEN]) = ( - [-8, 3, 13, 17, 22, 27, 32, 34, 38, 40, 48, 53, 55, 42], - [-45, -34, -32, -21, -12, -3, 1, 8, 11, 13, 7, 11, 16, 15], + [24, 35, 47, 51, 56, 61, 66, 68, 72, 73, 82, 87, 94, 68], + [-46, -31, -32, -23, -15, -6, -3, 4, 8, 11, 5, 9, 9, 18], ); const MOBILITY_ROOK_MG_EG: ([Score; ROOK_MOB_LEN], [Score; ROOK_MOB_LEN]) = ( - [-8, 1, 2, 5, 6, 13, 18, 24, 28, 35, 40, 43, 53, 70, 78], - [-38, -25, -15, -12, -3, -3, -5, 0, 7, 6, 9, 14, 17, 12, 4], + [-1, 8, 10, 15, 17, 26, 30, 35, 39, 47, 53, 55, 65, 82, 91], + [ + -40, -29, -18, -13, -10, -10, -11, -5, -1, -2, 1, 6, 10, 5, -3, + ], ); const MOBILITY_QUEEN_MG_EG: ([Score; QUEEN_MOB_LEN], [Score; QUEEN_MOB_LEN]) = ( [ - -3, 7, 10, 13, 19, 24, 28, 27, 26, 33, 35, 35, 36, 38, 42, 48, 50, 48, 59, 61, 54, 67, 72, - 101, 58, 56, 52, 35, + 37, 50, 54, 55, 62, 66, 71, 71, 69, 76, 79, 78, 79, 82, 86, 91, 95, 92, 102, 102, 95, 112, + 116, 133, 92, 77, 73, 57, ], [ - 0, -32, -58, -60, -73, -45, -46, -37, -12, -6, 1, 12, 19, 28, 29, 23, 27, 43, 40, 40, 54, - 43, 37, 21, 39, 48, 52, 50, + 5, -7, -19, -8, -25, 3, -3, 4, 26, 34, 38, 49, 55, 61, 64, 57, 58, 75, 72, 71, 85, 71, 67, + 62, 76, 94, 89, 91, ], ); -const DISTANCE_FRIENDLY_PAWN_MG_EG: ([Score; DISTANCE_LEN], [Score; DISTANCE_LEN]) = - ([0, 38, 23, 11, 1, -17, -4, -7], [0, 5, 10, 4, 4, 11, 8, 8]); -const DISTANCE_ENEMY_PAWN_MG_EG: ([Score; DISTANCE_LEN], [Score; DISTANCE_LEN]) = ( - [0, -12, -35, -8, -5, -9, -3, 27], - [0, 42, 11, -7, -14, -18, -23, -41], +const PAWN_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG: ( + [Score; SQUARE_RELATIVE_TO_KING_LEN], + [Score; SQUARE_RELATIVE_TO_KING_LEN], +) = ( + [ + 0, 0, 0, 0, 0, 0, 0, 0, 2, -9, -1, 0, 2, -1, 4, 0, 5, -8, 11, -2, -3, -14, -9, 3, -21, -20, + -31, -15, -9, -36, -24, -5, -21, -29, -44, -73, -45, -72, -88, -9, 9, -47, -27, -79, -66, + -80, -64, -32, 17, -8, 16, -16, -21, -35, -47, -23, 0, 45, 21, 6, -4, -18, -32, -24, 69, + 48, 17, 15, -1, -20, -6, -12, 68, 37, 32, 13, 10, -7, -8, -12, 48, 35, 19, 15, 16, 2, 6, + -2, 39, 24, 20, 23, 20, 18, 15, 15, 12, 5, 0, 9, 21, 18, 23, -1, -7, -22, 5, -12, -9, 3, + 54, -24, 0, 0, 0, 0, 0, 0, 0, 0, + ], + [ + 0, 0, 0, 0, 0, 0, 0, 0, 35, 30, 26, 26, 45, 9, 36, 10, 56, 55, 45, 35, 42, 64, 36, 24, 40, + 49, 31, 33, 39, 45, 41, 23, 28, 32, 31, 30, 31, 33, 44, 33, 14, 34, 17, 29, 31, 35, 30, 37, + 17, 12, 11, 17, 19, 21, 27, 17, 0, 12, 8, 5, 9, 11, 21, 10, -8, -8, 6, 3, 4, 13, 9, 8, -7, + -3, -4, -4, -4, 2, 3, 7, -21, -19, -19, -14, -13, -2, -6, -5, -35, -24, -32, -31, -16, -19, + -8, -23, -38, -21, -28, -31, -27, -14, -4, -12, -61, -48, -62, -26, -22, -28, -16, 24, 0, + 0, 0, 0, 0, 0, 0, 0, + ], ); -const DISTANCE_FRIENDLY_KNIGHT_MG_EG: ([Score; DISTANCE_LEN], [Score; DISTANCE_LEN]) = ( - [0, 61, 56, 50, 36, 45, 42, 14], - [0, -16, -18, -17, -10, -15, -11, -8], +const PAWN_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG: ( + [Score; SQUARE_RELATIVE_TO_KING_LEN], + [Score; SQUARE_RELATIVE_TO_KING_LEN], +) = ( + [ + 0, 0, 0, 0, 0, 0, 0, 0, -4, -2, 4, -3, -7, 0, -3, -1, -2, -2, 0, -1, -3, 9, -5, -1, 1, 16, + 24, 17, -1, 7, 4, 10, 15, 57, 30, 33, 51, 48, 28, 3, 66, 86, 76, 88, 65, 61, 38, 34, 53, + 113, 7, 43, 57, 52, 32, 29, 0, -15, -58, 28, 56, 44, 46, 29, 24, -88, -47, 0, -6, 18, 11, + 1, -42, -45, -25, -19, -4, 0, -6, 18, -16, -31, -27, -12, -17, -19, -17, 5, -14, -26, -26, + -28, -22, -25, -35, -5, -17, -25, -30, -31, -26, -29, -33, 1, -21, -26, -30, -29, -27, -26, + -41, -5, 0, 0, 0, 0, 0, 0, 0, 0, + ], + [ + 0, 0, 0, 0, 0, 0, 0, 0, -16, -18, 9, -33, -43, -24, -32, -6, -67, -73, -70, -63, -69, -61, + -75, -51, -84, -60, -68, -61, -40, -69, -68, -28, -47, -44, -30, -36, -50, -59, -39, -7, + -11, -10, -17, -31, -35, -33, -29, -14, 26, 16, 34, -3, -19, -27, -19, -20, 0, 71, 54, 12, + -10, -13, -24, -12, 68, 33, 44, 16, 9, -7, -12, -7, 34, 35, 24, 21, 9, -1, -5, -15, 26, 24, + 24, 19, 12, 6, 1, -19, 22, 24, 24, 23, 16, 9, 9, -9, 23, 21, 22, 23, 16, 11, 9, -8, 27, 21, + 22, 20, 18, 12, 11, -7, 0, 0, 0, 0, 0, 0, 0, 0, + ], ); -const DISTANCE_ENEMY_KNIGHT_MG_EG: ([Score; DISTANCE_LEN], [Score; DISTANCE_LEN]) = ( - [0, -67, -97, -43, -25, -24, -26, -22], - [0, 33, 22, 5, 2, 8, 14, 9], +const KNIGHT_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG: ( + [Score; SQUARE_RELATIVE_TO_KING_LEN], + [Score; SQUARE_RELATIVE_TO_KING_LEN], +) = ( + [ + -1, -1, 0, 0, 0, 0, 0, 0, -1, -4, -6, -3, -1, 1, -2, 0, -6, -3, -9, -5, -6, -2, -2, 0, -6, + -7, -15, -10, -25, -3, -16, 0, -6, -29, -2, -22, -14, -11, -2, 0, -30, 2, 8, -11, -10, -39, + 1, -5, 39, 12, 34, 22, -6, 8, 14, 0, 0, 26, 19, 29, 2, 18, 16, 3, 48, 37, 28, 23, 17, 8, + 22, -27, 37, 35, 35, 24, 12, 16, 8, -23, 23, 27, 24, 21, 29, 29, 17, 1, -3, 20, 6, 20, 32, + 11, 27, -36, 26, -11, -1, -21, 17, 16, 28, 23, 14, 7, -5, 5, -46, 20, 6, 16, 28, 5, 25, + -14, -48, -56, 18, 22, + ], + [ + -7, -6, -2, 0, 0, 0, -7, 0, -11, -18, -28, -6, -5, -3, -5, -2, -17, -4, -9, -23, -4, -2, 3, + -2, -37, -23, -35, -36, -35, -14, -22, -2, -31, -28, -21, -29, -16, -23, -15, -1, -14, -16, + -10, 1, -12, -29, -28, -13, -16, -8, -20, -13, -6, -28, -46, 1, 0, -5, -11, -16, -8, -24, + -35, -34, -2, -11, -6, -5, -9, -14, -18, -16, 3, -8, 0, -1, -1, -3, 6, -3, 4, 4, 10, 0, 2, + -4, 12, 17, 21, 22, 23, 29, 4, 21, 7, -9, 20, 32, 25, 42, 31, 11, 18, 20, 21, 23, 33, 39, + 42, 24, 26, 17, 33, -16, 13, 28, 25, 24, 30, 21, + ], ); -const DISTANCE_FRIENDLY_BISHOP_MG_EG: ([Score; DISTANCE_LEN], [Score; DISTANCE_LEN]) = ( - [0, 68, 68, 59, 69, 55, 60, 37], - [0, -8, -9, -10, -16, -9, -11, -2], +const KNIGHT_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG: ( + [Score; SQUARE_RELATIVE_TO_KING_LEN], + [Score; SQUARE_RELATIVE_TO_KING_LEN], +) = ( + [ + 0, -1, 0, 1, 0, 0, -1, 0, -1, 2, 5, 1, 2, 0, 1, 3, 13, 13, 10, 5, 9, 7, 1, -1, 5, 21, 2, 8, + 10, 3, 2, 0, 24, 3, -1, 2, 11, 17, -3, 1, -13, -10, 6, 44, -1, 15, 15, 4, 15, 6, -76, 6, + -7, 30, 6, -2, 0, 21, -20, -4, -34, 14, 66, -16, -46, -20, -162, -22, 6, -5, 15, 12, -33, + -129, -17, -9, -18, 10, 14, 14, -13, -25, -5, -18, 4, 5, -6, -18, -15, -2, -10, 4, -2, -6, + -13, 36, -9, -7, -7, -1, -16, -3, -11, 35, -10, -18, -15, -25, -17, 6, -3, -23, -28, -11, + -27, -19, -20, -35, -36, -19, + ], + [ + 0, 0, 1, 7, 7, 1, 0, 0, -4, 15, 19, 9, 20, 1, 1, 7, 19, 37, 21, 26, 58, 33, 6, -4, 18, 59, + 22, 31, 39, 46, 9, 7, 33, 32, 50, -10, 32, 50, 9, 5, 20, 6, 46, 23, 15, 26, 38, 6, 49, 18, + 5, -2, 12, 8, 15, -5, 0, 29, 2, 4, -6, -3, -31, 11, 31, -2, 1, -15, -2, -3, -4, 8, -6, -33, + -3, -11, -27, -18, -9, -14, -14, -31, -12, -52, -31, -23, -21, 17, -21, -19, -27, -24, -25, + -17, -18, -33, -13, -19, -21, -27, -19, -23, -16, 4, 0, -17, -12, -7, -1, -8, -19, -8, 0, + -25, -12, -28, -19, 8, 7, -3, + ], +); +const BISHOP_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG: ( + [Score; SQUARE_RELATIVE_TO_KING_LEN], + [Score; SQUARE_RELATIVE_TO_KING_LEN], +) = ( + [ + -4, -4, -5, -1, -5, 1, 0, 0, -1, -4, -8, -1, -2, 1, -1, -1, -14, 4, -2, -8, 2, -1, 4, -7, + -14, -27, -20, -33, -16, -1, -2, -2, -20, -35, -10, -21, -46, -26, -1, -1, 24, 3, -11, -17, + 25, -25, -10, -1, -4, 14, 8, 21, 18, 22, -37, -7, 0, 17, 33, 28, 34, 17, -1, -10, 48, 49, + 35, 30, 14, 16, 17, -2, 48, 26, 37, 17, 26, 21, 29, 11, 30, 35, 25, 30, 16, 29, 30, 9, 20, + -4, 31, 20, 25, 18, 10, -25, 32, 22, 14, 20, 0, 27, 14, -7, -10, 11, 0, 13, 14, 31, 65, 47, + 17, 16, -29, 5, 10, 25, 30, -11, + ], + [ + -15, -8, -2, -1, -6, 8, 0, 2, 11, -21, -16, -1, -19, 16, -4, -4, -6, -13, 5, 0, 8, -9, 18, + -22, -27, -5, -5, -2, -4, 12, -4, -5, -29, -17, -2, -14, -8, -24, -1, 15, -18, -12, -19, + -10, -21, -4, -8, 27, 4, -13, -6, -12, -12, -18, -15, -13, 0, -4, -14, -17, -31, -25, -5, + -10, -7, -11, -4, -8, -2, -9, -15, -2, -12, 0, 2, 5, -10, 1, -8, -1, 1, -3, 2, -2, 3, -2, + -2, -11, 1, 17, -3, 10, 9, 8, 5, 8, 10, 17, 14, 14, 17, 10, 2, 14, 36, 12, 28, 30, 12, 4, + 12, 28, 16, 24, 22, 10, 15, 7, 29, 14, + ], ); -const DISTANCE_ENEMY_BISHOP_MG_EG: ([Score; DISTANCE_LEN], [Score; DISTANCE_LEN]) = ( - [0, -155, -70, -43, -39, -37, -35, -37], - [0, 45, 12, 1, 0, 0, 1, 6], +const BISHOP_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG: ( + [Score; SQUARE_RELATIVE_TO_KING_LEN], + [Score; SQUARE_RELATIVE_TO_KING_LEN], +) = ( + [ + 1, 1, 1, 1, 2, 0, 0, 0, 3, 3, 7, 1, 2, 2, 0, 0, 8, 7, 2, -1, 4, -1, 3, 2, 12, 20, 0, 12, + -4, 3, -1, 2, 27, 13, 23, -8, 11, 0, 1, 5, 16, 45, -6, 5, -23, 18, 3, 5, 15, -15, 48, 25, + -26, 11, 58, -8, 0, -34, -39, 20, -2, 39, 0, 24, -45, -180, -9, -13, 6, 20, 32, 32, -39, + -25, -97, -18, -18, 14, 6, -3, -31, -28, -16, -22, -11, -18, -2, -1, -14, -8, -26, -15, + -32, -14, -32, 26, -7, -23, -13, -25, -20, -34, -18, -27, -23, -20, -25, -24, -35, -28, + -41, -16, -20, -36, -31, -41, -37, -30, -51, -25, + ], + [ + 11, 3, 1, 8, 12, 1, -1, 0, 27, 13, 7, 7, 0, 10, 0, 1, 25, 4, 15, 4, 4, -7, -8, 9, 5, 34, 2, + 30, -24, 9, -19, 3, 25, -2, 16, -2, 14, 11, 15, 23, 3, 22, -32, 18, 3, 11, 9, 2, 24, -25, + 14, -7, 14, 0, 3, 7, 0, 38, 15, 11, -13, 3, -1, -2, 41, -11, 19, -8, 4, -11, -16, -15, 5, + 12, -38, 8, -10, 2, -19, 8, 16, -4, 5, -50, -1, -16, -11, -4, -17, 3, -10, 1, -25, 2, -11, + -12, 2, -11, -2, -7, -11, -26, -14, -14, -3, 3, -16, 0, -5, 4, -19, 15, -8, -13, 1, -12, 8, + -13, 12, -21, + ], ); -const DISTANCE_FRIENDLY_ROOK_MG_EG: ([Score; DISTANCE_LEN], [Score; DISTANCE_LEN]) = ( - [0, 55, 63, 65, 59, 59, 49, 59], - [0, -10, -7, -10, -6, -3, 4, 0], +const ROOK_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG: ( + [Score; SQUARE_RELATIVE_TO_KING_LEN], + [Score; SQUARE_RELATIVE_TO_KING_LEN], +) = ( + [ + -3, -5, -13, 5, 2, -5, -1, -1, -4, -12, -7, -11, -6, 0, -3, -3, -11, -1, -13, -12, -25, -2, + -6, 0, -15, -16, -47, -45, -2, -45, -30, -22, -17, 8, -22, -13, -29, -16, -56, -8, -19, -7, + -10, 0, -24, 5, -3, -26, -11, 0, -3, -15, -12, -20, -16, -15, 0, 19, 33, 41, 34, 37, 28, + 35, 88, 35, 30, 32, 52, 25, 40, -22, 50, 37, 34, 23, 38, 20, 14, -57, 28, 18, 36, 24, 30, + 24, 17, -7, 21, 31, 24, 57, 25, 25, 23, -24, 32, 30, 34, 15, 33, 22, 5, -15, 43, 21, -32, + -38, -20, 1, -18, -13, -8, 43, 4, 32, 23, 12, 38, -3, + ], + [ + -10, -8, -45, -10, -6, -27, -13, -6, -25, -53, -50, -36, -3, -15, -7, -18, -48, -48, -38, + -47, -45, -23, -8, -8, -53, -35, -25, -45, -51, -39, -24, -11, -44, -37, -20, -37, -10, + -15, -8, -3, -29, -22, -21, -28, -21, -22, -13, -1, -25, -25, -16, -15, -12, -5, -8, 1, 0, + -10, -20, -26, -16, -15, -13, -15, -27, -13, 0, -6, -13, -4, -10, 7, 0, 2, 8, 9, 3, 5, 6, + 21, 0, 18, 12, 12, 13, 17, 19, 22, 13, 24, 26, 14, 19, 22, 18, 29, 22, 30, 30, 34, 34, 30, + 36, 37, 34, 39, 63, 63, 58, 53, 52, 46, 51, 50, 64, 55, 52, 53, 48, 6, + ], ); -const DISTANCE_ENEMY_ROOK_MG_EG: ([Score; DISTANCE_LEN], [Score; DISTANCE_LEN]) = ( - [0, -245, -68, -53, -35, -19, -1, 13], - [0, 67, 9, 0, -4, -7, -13, -20], +const ROOK_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG: ( + [Score; SQUARE_RELATIVE_TO_KING_LEN], + [Score; SQUARE_RELATIVE_TO_KING_LEN], +) = ( + [ + 7, 22, 11, 5, 4, 0, -1, 1, 13, 20, 22, 17, 19, 11, 10, 3, 21, 5, -7, 19, 14, 18, 12, 1, 1, + 4, 12, 4, 28, 18, 11, 0, -7, 3, 16, 24, 22, 6, 17, 10, -31, -4, 42, 11, 18, 41, 44, 22, + -62, -73, -10, -14, -11, 1, 6, 13, 0, -177, -64, -68, -43, -25, -8, 19, -194, -81, -22, + -24, -5, 22, 21, 29, -59, -33, -16, -11, 25, 17, -3, 16, -40, -18, -14, -6, -1, 7, 11, 52, + -19, -25, -8, -10, 2, 11, 0, 35, -27, -15, -4, -5, 13, 3, 14, 14, -15, -25, -15, -5, 7, 4, + -3, 21, -38, -40, -35, -32, -26, -31, -26, -6, + ], + [ + 36, 72, 37, 24, 19, 0, -1, 2, 59, 98, 75, 62, 58, 50, 40, 10, 69, 82, 67, 74, 89, 77, 50, + 15, 54, 63, 57, 64, 64, 64, 53, 22, 27, 45, 45, 44, 47, 46, 31, 32, 19, 39, 29, 31, 30, 27, + 33, 23, -69, 66, 32, 31, 32, 30, 33, 25, 0, -32, 15, 1, 1, 1, 7, -2, -22, 39, -2, -9, -9, + -18, -19, -10, -17, -3, -13, -21, -33, -32, -25, -22, -23, -18, -29, -30, -37, -34, -47, + -37, -29, -26, -40, -43, -43, -52, -48, -53, -26, -39, -47, -51, -59, -59, -68, -53, -48, + -44, -57, -63, -71, -67, -72, -89, -50, -47, -56, -62, -63, -63, -75, -70, + ], ); -const DISTANCE_FRIENDLY_QUEEN_MG_EG: ([Score; DISTANCE_LEN], [Score; DISTANCE_LEN]) = ( - [0, 175, 172, 168, 160, 158, 163, 135], - [0, 14, 31, 36, 35, 37, 40, 46], +const QUEEN_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG: ( + [Score; SQUARE_RELATIVE_TO_KING_LEN], + [Score; SQUARE_RELATIVE_TO_KING_LEN], +) = ( + [ + 4, -4, 2, 2, -2, 0, -3, 2, 3, 0, 0, 9, 5, -3, -2, 4, -1, -2, 7, 6, -10, 1, -4, 0, 0, -23, + 2, -10, -5, 0, 7, -2, -5, 1, 5, -11, -16, -7, -7, 0, -3, -17, 39, -19, -11, -27, 8, 0, -3, + -6, 9, 25, 38, 1, -10, -26, 0, 34, 20, 34, 22, 28, 8, 4, 53, 52, 45, 35, 29, 34, 43, 9, 57, + 49, 53, 41, 37, 35, 40, 36, 47, 43, 47, 31, 57, 63, 53, 4, 29, 39, 32, 46, 44, 59, 47, 17, + 7, 37, 24, 31, 46, 12, 39, 20, 66, 48, 18, 38, 52, 59, 65, 16, 40, 60, 35, -27, 16, 43, + 103, 4, + ], + [ + 8, -8, 5, 3, -3, 0, -4, 4, 7, -1, -3, 15, 5, -6, -6, 5, 3, -5, 17, 11, -18, 5, -9, 0, 3, + -29, 9, -8, 2, -1, 7, -4, -10, 8, 11, -20, -7, 0, -14, -1, 5, 34, -32, 17, 17, -1, 1, -17, + -2, 9, 9, -4, -25, 11, -3, -1, 0, -4, 18, 9, 11, 1, 31, -24, -3, 11, 1, 18, 28, 21, -10, + -20, 5, 15, -2, 18, 8, 17, -11, 1, -10, 24, 17, 21, -9, -8, -3, 39, 12, 21, 27, 29, 25, + -10, 16, 22, 39, 42, 68, 31, 13, 46, 40, 3, 29, 33, 57, 56, 36, 30, 51, 40, 36, 28, 28, 79, + 44, 26, 42, 9, + ], ); -const DISTANCE_ENEMY_QUEEN_MG_EG: ([Score; DISTANCE_LEN], [Score; DISTANCE_LEN]) = ( - [0, -553, -172, -122, -93, -80, -65, -48], - [0, -212, -20, -16, -7, -5, 5, 16], +const QUEEN_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG: ( + [Score; SQUARE_RELATIVE_TO_KING_LEN], + [Score; SQUARE_RELATIVE_TO_KING_LEN], +) = ( + [ + 2, 22, 4, 10, 27, 6, 13, 5, 6, 21, 22, 17, 20, 26, 8, 6, 3, 12, 24, 1, 27, 5, 26, 4, -11, + 33, -2, 19, -2, 23, 19, 10, -26, -41, -7, -35, 31, 5, 15, 6, -44, -27, -57, -38, -2, -5, 9, + -21, -29, -40, -12, -60, 8, 24, 43, 46, 0, -142, -141, -41, -13, 19, 68, 30, -415, -375, + -61, -24, -4, 35, 46, 76, -106, -81, -114, -52, -16, 27, 34, 35, -85, -57, -57, -44, -35, + -37, 10, -5, -57, -43, -43, -35, -19, -13, -4, 7, -36, -37, -23, -38, -27, -26, -23, -19, + -41, -32, -25, -34, -25, -10, -34, -13, -46, -30, -34, -30, -34, -38, -17, -2, + ], + [ + 4, 29, 8, 18, 40, 15, 23, 2, 10, 44, 30, 41, 42, 33, 16, 9, 23, 34, 34, 17, 50, 6, 36, 6, + 1, 48, 6, 48, 9, 59, 28, 16, -25, 13, 15, -28, 44, 5, 24, 14, -64, -2, -60, 4, -2, -1, 16, + -24, -37, -55, -13, 20, 9, 0, 29, 39, 0, -134, -66, -48, -49, -49, -49, 1, -202, -145, -20, + -50, -18, -46, -12, -1, -92, -18, -105, -7, -46, -51, -59, -10, -42, -39, -23, -53, -10, + -34, -53, -6, -30, -17, -25, -35, -55, -23, -58, -24, -4, -20, -46, -16, -38, -2, 13, -32, + 2, 1, -25, -4, -29, -30, 2, 8, 42, 30, -5, -14, 6, -5, 5, 9, + ], ); -const DISTANCE_FRIENDLY_KING_MG_EG: ([Score; DISTANCE_LEN], [Score; DISTANCE_LEN]) = - ([0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]); -const DISTANCE_ENEMY_KING_MG_EG: ([Score; DISTANCE_LEN], [Score; DISTANCE_LEN]) = - ([0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]); // Piece square tables: // We only define values for the queenside (left side) and mirror them to the @@ -125,138 +296,138 @@ const DISTANCE_ENEMY_KING_MG_EG: ([Score; DISTANCE_LEN], [Score; DISTANCE_LEN]) const PST_PAWN_MG_EG: ([Score; 32], [Score; 32]) = ( [ 0, 0, 0, 0, - 125, 127, 147, 150, - 89, 104, 152, 130, - 85, 99, 96, 118, - 67, 82, 96, 109, - 76, 87, 88, 89, - 68, 99, 84, 77, + 117, 155, 151, 170, + 63, 88, 133, 108, + 55, 68, 66, 87, + 36, 55, 65, 77, + 55, 57, 64, 59, + 44, 76, 65, 50, 0, 0, 0, 0, ], [ 0, 0, 0, 0, - 284, 289, 264, 244, - 78, 87, 85, 89, - 71, 74, 78, 65, - 64, 66, 68, 62, - 52, 58, 65, 68, - 50, 50, 68, 72, + 311, 314, 297, 280, + 114, 122, 122, 138, + 106, 110, 117, 111, + 97, 99, 104, 105, + 81, 90, 98, 108, + 78, 80, 101, 111, 0, 0, 0, 0, ], ); #[rustfmt::skip] const PST_KNIGHT_MG_EG: ([Score; 32], [Score; 32]) = ( [ - 136, 268, 212, 273, - 266, 288, 373, 341, - 286, 330, 342, 358, - 340, 325, 338, 342, - 309, 321, 344, 338, - 305, 325, 333, 341, - 314, 313, 323, 329, - 267, 308, 307, 309, - ], - [ - 255, 260, 290, 292, - 283, 295, 282, 292, - 291, 295, 322, 313, - 293, 314, 327, 332, - 295, 305, 317, 327, - 282, 298, 302, 318, - 279, 291, 298, 300, - 272, 282, 301, 302, + 186, 278, 252, 308, + 299, 294, 398, 324, + 295, 354, 349, 403, + 333, 342, 336, 356, + 311, 319, 342, 343, + 306, 328, 328, 341, + 309, 317, 318, 321, + 264, 291, 307, 301, + ], + [ + 239, 266, 290, 292, + 270, 291, 277, 293, + 282, 285, 313, 297, + 286, 299, 318, 318, + 282, 299, 311, 318, + 277, 290, 299, 312, + 276, 287, 298, 300, + 278, 296, 299, 301, ], ); #[rustfmt::skip] const PST_BISHOP_MG_EG: ([Score; 32], [Score; 32]) = ( [ - 283, 290, 228, 194, - 275, 304, 296, 282, - 319, 331, 353, 334, - 302, 311, 305, 328, - 313, 325, 319, 347, - 338, 331, 339, 325, - 326, 361, 334, 332, - 331, 322, 316, 322, - ], - [ - 300, 293, 304, 312, - 299, 303, 301, 300, - 301, 301, 302, 304, - 301, 304, 307, 312, - 294, 291, 304, 299, - 285, 293, 294, 303, - 289, 280, 287, 291, - 285, 295, 299, 302, + 302, 312, 294, 252, + 295, 355, 337, 340, + 344, 344, 365, 339, + 329, 326, 332, 346, + 315, 327, 327, 350, + 340, 333, 346, 329, + 320, 351, 333, 323, + 332, 321, 312, 313, + ], + [ + 292, 289, 293, 302, + 295, 293, 294, 287, + 298, 299, 299, 302, + 295, 299, 301, 305, + 295, 292, 303, 300, + 284, 295, 296, 305, + 295, 292, 293, 299, + 290, 303, 312, 311, ], ); #[rustfmt::skip] const PST_ROOK_MG_EG: ([Score; 32], [Score; 32]) = ( [ - 535, 557, 557, 552, - 533, 500, 519, 504, - 524, 512, 488, 487, - 496, 488, 483, 478, - 486, 476, 465, 478, - 499, 500, 501, 514, - 497, 519, 526, 530, - 541, 538, 559, 565, - ], - [ - 499, 493, 491, 490, - 497, 514, 510, 510, - 499, 506, 512, 513, - 500, 505, 514, 513, - 498, 505, 513, 513, - 490, 492, 496, 497, - 491, 492, 497, 494, - 474, 485, 482, 483, + 542, 572, 563, 560, + 566, 544, 562, 553, + 538, 525, 520, 520, + 506, 503, 511, 498, + 497, 491, 487, 491, + 510, 507, 505, 516, + 475, 508, 498, 511, + 489, 483, 511, 511, + ], + [ + 515, 505, 505, 504, + 499, 511, 506, 502, + 499, 503, 503, 503, + 495, 498, 502, 503, + 488, 494, 500, 503, + 477, 482, 485, 487, + 484, 482, 496, 490, + 480, 493, 490, 495, ], ); #[rustfmt::skip] const PST_QUEEN_MG_EG: ([Score; 32], [Score; 32]) = ( [ - 915, 935, 939, 966, - 926, 881, 875, 791, - 925, 942, 906, 895, - 927, 906, 899, 887, - 934, 934, 927, 919, - 952, 958, 950, 947, - 968, 984, 980, 979, - 999, 995, 995, 998, - ], - [ - 931, 904, 914, 897, - 919, 941, 963, 997, - 899, 895, 931, 946, - 907, 925, 930, 943, - 905, 902, 899, 923, - 881, 877, 899, 885, - 896, 874, 875, 882, - 879, 869, 877, 874, + 962, 968, 968, 992, + 983, 958, 945, 883, + 982, 1014, 947, 946, + 964, 930, 935, 927, + 963, 959, 955, 949, + 975, 983, 971, 968, + 978, 1003, 1000, 994, + 1030, 997, 1012, 1010, + ], + [ + 953, 944, 959, 948, + 941, 950, 970, 996, + 921, 908, 962, 965, + 932, 958, 961, 975, + 930, 938, 937, 959, + 923, 922, 934, 924, + 947, 906, 897, 924, + 915, 914, 919, 912, ], ); #[rustfmt::skip] const PST_KING_MG_EG: ([Score; 32], [Score; 32]) = ( [ - 21, 28, 48, 44, - -11, 39, 85, 50, - -10, 95, 70, 50, - -49, 6, 37, 10, - -74, -18, -31, -47, - -36, -3, -40, -87, - 7, 25, -41, -85, - 5, 25, -44, -70, - ], - [ - -47, -21, -21, -20, - -2, 5, -6, -9, - 2, 4, 1, -2, - 4, 1, 1, 3, - -1, -1, 5, 12, - -2, 1, 13, 24, - -6, 3, 22, 32, - -29, -8, 20, 19, + 19, 13, 32, 12, + -9, 10, 44, -1, + 5, 78, 32, 20, + -17, 9, 27, 4, + -34, 0, -16, -25, + 3, 20, -29, -58, + 43, 27, -33, -64, + 6, 24, -56, -85, + ], + [ + -50, -13, -9, -6, + -23, 0, -5, -5, + -17, -4, -3, -9, + -15, -8, -9, -11, + -11, -5, -2, 1, + -5, 2, 14, 20, + 1, 14, 30, 34, + -2, 15, 40, 41, ], ); @@ -275,14 +446,17 @@ const fn human_readable_to_file_rank(piece_value: Score, pst: [Score; 32]) -> [S res } -const fn convert_distance( - mg_eg: ([Score; DISTANCE_LEN], [Score; DISTANCE_LEN]), -) -> [ScorePair; DISTANCE_LEN] { +const fn convert_square_relative_to( + mg_eg: ( + [Score; SQUARE_RELATIVE_TO_KING_LEN], + [Score; SQUARE_RELATIVE_TO_KING_LEN], + ), +) -> [ScorePair; SQUARE_RELATIVE_TO_KING_LEN] { let mg = mg_eg.0; let eg = mg_eg.1; - let mut scores = [ScorePair(0, 0); DISTANCE_LEN]; + let mut scores = [ScorePair(0, 0); SQUARE_RELATIVE_TO_KING_LEN]; let mut idx = 0; - while idx < DISTANCE_LEN { + while idx < SQUARE_RELATIVE_TO_KING_LEN { scores[idx] = ScorePair(mg[idx], eg[idx]); idx += 1; } @@ -337,37 +511,26 @@ pub const MOBILITY_QUEEN: [ScorePair; 28] = { table }; -pub const DISTANCE_FRIENDLY_PAWN: [ScorePair; DISTANCE_LEN] = - convert_distance(DISTANCE_FRIENDLY_PAWN_MG_EG); -pub const DISTANCE_ENEMY_PAWN: [ScorePair; DISTANCE_LEN] = - convert_distance(DISTANCE_ENEMY_PAWN_MG_EG); - -pub const DISTANCE_FRIENDLY_KNIGHT: [ScorePair; DISTANCE_LEN] = - convert_distance(DISTANCE_FRIENDLY_KNIGHT_MG_EG); -pub const DISTANCE_ENEMY_KNIGHT: [ScorePair; DISTANCE_LEN] = - convert_distance(DISTANCE_ENEMY_KNIGHT_MG_EG); - -pub const DISTANCE_FRIENDLY_BISHOP: [ScorePair; DISTANCE_LEN] = - convert_distance(DISTANCE_FRIENDLY_BISHOP_MG_EG); -pub const DISTANCE_ENEMY_BISHOP: [ScorePair; DISTANCE_LEN] = - convert_distance(DISTANCE_ENEMY_BISHOP_MG_EG); - -pub const DISTANCE_FRIENDLY_ROOK: [ScorePair; DISTANCE_LEN] = - convert_distance(DISTANCE_FRIENDLY_ROOK_MG_EG); -pub const DISTANCE_ENEMY_ROOK: [ScorePair; DISTANCE_LEN] = - convert_distance(DISTANCE_ENEMY_ROOK_MG_EG); - -pub const DISTANCE_FRIENDLY_QUEEN: [ScorePair; DISTANCE_LEN] = - convert_distance(DISTANCE_FRIENDLY_QUEEN_MG_EG); -pub const DISTANCE_ENEMY_QUEEN: [ScorePair; DISTANCE_LEN] = - convert_distance(DISTANCE_ENEMY_QUEEN_MG_EG); - -// This will always be 0, but is included to avoid branches -pub const DISTANCE_FRIENDLY_KING: [ScorePair; DISTANCE_LEN] = - convert_distance(DISTANCE_FRIENDLY_KING_MG_EG); -// Both sides will cancel each other out, but it is included to avoid branches -pub const DISTANCE_ENEMY_KING: [ScorePair; DISTANCE_LEN] = - convert_distance(DISTANCE_ENEMY_KING_MG_EG); +pub const PAWN_SQUARE_RELATIVE_TO_FRIENDLY_KING: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN] = + convert_square_relative_to(PAWN_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG); +pub const PAWN_SQUARE_RELATIVE_TO_ENEMY_KING: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN] = + convert_square_relative_to(PAWN_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG); +pub const KNIGHT_SQUARE_RELATIVE_TO_FRIENDLY_KING: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN] = + convert_square_relative_to(KNIGHT_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG); +pub const KNIGHT_SQUARE_RELATIVE_TO_ENEMY_KING: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN] = + convert_square_relative_to(KNIGHT_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG); +pub const BISHOP_SQUARE_RELATIVE_TO_FRIENDLY_KING: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN] = + convert_square_relative_to(BISHOP_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG); +pub const BISHOP_SQUARE_RELATIVE_TO_ENEMY_KING: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN] = + convert_square_relative_to(BISHOP_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG); +pub const ROOK_SQUARE_RELATIVE_TO_FRIENDLY_KING: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN] = + convert_square_relative_to(ROOK_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG); +pub const ROOK_SQUARE_RELATIVE_TO_ENEMY_KING: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN] = + convert_square_relative_to(ROOK_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG); +pub const QUEEN_SQUARE_RELATIVE_TO_FRIENDLY_KING: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN] = + convert_square_relative_to(QUEEN_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG); +pub const QUEEN_SQUARE_RELATIVE_TO_ENEMY_KING: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN] = + convert_square_relative_to(QUEEN_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG); pub const PASSED_PAWN: PieceSquareTable = { let mg = human_readable_to_file_rank(0, PASSED_PAWN_MG_EG.0); diff --git a/eval/src/piece_table_refs.rs b/eval/src/piece_table_refs.rs index 1dc10e8..7977451 100644 --- a/eval/src/piece_table_refs.rs +++ b/eval/src/piece_table_refs.rs @@ -5,8 +5,8 @@ use crate::{params, score_pair::ScorePair}; #[derive(Debug, Clone, Copy)] pub struct PieceTableRefs<'a> { pub pst: &'a [ScorePair], - pub friendly_distance: &'a [ScorePair], - pub enemy_distance: &'a [ScorePair], + pub square_relative_to_friendly_king: &'a [ScorePair], + pub square_relative_to_enemy_king: &'a [ScorePair], } pub const PIECE_TABLE_REFS: [PieceTableRefs; 6] = { @@ -20,8 +20,8 @@ pub const PIECE_TABLE_REFS: [PieceTableRefs; 6] = { ]; let mut piece_tables = [PieceTableRefs { pst: &[], - friendly_distance: &[], - enemy_distance: &[], + square_relative_to_friendly_king: &[], + square_relative_to_enemy_king: &[], }; 6]; let mut i = 0; while i < piece_types.len() { @@ -29,33 +29,33 @@ pub const PIECE_TABLE_REFS: [PieceTableRefs; 6] = { let tables = match pt { piece::Type::Pawn => PieceTableRefs { pst: ¶ms::PST_PAWN, - friendly_distance: ¶ms::DISTANCE_FRIENDLY_PAWN, - enemy_distance: ¶ms::DISTANCE_ENEMY_PAWN, + square_relative_to_friendly_king: ¶ms::PAWN_SQUARE_RELATIVE_TO_FRIENDLY_KING, + square_relative_to_enemy_king: ¶ms::PAWN_SQUARE_RELATIVE_TO_ENEMY_KING, }, piece::Type::Knight => PieceTableRefs { pst: ¶ms::PST_KNIGHT, - friendly_distance: ¶ms::DISTANCE_FRIENDLY_KNIGHT, - enemy_distance: ¶ms::DISTANCE_ENEMY_KNIGHT, + square_relative_to_friendly_king: ¶ms::KNIGHT_SQUARE_RELATIVE_TO_FRIENDLY_KING, + square_relative_to_enemy_king: ¶ms::KNIGHT_SQUARE_RELATIVE_TO_ENEMY_KING, }, piece::Type::Bishop => PieceTableRefs { pst: ¶ms::PST_BISHOP, - friendly_distance: ¶ms::DISTANCE_FRIENDLY_BISHOP, - enemy_distance: ¶ms::DISTANCE_ENEMY_BISHOP, + square_relative_to_friendly_king: ¶ms::BISHOP_SQUARE_RELATIVE_TO_FRIENDLY_KING, + square_relative_to_enemy_king: ¶ms::BISHOP_SQUARE_RELATIVE_TO_ENEMY_KING, }, piece::Type::Rook => PieceTableRefs { pst: ¶ms::PST_ROOK, - friendly_distance: ¶ms::DISTANCE_FRIENDLY_ROOK, - enemy_distance: ¶ms::DISTANCE_ENEMY_ROOK, + square_relative_to_friendly_king: ¶ms::ROOK_SQUARE_RELATIVE_TO_FRIENDLY_KING, + square_relative_to_enemy_king: ¶ms::ROOK_SQUARE_RELATIVE_TO_ENEMY_KING, }, piece::Type::Queen => PieceTableRefs { pst: ¶ms::PST_QUEEN, - friendly_distance: ¶ms::DISTANCE_FRIENDLY_QUEEN, - enemy_distance: ¶ms::DISTANCE_ENEMY_QUEEN, + square_relative_to_friendly_king: ¶ms::QUEEN_SQUARE_RELATIVE_TO_FRIENDLY_KING, + square_relative_to_enemy_king: ¶ms::QUEEN_SQUARE_RELATIVE_TO_ENEMY_KING, }, piece::Type::King => PieceTableRefs { pst: ¶ms::PST_KING, - friendly_distance: &[], - enemy_distance: &[], + square_relative_to_friendly_king: &[], + square_relative_to_enemy_king: &[], }, }; piece_tables[pt.idx()] = tables; diff --git a/movegen/src/square.rs b/movegen/src/square.rs index 836ae34..f26f1f1 100644 --- a/movegen/src/square.rs +++ b/movegen/src/square.rs @@ -179,6 +179,11 @@ impl Square { .abs() .max((self.rank().idx() as i8 - other.rank().idx() as i8).abs()) as usize } + + pub fn relative_to(self, other: Self) -> i8 { + (self.rank().idx() as i8 - other.rank().idx() as i8) * File::NUM_FILES as i8 + + (self.file().idx() as i8 - other.file().idx() as i8).abs() + } } impl From<(File, Rank)> for Square { @@ -372,6 +377,20 @@ mod tests { assert_eq!(7, Square::H8.distance(Square::A1)); } + #[test] + fn relative_to() { + assert_eq!(0, Square::A1.relative_to(Square::A1)); + assert_eq!(-8, Square::A1.relative_to(Square::A2)); + assert_eq!(1, Square::A1.relative_to(Square::B1)); + assert_eq!(-7, Square::A1.relative_to(Square::B2)); + assert_eq!(-56, Square::A1.relative_to(Square::A8)); + assert_eq!(7, Square::A1.relative_to(Square::H1)); + assert_eq!(-49, Square::A1.relative_to(Square::H8)); + assert_eq!(56, Square::H8.relative_to(Square::H1)); + assert_eq!(7, Square::H8.relative_to(Square::A8)); + assert_eq!(63, Square::H8.relative_to(Square::A1)); + } + #[test] fn fmt() { assert_eq!("a1", format!("{}", Square::A1)); diff --git a/search/tests/search.rs b/search/tests/search.rs index fc459e7..1361242 100644 --- a/search/tests/search.rs +++ b/search/tests/search.rs @@ -385,7 +385,7 @@ fn underpromotions(search_algo: impl Search + Send + 'static) { ), ( "8/3P4/3b4/8/8/1p2k2p/1Pp4P/2K5 w - - 0 1", - 7, + 8, Move::new(Square::D7, Square::D8, MoveType::PROMOTION_ROOK), ), ( diff --git a/tuner/src/eval_params.rs b/tuner/src/eval_params.rs index 5e076f6..af92e4c 100644 --- a/tuner/src/eval_params.rs +++ b/tuner/src/eval_params.rs @@ -1,7 +1,9 @@ use std::fmt::Display; use eval::{ - params::{BISHOP_MOB_LEN, DISTANCE_LEN, KNIGHT_MOB_LEN, QUEEN_MOB_LEN, ROOK_MOB_LEN}, + params::{ + BISHOP_MOB_LEN, KNIGHT_MOB_LEN, QUEEN_MOB_LEN, ROOK_MOB_LEN, SQUARE_RELATIVE_TO_KING_LEN, + }, score_pair::ScorePair, Score, }; @@ -26,18 +28,16 @@ pub struct EvalParams { rook_mobility: [ScorePair; ROOK_MOB_LEN], queen_mobility: [ScorePair; QUEEN_MOB_LEN], bishop_pair: ScorePair, - distance_friendly_pawn: [ScorePair; DISTANCE_LEN], - distance_enemy_pawn: [ScorePair; DISTANCE_LEN], - distance_friendly_knight: [ScorePair; DISTANCE_LEN], - distance_enemy_knight: [ScorePair; DISTANCE_LEN], - distance_friendly_bishop: [ScorePair; DISTANCE_LEN], - distance_enemy_bishop: [ScorePair; DISTANCE_LEN], - distance_friendly_rook: [ScorePair; DISTANCE_LEN], - distance_enemy_rook: [ScorePair; DISTANCE_LEN], - distance_friendly_queen: [ScorePair; DISTANCE_LEN], - distance_enemy_queen: [ScorePair; DISTANCE_LEN], - distance_friendly_king: [ScorePair; DISTANCE_LEN], - distance_enemy_king: [ScorePair; DISTANCE_LEN], + pawn_square_relative_to_friendly_king: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN], + pawn_square_relative_to_enemy_king: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN], + knight_square_relative_to_friendly_king: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN], + knight_square_relative_to_enemy_king: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN], + bishop_square_relative_to_friendly_king: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN], + bishop_square_relative_to_enemy_king: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN], + rook_square_relative_to_friendly_king: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN], + rook_square_relative_to_enemy_king: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN], + queen_square_relative_to_friendly_king: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN], + queen_square_relative_to_enemy_king: [ScorePair; SQUARE_RELATIVE_TO_KING_LEN], } impl Default for EvalParams { @@ -59,18 +59,16 @@ impl Default for EvalParams { rook_mobility: [ScorePair(0, 0); ROOK_MOB_LEN], queen_mobility: [ScorePair(0, 0); QUEEN_MOB_LEN], bishop_pair: ScorePair(0, 0), - distance_friendly_pawn: [ScorePair(0, 0); DISTANCE_LEN], - distance_enemy_pawn: [ScorePair(0, 0); DISTANCE_LEN], - distance_friendly_knight: [ScorePair(0, 0); DISTANCE_LEN], - distance_enemy_knight: [ScorePair(0, 0); DISTANCE_LEN], - distance_friendly_bishop: [ScorePair(0, 0); DISTANCE_LEN], - distance_enemy_bishop: [ScorePair(0, 0); DISTANCE_LEN], - distance_friendly_rook: [ScorePair(0, 0); DISTANCE_LEN], - distance_enemy_rook: [ScorePair(0, 0); DISTANCE_LEN], - distance_friendly_queen: [ScorePair(0, 0); DISTANCE_LEN], - distance_enemy_queen: [ScorePair(0, 0); DISTANCE_LEN], - distance_friendly_king: [ScorePair(0, 0); DISTANCE_LEN], - distance_enemy_king: [ScorePair(0, 0); DISTANCE_LEN], + pawn_square_relative_to_friendly_king: [ScorePair(0, 0); SQUARE_RELATIVE_TO_KING_LEN], + pawn_square_relative_to_enemy_king: [ScorePair(0, 0); SQUARE_RELATIVE_TO_KING_LEN], + knight_square_relative_to_friendly_king: [ScorePair(0, 0); SQUARE_RELATIVE_TO_KING_LEN], + knight_square_relative_to_enemy_king: [ScorePair(0, 0); SQUARE_RELATIVE_TO_KING_LEN], + bishop_square_relative_to_friendly_king: [ScorePair(0, 0); SQUARE_RELATIVE_TO_KING_LEN], + bishop_square_relative_to_enemy_king: [ScorePair(0, 0); SQUARE_RELATIVE_TO_KING_LEN], + rook_square_relative_to_friendly_king: [ScorePair(0, 0); SQUARE_RELATIVE_TO_KING_LEN], + rook_square_relative_to_enemy_king: [ScorePair(0, 0); SQUARE_RELATIVE_TO_KING_LEN], + queen_square_relative_to_friendly_king: [ScorePair(0, 0); SQUARE_RELATIVE_TO_KING_LEN], + queen_square_relative_to_enemy_king: [ScorePair(0, 0); SQUARE_RELATIVE_TO_KING_LEN], } } } @@ -95,18 +93,46 @@ impl From<&WeightVector> for EvalParams { Self::next_params(&mut eval_params.rook_mobility, &mut weight_iter); Self::next_params(&mut eval_params.queen_mobility, &mut weight_iter); Self::next_param(&mut eval_params.bishop_pair, &mut weight_iter); - Self::next_params(&mut eval_params.distance_friendly_pawn, &mut weight_iter); - Self::next_params(&mut eval_params.distance_enemy_pawn, &mut weight_iter); - Self::next_params(&mut eval_params.distance_friendly_knight, &mut weight_iter); - Self::next_params(&mut eval_params.distance_enemy_knight, &mut weight_iter); - Self::next_params(&mut eval_params.distance_friendly_bishop, &mut weight_iter); - Self::next_params(&mut eval_params.distance_enemy_bishop, &mut weight_iter); - Self::next_params(&mut eval_params.distance_friendly_rook, &mut weight_iter); - Self::next_params(&mut eval_params.distance_enemy_rook, &mut weight_iter); - Self::next_params(&mut eval_params.distance_friendly_queen, &mut weight_iter); - Self::next_params(&mut eval_params.distance_enemy_queen, &mut weight_iter); - Self::next_params(&mut eval_params.distance_friendly_king, &mut weight_iter); - Self::next_params(&mut eval_params.distance_enemy_king, &mut weight_iter); + Self::next_params( + &mut eval_params.pawn_square_relative_to_friendly_king, + &mut weight_iter, + ); + Self::next_params( + &mut eval_params.pawn_square_relative_to_enemy_king, + &mut weight_iter, + ); + Self::next_params( + &mut eval_params.knight_square_relative_to_friendly_king, + &mut weight_iter, + ); + Self::next_params( + &mut eval_params.knight_square_relative_to_enemy_king, + &mut weight_iter, + ); + Self::next_params( + &mut eval_params.bishop_square_relative_to_friendly_king, + &mut weight_iter, + ); + Self::next_params( + &mut eval_params.bishop_square_relative_to_enemy_king, + &mut weight_iter, + ); + Self::next_params( + &mut eval_params.rook_square_relative_to_friendly_king, + &mut weight_iter, + ); + Self::next_params( + &mut eval_params.rook_square_relative_to_enemy_king, + &mut weight_iter, + ); + Self::next_params( + &mut eval_params.queen_square_relative_to_friendly_king, + &mut weight_iter, + ); + Self::next_params( + &mut eval_params.queen_square_relative_to_enemy_king, + &mut weight_iter, + ); eval_params } } @@ -142,7 +168,7 @@ impl Display for EvalParams { )?; self.fmt_mobilities(f)?; - self.fmt_distances(f)?; + self.fmt_squares_relative_to_king(f)?; self.fmt_pst(f)?; Ok(()) @@ -196,31 +222,50 @@ impl EvalParams { Ok(()) } - fn fmt_distances(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for (const_name, distance) in [ - ("DISTANCE_FRIENDLY_PAWN_MG_EG", &self.distance_friendly_pawn), - ("DISTANCE_ENEMY_PAWN_MG_EG", &self.distance_enemy_pawn), + fn fmt_squares_relative_to_king(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for (const_name, weights) in [ ( - "DISTANCE_FRIENDLY_KNIGHT_MG_EG", - &self.distance_friendly_knight, + "PAWN_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG", + &self.pawn_square_relative_to_friendly_king, ), - ("DISTANCE_ENEMY_KNIGHT_MG_EG", &self.distance_enemy_knight), ( - "DISTANCE_FRIENDLY_BISHOP_MG_EG", - &self.distance_friendly_bishop, + "PAWN_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG", + &self.pawn_square_relative_to_enemy_king, ), - ("DISTANCE_ENEMY_BISHOP_MG_EG", &self.distance_enemy_bishop), - ("DISTANCE_FRIENDLY_ROOK_MG_EG", &self.distance_friendly_rook), - ("DISTANCE_ENEMY_ROOK_MG_EG", &self.distance_enemy_rook), ( - "DISTANCE_FRIENDLY_QUEEN_MG_EG", - &self.distance_friendly_queen, + "KNIGHT_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG", + &self.knight_square_relative_to_friendly_king, + ), + ( + "KNIGHT_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG", + &self.knight_square_relative_to_enemy_king, + ), + ( + "BISHOP_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG", + &self.bishop_square_relative_to_friendly_king, + ), + ( + "BISHOP_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG", + &self.bishop_square_relative_to_enemy_king, + ), + ( + "ROOK_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG", + &self.rook_square_relative_to_friendly_king, + ), + ( + "ROOK_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG", + &self.rook_square_relative_to_enemy_king, + ), + ( + "QUEEN_SQUARE_RELATIVE_TO_FRIENDLY_KING_MG_EG", + &self.queen_square_relative_to_friendly_king, + ), + ( + "QUEEN_SQUARE_RELATIVE_TO_ENEMY_KING_MG_EG", + &self.queen_square_relative_to_enemy_king, ), - ("DISTANCE_ENEMY_QUEEN_MG_EG", &self.distance_enemy_queen), - ("DISTANCE_FRIENDLY_KING_MG_EG", &self.distance_friendly_king), - ("DISTANCE_ENEMY_KING_MG_EG", &self.distance_enemy_king), ] { - self.fmt_weights(f, const_name, "DISTANCE_LEN", distance)?; + self.fmt_weights(f, const_name, "SQUARE_RELATIVE_TO_KING_LEN", weights)?; } Ok(()) } diff --git a/tuner/src/feature_evaluator.rs b/tuner/src/feature_evaluator.rs index 698e8d5..b23ea3d 100644 --- a/tuner/src/feature_evaluator.rs +++ b/tuner/src/feature_evaluator.rs @@ -1,6 +1,6 @@ use std::iter; -use eval::params::{self, DISTANCE_LEN, MOB_LEN}; +use eval::params::{self, MOB_LEN, SQUARE_RELATIVE_TO_KING_LEN}; use nalgebra::SVector; use crate::eval_coeffs::EvalCoeffs; @@ -24,7 +24,8 @@ const NUM_BACKWARD_PAWN_FEATURES: usize = 1; const NUM_DOUBLED_PAWN_FEATURES: usize = 1; const NUM_MOBILITY_FEATURES: usize = MOB_LEN; const NUM_BISHOP_PAIR_FEATURES: usize = 1; -const NUM_KING_TROPISM_FEATURES: usize = NUM_SIDES * NUM_PIECE_TYPES * DISTANCE_LEN; +const NUM_SQUARE_RELATIVE_TO_KING_FEATURES: usize = + NUM_SIDES * (NUM_PIECE_TYPES - 1) * SQUARE_RELATIVE_TO_KING_LEN; pub const NUM_FEATURES: usize = NUM_PST_FEATURES + NUM_TEMPO_FEATURES + NUM_PASSED_PAWN_FEATURES @@ -33,7 +34,7 @@ pub const NUM_FEATURES: usize = NUM_PST_FEATURES + NUM_DOUBLED_PAWN_FEATURES + NUM_MOBILITY_FEATURES + NUM_BISHOP_PAIR_FEATURES - + NUM_KING_TROPISM_FEATURES; + + NUM_SQUARE_RELATIVE_TO_KING_FEATURES; pub const START_IDX_PST: usize = 0; @@ -126,18 +127,16 @@ pub fn engine_weights() -> WeightVector { .chain(params::MOBILITY_ROOK.iter()) .chain(params::MOBILITY_QUEEN.iter()) .chain(iter::once(¶ms::BISHOP_PAIR)) - .chain(params::DISTANCE_FRIENDLY_PAWN.iter()) - .chain(params::DISTANCE_ENEMY_PAWN.iter()) - .chain(params::DISTANCE_FRIENDLY_KNIGHT.iter()) - .chain(params::DISTANCE_ENEMY_KNIGHT.iter()) - .chain(params::DISTANCE_FRIENDLY_BISHOP.iter()) - .chain(params::DISTANCE_ENEMY_BISHOP.iter()) - .chain(params::DISTANCE_FRIENDLY_ROOK.iter()) - .chain(params::DISTANCE_ENEMY_ROOK.iter()) - .chain(params::DISTANCE_FRIENDLY_QUEEN.iter()) - .chain(params::DISTANCE_ENEMY_QUEEN.iter()) - .chain(params::DISTANCE_FRIENDLY_KING.iter()) - .chain(params::DISTANCE_ENEMY_KING.iter()); + .chain(params::PAWN_SQUARE_RELATIVE_TO_FRIENDLY_KING.iter()) + .chain(params::PAWN_SQUARE_RELATIVE_TO_ENEMY_KING.iter()) + .chain(params::KNIGHT_SQUARE_RELATIVE_TO_FRIENDLY_KING.iter()) + .chain(params::KNIGHT_SQUARE_RELATIVE_TO_ENEMY_KING.iter()) + .chain(params::BISHOP_SQUARE_RELATIVE_TO_FRIENDLY_KING.iter()) + .chain(params::BISHOP_SQUARE_RELATIVE_TO_ENEMY_KING.iter()) + .chain(params::ROOK_SQUARE_RELATIVE_TO_FRIENDLY_KING.iter()) + .chain(params::ROOK_SQUARE_RELATIVE_TO_ENEMY_KING.iter()) + .chain(params::QUEEN_SQUARE_RELATIVE_TO_FRIENDLY_KING.iter()) + .chain(params::QUEEN_SQUARE_RELATIVE_TO_ENEMY_KING.iter()); let mut weights = WeightVector::from_element(0.0); for (idx, &weight) in weight_iter.enumerate() { // Middlegame