diff options
| -rw-r--r-- | src/grossmeister/evaluation.rs | 141 | 
1 files changed, 45 insertions, 96 deletions
| diff --git a/src/grossmeister/evaluation.rs b/src/grossmeister/evaluation.rs index 29c1128..dafc33a 100644 --- a/src/grossmeister/evaluation.rs +++ b/src/grossmeister/evaluation.rs @@ -101,11 +101,11 @@ const KING_BONUS_ENGAME: [f32; 64] = [  ];  impl Grossmeister { -    pub fn passer_mask(&self, color: Color) -> Bitboard { +    pub fn passer_count(&self, color: Color) -> f32 {          let black_pawns = self.board.piece_sets[Piece::PawnBlack as usize];          let white_pawns = self.board.piece_sets[Piece::Pawn as usize]; -        match color { +        let mask = match color {              Color::Black => {                  let mut front_fill = white_pawns.nort_fill().nort_one();                  front_fill |= front_fill.east_one() | front_fill.west_one(); @@ -116,7 +116,12 @@ impl Grossmeister {                  front_fill |= front_fill.east_one() | front_fill.west_one();                  white_pawns & !front_fill              } -        } +        }; + +        (mask & match color { +            Color::White => white_pawns, +            Color::Black => black_pawns, +        }).pop_count() as f32      }      pub fn is_dead_position(&self) -> bool { @@ -171,32 +176,6 @@ impl Grossmeister {          islands_west_files.pop_count() as f32      } -    // Returns a value in [0, 240] representing how -    // much material is left in the game -    // Note: not related to actual material counting -    pub fn phase(&self) -> u8 { -        let knight_phase = 10; -        let bishop_phase = 10; -        let rook_phase = 20; -        let queen_phase = 40; - -        let total_phase = knight_phase*4 + bishop_phase*4 + rook_phase*4 + queen_phase*2; -         // If you change it, make sure to update denominator in interpolation -        debug_assert_eq!(total_phase, 240); - -        self.board.piece_sets.iter().enumerate().fold(0, |acc, (piece_index, &bitboard)| { -            acc + match Piece::from(piece_index).without_color() { -                Piece::King => 0, -                Piece::Pawn => 0, -                Piece::Knight => knight_phase, -                Piece::Bishop => bishop_phase, -                Piece::Rook => rook_phase, -                Piece::Queen => queen_phase, -                _ => panic!("Unreachable") -            } * bitboard.pop_count() -        }) -    } -      /// Compute total bonus for well-positioned pieces      /// according to Piece-Square Tables      pub fn pst_bonus(&self, color: Color, is_endgame: bool) -> f32 { @@ -228,6 +207,40 @@ impl Grossmeister {          })      } +    /// Count raw material of the given color +    pub fn material(&self, color: Color) -> f32 { +        self.board.pieces_by_color(color).iter().enumerate().fold(0., |acc, (piece_index, bitboard)| { +            acc + Piece::from(piece_index).static_eval() * bitboard.pop_count() as f32 +        }) +    } + +    // Returns a value in [0, 240] representing how +    // much material is left in the game +    // Note: not related to actual material counting +    pub fn phase(&self) -> u8 { +        let knight_phase = 10; +        let bishop_phase = 10; +        let rook_phase = 20; +        let queen_phase = 40; + +        let total_phase = knight_phase*4 + bishop_phase*4 + rook_phase*4 + queen_phase*2; +         // If you change it, make sure to update denominator in interpolation +        debug_assert_eq!(total_phase, 240); + +        self.board.piece_sets.iter().enumerate().fold(0, |acc, (piece_index, &bitboard)| { +            acc + match Piece::from(piece_index).without_color() { +                Piece::King => 0, +                Piece::Pawn => 0, +                Piece::Knight => knight_phase, +                Piece::Bishop => bishop_phase, +                Piece::Rook => rook_phase, +                Piece::Queen => queen_phase, +                _ => panic!("Unreachable") +            } * bitboard.pop_count() +        }) +    } + +      /// Evaluate a position relative to the current player      pub fn evaluate(&self) -> f32 {          if self.is_dead_position() { @@ -239,18 +252,21 @@ impl Grossmeister {          let material_advantage = self.material(color) - self.material(opponent_color);          let mobility_advantage = self.mobility(color) - self.mobility(opponent_color);          let pawn_shield_advantage = self.pawn_shield(color) - self.pawn_shield(opponent_color); +        let passer_advantage = self.passer_count(color) - self.passer_count(opponent_color);          let pawn_islands_advantage = self.pawn_islands(opponent_color) - self.pawn_islands(color);          let middlegame_eval =              mobility_advantage * 0.05 +              pawn_shield_advantage * 0.15 +              pawn_islands_advantage * 0.10 + +            passer_advantage * 0.05 +              (self.pst_bonus(color, false) - self.pst_bonus(opponent_color, false));          let endgame_eval =              mobility_advantage * 0.03 +              pawn_shield_advantage * 0.20 +              pawn_islands_advantage * 0.15 + +            passer_advantage * 0.10 +              (self.pst_bonus(color, true) - self.pst_bonus(opponent_color, true));          let phase = self.phase(); @@ -259,73 +275,6 @@ impl Grossmeister {          material_advantage + tapered_eval      } -    /// Count raw material of the given color -    pub fn material(&self, color: Color) -> f32 { -        self.board.pieces_by_color(color).iter().enumerate().fold(0., |acc, (piece_index, bitboard)| { -            acc + Piece::from(piece_index).static_eval() * bitboard.pop_count() as f32 -        }) -    } - -    /// Returns sum of the doubled, blocked and isolated pawns -    /// The greater result is, the worse is the pawn structure -    pub fn pawn_structure_penalty(&self, color: Color) -> f32 { -        let mut result = 0.0; - -        let pawns = match color { -            Color::White => self.board.piece_sets[Piece::Pawn as usize], -            Color::Black => self.board.piece_sets[Piece::PawnBlack as usize], -        }; - -        for file in 0..8 { -            let file_mask = A_FILE << file; -            let pawns_on_file = (pawns & file_mask).pop_count() as f32; - -            // Doubled pawns (-1 because one pawn on a file is ok) -            result += (pawns_on_file - 1.).max(0.0); - -            // Isolated pawns (no pawns on neighbor files) -            if [ -                A_FILE << (file - 1).max(0), // File to the left (if any) -                A_FILE << (file + 1).min(7), // File to the right (if any) -            ].iter().all(|file| file & pawns == 0) { -                result += pawns_on_file; -            } -        } - -        // Blocked pawns -        let blocked_mask = match color { -            Color::White => self.board.occupancy >> 8, -            Color::Black => self.board.occupancy << 8, -        }; -        result += (pawns & blocked_mask).pop_count() as f32; - -        result -    } - -    /// Returns the weighted sum of distances from attacking pieces to a king -    /// The higher this value, the safer is the king -    pub fn king_tropism(&self, color: Color) -> f32 { -        let mut result = 0.0; - -        let king_square = match color { -            Color::White => self.board.piece_sets[Piece::King as usize], -            Color::Black => self.board.piece_sets[Piece::KingBlack as usize], -        }.bitscan(); - -        for (piece_type, bitboard) in self.board.pieces_by_color(color.flip()).iter().enumerate() { -            if piece_type != Piece::King as usize && piece_type != Piece::Pawn as usize { -                for square in bitboard.serialize() { -                    let distance = -                        (king_square.rank() as f32 - square.rank() as f32).abs() + -                        (king_square.file() as f32 - square.file() as f32).abs(); - -                    result += distance / Piece::from(piece_type).static_eval(); -                } -            } -        } -        result -    } -      /// Count pseudo-legal moves without actually generating them      /// Also exclude all moves that put a piece under attack of a pawn - so called safe mobility      pub fn mobility(&self, color: Color) -> f32 { | 
