From ad8da357c2901310aba149c2fde5cc3bd3effad4 Mon Sep 17 00:00:00 2001 From: Tearth Date: Mon, 19 Aug 2024 08:11:55 +0200 Subject: [PATCH] Refactoring --- src/evaluation/mod.rs | 14 ++++----- src/evaluation/pawns.rs | 3 -- src/evaluation/pst/bishop.rs | 2 +- src/evaluation/pst/king.rs | 2 +- src/evaluation/pst/knight.rs | 2 +- src/evaluation/pst/mod.rs | 34 ++++++++++++++++++---- src/evaluation/pst/pawn.rs | 2 +- src/evaluation/pst/queen.rs | 2 +- src/evaluation/pst/rook.rs | 2 +- src/evaluation/safety.rs | 3 -- src/state/representation.rs | 55 ++++++++++++++++++++++++++---------- src/tuning/tuner.rs | 41 ++++++++++++++------------- 12 files changed, 100 insertions(+), 62 deletions(-) diff --git a/src/evaluation/mod.rs b/src/evaluation/mod.rs index 6fe3730..e19e927 100644 --- a/src/evaluation/mod.rs +++ b/src/evaluation/mod.rs @@ -1,5 +1,6 @@ use crate::state::*; -use crate::utils::bithelpers::BitHelpers; +use pst::*; +use std::hint::unreachable_unchecked; use std::ops; pub mod material; @@ -54,12 +55,7 @@ pub struct EvaluationResult { impl EvaluationParameters { /// Gets a PST value for the specified `color`, `piece`, `phase` and `square`. - pub fn get_pst_value(&self, color: usize, piece: usize, king_file: usize, phase: usize, mut square: usize) -> i16 { - if color == BLACK { - // king_file = (1u64 << (king_file & 0x3f)).swap_bytes().bit_scan(); - square = (1u64 << square).swap_bytes().bit_scan(); - } - + pub fn get_pst_value(&self, piece: usize, king_square: usize, phase: usize, square: usize) -> i16 { let pst = match piece { PAWN => &Self::PAWN_PST_PATTERN, KNIGHT => &Self::KNIGHT_PST_PATTERN, @@ -67,10 +63,10 @@ impl EvaluationParameters { ROOK => &Self::ROOK_PST_PATTERN, QUEEN => &Self::QUEEN_PST_PATTERN, KING => &Self::KING_PST_PATTERN, - _ => panic!("Invalid value: piece={}", piece), + _ => unsafe { unreachable_unchecked() }, }; - pst[king_file & 0x3f][phase][63 - square] + pst[KING_BUCKETS[63 - king_square]][phase][63 - square] } } diff --git a/src/evaluation/pawns.rs b/src/evaluation/pawns.rs index a8c7689..6cc8f2e 100644 --- a/src/evaluation/pawns.rs +++ b/src/evaluation/pawns.rs @@ -6,9 +6,6 @@ use crate::utils::bithelpers::BitHelpers; use crate::utils::conditional_expression; use std::cmp; -#[cfg(feature = "dev")] -use pst::*; - #[cfg(feature = "dev")] use crate::tuning::tuner::TunerCoefficient; diff --git a/src/evaluation/pst/bishop.rs b/src/evaluation/pst/bishop.rs index 4a4fa32..662adca 100644 --- a/src/evaluation/pst/bishop.rs +++ b/src/evaluation/pst/bishop.rs @@ -6,7 +6,7 @@ use super::*; impl EvaluationParameters { #[rustfmt::skip] - pub const BISHOP_PST_PATTERN: [[[i16; 64]; 2]; 8] = + pub const BISHOP_PST_PATTERN: [[[i16; 64]; 2]; KING_BUCKETS_COUNT] = [ [ [ diff --git a/src/evaluation/pst/king.rs b/src/evaluation/pst/king.rs index 5926882..70665ce 100644 --- a/src/evaluation/pst/king.rs +++ b/src/evaluation/pst/king.rs @@ -6,7 +6,7 @@ use super::*; impl EvaluationParameters { #[rustfmt::skip] - pub const KING_PST_PATTERN: [[[i16; 64]; 2]; 8] = + pub const KING_PST_PATTERN: [[[i16; 64]; 2]; KING_BUCKETS_COUNT] = [ [ [ diff --git a/src/evaluation/pst/knight.rs b/src/evaluation/pst/knight.rs index a09d0e6..e0a3d18 100644 --- a/src/evaluation/pst/knight.rs +++ b/src/evaluation/pst/knight.rs @@ -6,7 +6,7 @@ use super::*; impl EvaluationParameters { #[rustfmt::skip] - pub const KNIGHT_PST_PATTERN: [[[i16; 64]; 2]; 8] = + pub const KNIGHT_PST_PATTERN: [[[i16; 64]; 2]; KING_BUCKETS_COUNT] = [ [ [ diff --git a/src/evaluation/pst/mod.rs b/src/evaluation/pst/mod.rs index 483c5c7..a19721e 100644 --- a/src/evaluation/pst/mod.rs +++ b/src/evaluation/pst/mod.rs @@ -12,6 +12,20 @@ pub mod pawn; pub mod queen; pub mod rook; +pub const KING_BUCKETS_COUNT: usize = 8; + +#[rustfmt::skip] +pub const KING_BUCKETS: [usize; 64] = [ + 7, 6, 5, 4, 3, 2, 1, 0, + 7, 6, 5, 4, 3, 2, 1, 0, + 7, 6, 5, 4, 3, 2, 1, 0, + 7, 6, 5, 4, 3, 2, 1, 0, + 7, 6, 5, 4, 3, 2, 1, 0, + 7, 6, 5, 4, 3, 2, 1, 0, + 7, 6, 5, 4, 3, 2, 1, 0, + 7, 6, 5, 4, 3, 2, 1, 0, +]; + /// Evaluates piece-square table value on the `board` and returns score from the white color perspective (more than 0 when advantage, less than 0 when disadvantage). /// This evaluator sums all values of the pieces for the specified squares, using incremental counters in `board`. pub fn evaluate(board: &Board) -> EvaluationResult { @@ -24,17 +38,25 @@ pub fn evaluate(board: &Board) -> EvaluationResult { /// Recalculates incremental counters on the `board`. This function should be called only once during board initialization, as it's too slow in regular search. pub fn recalculate_incremental_values(board: &mut Board) { for color_index in ALL_COLORS { - let king_file = board.pieces[color_index][KING].bit_scan() & 7; + let mut king_square = board.pieces[color_index][KING].bit_scan() & 0x3f; + if color_index == BLACK { + king_square = (1u64 << king_square).swap_bytes().bit_scan(); + } + for phase in ALL_PHASES { let mut score = 0; for piece_index in ALL_PIECES { let mut pieces_bb = board.pieces[color_index][piece_index]; while pieces_bb != 0 { let square_bb = pieces_bb.get_lsb(); - let square = square_bb.bit_scan(); + let mut square = square_bb.bit_scan(); pieces_bb = pieces_bb.pop_lsb(); - score += board.evaluation_parameters.get_pst_value(color_index, piece_index, king_file, phase, square); + if color_index == BLACK { + square = (1u64 << square).swap_bytes().bit_scan(); + } + + score += board.evaluation_parameters.get_pst_value(piece_index, king_square, phase, square); } } @@ -46,9 +68,9 @@ pub fn recalculate_incremental_values(board: &mut Board) { /// Gets coefficients of piece-square table for `piece` on `board` and assigns indexes starting from `index`. #[cfg(feature = "dev")] pub fn get_coefficients(board: &Board, piece: usize, index: &mut u16, coefficients: &mut Vec, indices: &mut Vec) { - for king_file in ALL_FILES { - let valid_for_white = king_file == board.pieces[WHITE][KING].bit_scan() & 7; - let valid_for_black = king_file == board.pieces[BLACK][KING].bit_scan() & 7; + for bucket in 0..KING_BUCKETS_COUNT { + let valid_for_white = bucket == KING_BUCKETS[63 - board.pieces[WHITE][KING].bit_scan()]; + let valid_for_black = bucket == KING_BUCKETS[63 - board.pieces[BLACK][KING].bit_scan()]; for game_phase in ALL_PHASES { for square in ALL_SQUARES { diff --git a/src/evaluation/pst/pawn.rs b/src/evaluation/pst/pawn.rs index ce63e23..2011060 100644 --- a/src/evaluation/pst/pawn.rs +++ b/src/evaluation/pst/pawn.rs @@ -6,7 +6,7 @@ use super::*; impl EvaluationParameters { #[rustfmt::skip] - pub const PAWN_PST_PATTERN: [[[i16; 64]; 2]; 8] = + pub const PAWN_PST_PATTERN: [[[i16; 64]; 2]; KING_BUCKETS_COUNT] = [ [ [ diff --git a/src/evaluation/pst/queen.rs b/src/evaluation/pst/queen.rs index adf198a..3c21223 100644 --- a/src/evaluation/pst/queen.rs +++ b/src/evaluation/pst/queen.rs @@ -6,7 +6,7 @@ use super::*; impl EvaluationParameters { #[rustfmt::skip] - pub const QUEEN_PST_PATTERN: [[[i16; 64]; 2]; 8] = + pub const QUEEN_PST_PATTERN: [[[i16; 64]; 2]; KING_BUCKETS_COUNT] = [ [ [ diff --git a/src/evaluation/pst/rook.rs b/src/evaluation/pst/rook.rs index d1be27d..50557c5 100644 --- a/src/evaluation/pst/rook.rs +++ b/src/evaluation/pst/rook.rs @@ -6,7 +6,7 @@ use super::*; impl EvaluationParameters { #[rustfmt::skip] - pub const ROOK_PST_PATTERN: [[[i16; 64]; 2]; 8] = + pub const ROOK_PST_PATTERN: [[[i16; 64]; 2]; KING_BUCKETS_COUNT] = [ [ [ diff --git a/src/evaluation/safety.rs b/src/evaluation/safety.rs index 183df0c..3f0b7e7 100644 --- a/src/evaluation/safety.rs +++ b/src/evaluation/safety.rs @@ -1,9 +1,6 @@ use super::*; use crate::state::representation::Board; -#[cfg(feature = "dev")] -use pst::*; - #[cfg(feature = "dev")] use crate::tuning::tuner::TunerCoefficient; diff --git a/src/state/representation.rs b/src/state/representation.rs index 72c5bc9..df14fd9 100644 --- a/src/state/representation.rs +++ b/src/state/representation.rs @@ -14,6 +14,7 @@ use crate::evaluation::material; use crate::evaluation::mobility; use crate::evaluation::pawns; use crate::evaluation::pst; +use crate::evaluation::pst::*; use crate::evaluation::safety; use crate::evaluation::EvaluationParameters; use crate::evaluation::*; @@ -350,7 +351,12 @@ impl Board { self.pawn_hash ^= self.zobrist.get_piece_hash(color, KING, from); self.pawn_hash ^= self.zobrist.get_piece_hash(color, KING, to); - pst::recalculate_incremental_values(self); + let from = if color == WHITE { from } else { (1u64 << from).swap_bytes().bit_scan() }; + let to = if color == WHITE { to } else { (1u64 << to).swap_bytes().bit_scan() }; + + if KING_BUCKETS[from] != KING_BUCKETS[to] { + pst::recalculate_incremental_values(self); + } } else if piece == ROOK { match color { WHITE => match from { @@ -688,7 +694,7 @@ impl Board { } /// Adds `piece` on the `square` with the specified `color`, also updates occupancy and incremental values. - pub fn add_piece(&mut self, color: usize, piece: usize, square: usize) { + pub fn add_piece(&mut self, color: usize, piece: usize, mut square: usize) { self.pieces[color][piece] |= 1u64 << square; self.occupancy[color] |= 1u64 << square; self.piece_table[square] = piece as u8; @@ -696,14 +702,20 @@ impl Board { self.game_phase += PIECE_PHASE_VALUE[piece]; if !UNDO { - let king_file = self.pieces[color][KING].bit_scan() & 7; - self.pst_scores[color][OPENING] += self.evaluation_parameters.get_pst_value(color, piece, king_file, OPENING, square); - self.pst_scores[color][ENDING] += self.evaluation_parameters.get_pst_value(color, piece, king_file, ENDING, square); + let mut king_square = self.pieces[color][KING].bit_scan() & 0x3f; + + if color == BLACK { + king_square = (1u64 << king_square).swap_bytes().bit_scan(); + square = (1u64 << square).swap_bytes().bit_scan(); + } + + self.pst_scores[color][OPENING] += self.evaluation_parameters.get_pst_value(piece, king_square, OPENING, square); + self.pst_scores[color][ENDING] += self.evaluation_parameters.get_pst_value(piece, king_square, ENDING, square); } } /// Removes `piece` on the `square` with the specified `color`, also updates occupancy and incremental values. - pub fn remove_piece(&mut self, color: usize, piece: usize, square: usize) { + pub fn remove_piece(&mut self, color: usize, piece: usize, mut square: usize) { self.pieces[color][piece] &= !(1u64 << square); self.occupancy[color] &= !(1u64 << square); self.piece_table[square] = u8::MAX; @@ -711,14 +723,20 @@ impl Board { self.game_phase -= PIECE_PHASE_VALUE[piece]; if !UNDO { - let king_file = self.pieces[color][KING].bit_scan() & 7; - self.pst_scores[color][OPENING] -= self.evaluation_parameters.get_pst_value(color, piece, king_file, OPENING, square); - self.pst_scores[color][ENDING] -= self.evaluation_parameters.get_pst_value(color, piece, king_file, ENDING, square); + let mut king_square = self.pieces[color][KING].bit_scan() & 0x3f; + + if color == BLACK { + king_square = (1u64 << king_square).swap_bytes().bit_scan(); + square = (1u64 << square).swap_bytes().bit_scan(); + } + + self.pst_scores[color][OPENING] -= self.evaluation_parameters.get_pst_value(piece, king_square, OPENING, square); + self.pst_scores[color][ENDING] -= self.evaluation_parameters.get_pst_value(piece, king_square, ENDING, square); } } /// Moves `piece` from the square specified by `from` to the square specified by `to` with the specified `color`, also updates occupancy and incremental values. - pub fn move_piece(&mut self, color: usize, piece: usize, from: usize, to: usize) { + pub fn move_piece(&mut self, color: usize, piece: usize, mut from: usize, mut to: usize) { self.pieces[color][piece] ^= (1u64 << from) | (1u64 << to); self.occupancy[color] ^= (1u64 << from) | (1u64 << to); @@ -726,11 +744,18 @@ impl Board { self.piece_table[from] = u8::MAX; if !UNDO { - let king_file = self.pieces[color][KING].bit_scan() & 7; - self.pst_scores[color][OPENING] -= self.evaluation_parameters.get_pst_value(color, piece, king_file, OPENING, from); - self.pst_scores[color][ENDING] -= self.evaluation_parameters.get_pst_value(color, piece, king_file, ENDING, from); - self.pst_scores[color][OPENING] += self.evaluation_parameters.get_pst_value(color, piece, king_file, OPENING, to); - self.pst_scores[color][ENDING] += self.evaluation_parameters.get_pst_value(color, piece, king_file, ENDING, to); + let mut king_square = self.pieces[color][KING].bit_scan() & 0x3f; + + if color == BLACK { + king_square = (1u64 << king_square).swap_bytes().bit_scan(); + from = (1u64 << from).swap_bytes().bit_scan(); + to = (1u64 << to).swap_bytes().bit_scan(); + } + + self.pst_scores[color][OPENING] -= self.evaluation_parameters.get_pst_value(piece, king_square, OPENING, from); + self.pst_scores[color][ENDING] -= self.evaluation_parameters.get_pst_value(piece, king_square, ENDING, from); + self.pst_scores[color][OPENING] += self.evaluation_parameters.get_pst_value(piece, king_square, OPENING, to); + self.pst_scores[color][ENDING] += self.evaluation_parameters.get_pst_value(piece, king_square, ENDING, to); } } diff --git a/src/tuning/tuner.rs b/src/tuning/tuner.rs index c5c91ec..b542ba6 100644 --- a/src/tuning/tuner.rs +++ b/src/tuning/tuner.rs @@ -3,6 +3,7 @@ use crate::evaluation::material; use crate::evaluation::mobility; use crate::evaluation::pawns; use crate::evaluation::pst; +use crate::evaluation::pst::*; use crate::evaluation::safety; use crate::evaluation::EvaluationParameters; use crate::evaluation::*; @@ -448,39 +449,39 @@ fn load_values(random_values: bool) -> Vec { parameters.append(&mut evaluation_parameters.king_attacked_squares_ending.iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); let pawn_pst = &EvaluationParameters::PAWN_PST_PATTERN; - for king_file in ALL_FILES { - parameters.append(&mut pawn_pst[king_file][0].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); - parameters.append(&mut pawn_pst[king_file][1].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); + for king_bucket in 0..KING_BUCKETS_COUNT { + parameters.append(&mut pawn_pst[king_bucket][0].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); + parameters.append(&mut pawn_pst[king_bucket][1].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); } let knight_pst = &EvaluationParameters::KNIGHT_PST_PATTERN; - for king_file in ALL_FILES { - parameters.append(&mut knight_pst[king_file][0].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); - parameters.append(&mut knight_pst[king_file][1].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); + for king_bucket in 0..KING_BUCKETS_COUNT { + parameters.append(&mut knight_pst[king_bucket][0].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); + parameters.append(&mut knight_pst[king_bucket][1].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); } let bishop_pst = &EvaluationParameters::BISHOP_PST_PATTERN; - for king_file in ALL_FILES { - parameters.append(&mut bishop_pst[king_file][0].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); - parameters.append(&mut bishop_pst[king_file][1].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); + for king_bucket in 0..KING_BUCKETS_COUNT { + parameters.append(&mut bishop_pst[king_bucket][0].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); + parameters.append(&mut bishop_pst[king_bucket][1].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); } let rook_pst = &EvaluationParameters::ROOK_PST_PATTERN; - for king_file in ALL_FILES { - parameters.append(&mut rook_pst[king_file][0].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); - parameters.append(&mut rook_pst[king_file][1].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); + for king_bucket in 0..KING_BUCKETS_COUNT { + parameters.append(&mut rook_pst[king_bucket][0].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); + parameters.append(&mut rook_pst[king_bucket][1].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); } let queen_pst = &EvaluationParameters::QUEEN_PST_PATTERN; - for king_file in ALL_FILES { - parameters.append(&mut queen_pst[king_file][0].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); - parameters.append(&mut queen_pst[king_file][1].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); + for king_bucket in 0..KING_BUCKETS_COUNT { + parameters.append(&mut queen_pst[king_bucket][0].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); + parameters.append(&mut queen_pst[king_bucket][1].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); } let king_pst = &EvaluationParameters::KING_PST_PATTERN; - for king_file in ALL_FILES { - parameters.append(&mut king_pst[king_file][0].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); - parameters.append(&mut king_pst[king_file][1].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); + for king_bucket in 0..KING_BUCKETS_COUNT { + parameters.append(&mut king_pst[king_bucket][0].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); + parameters.append(&mut king_pst[king_bucket][1].iter().map(|v| TunerParameter::new(*v, -999, -40, 40, 999)).collect()); } if random_values { @@ -560,10 +561,10 @@ fn write_piece_square_table(weights: &mut Iter, output_directory: &str, bes output.push('\n'); output.push_str("impl EvaluationParameters {\n"); output.push_str(" #[rustfmt::skip]\n"); - output.push_str(&format!(" pub const {}_PST_PATTERN: [[[i16; 64]; 2]; 8] =\n", name)); + output.push_str(&format!(" pub const {}_PST_PATTERN: [[[i16; 64]; 2]; KING_BUCKETS_COUNT] =\n", name)); output.push_str(" [\n"); - for _ in ALL_FILES { + for _ in 0..KING_BUCKETS_COUNT { output.push_str(" [\n"); output.push_str(" [\n"); output.push_str(get_piece_square_table(weights).as_str());