From 746e3bf17463a377b6c54b291ebef9a736d6ceb7 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Thu, 25 Jan 2024 11:24:36 +0100 Subject: chore: autoformat code Use #[rustfmt:skip] to preserve aligned blocks --- src/grossmeister/evaluation.rs | 276 ++++++++++++++++++++++++++--------------- 1 file changed, 173 insertions(+), 103 deletions(-) (limited to 'src/grossmeister/evaluation.rs') diff --git a/src/grossmeister/evaluation.rs b/src/grossmeister/evaluation.rs index 1b57f5a..8deb929 100644 --- a/src/grossmeister/evaluation.rs +++ b/src/grossmeister/evaluation.rs @@ -1,12 +1,17 @@ use std::f32::INFINITY; -use crate::{board::{piece::Piece, color::Color, CastlingSide}, bitboard::{Bitboard, BitboardFns}, square::Square}; +use crate::{ + bitboard::{Bitboard, BitboardFns}, + board::{color::Color, piece::Piece, CastlingSide}, + square::Square, +}; use super::Grossmeister; /// Score in pawns (not centipawns) pub type Score = f32; +#[rustfmt::skip] const PAWN_BONUS: [Score; 64] = [ // A B C D E F G H 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, @@ -19,6 +24,7 @@ const PAWN_BONUS: [Score; 64] = [ 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00 ]; +#[rustfmt::skip] const PAWN_BONUS_PASSER_ENDGAME: [Score; 64] = [ // A B C D E F G H 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, @@ -31,6 +37,7 @@ const PAWN_BONUS_PASSER_ENDGAME: [Score; 64] = [ 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, ]; +#[rustfmt::skip] const KNIGHT_BONUS: [Score; 64] = [ // A B C D E F G H -0.50, -0.40, -0.30, -0.30, -0.30, -0.30, -0.40, -0.50, @@ -43,6 +50,7 @@ const KNIGHT_BONUS: [Score; 64] = [ -0.50, -0.40, -0.30, -0.30, -0.30, -0.30, -0.40, -0.50, ]; +#[rustfmt::skip] const BISHOP_BONUS: [Score; 64] = [ // A B C D E F G H -0.20, -0.10, -0.10, -0.10, -0.10, -0.10, -0.10, -0.20, @@ -55,6 +63,7 @@ const BISHOP_BONUS: [Score; 64] = [ -0.20, -0.10, -0.10, -0.10, -0.10, -0.10, -0.10, -0.20, ]; +#[rustfmt::skip] const ROOK_BONUS: [Score; 64] = [ // A B C D E F G H 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, @@ -67,6 +76,7 @@ const ROOK_BONUS: [Score; 64] = [ 0.00, 0.00, 0.00, 0.05, 0.05, 0.00, 0.00, 0.00 ]; +#[rustfmt::skip] const QUEEN_BONUS: [Score; 64] = [ // A B C D E F G H -0.20, -0.10, -0.10, -0.05, -0.05, -0.10, -0.10, -0.20, @@ -79,6 +89,7 @@ const QUEEN_BONUS: [Score; 64] = [ -0.20, -0.10, -0.10, -0.05, -0.05, -0.10, -0.10, -0.20 ]; +#[rustfmt::skip] const KING_BONUS: [Score; 64] = [ // A B C D E F G H -0.30, -0.40, -0.40, -0.50, -0.50, -0.40, -0.40, -0.30, @@ -91,6 +102,7 @@ const KING_BONUS: [Score; 64] = [ 0.20, 0.10, 0.30, -0.20, 0.00, 0.10, 0.30, 0.20 ]; +#[rustfmt::skip] const KING_BONUS_ENGAME: [Score; 64] = [ // A B C D E F G H -0.50, -0.40, -0.30, -0.20, -0.20, -0.30, -0.40, -0.50, @@ -149,39 +161,50 @@ impl Grossmeister { /// Compute total bonus for well-positioned pieces /// according to Piece-Square Tables pub fn pst_bonus(&self, color: Color, is_endgame: bool) -> f32 { - self.board.pieces_by_color(color).iter().enumerate().fold(0., |total, (piece_index, bitboard)| { - let pst = match Piece::from(piece_index).without_color() { - Piece::Pawn => if is_endgame && (bitboard & self.passer_mask(color) > 0) { - PAWN_BONUS_PASSER_ENDGAME - } else { - PAWN_BONUS - } - Piece::Knight => KNIGHT_BONUS, - Piece::Bishop => BISHOP_BONUS, - Piece::Rook => ROOK_BONUS, - Piece::Queen => QUEEN_BONUS, - Piece::King => if is_endgame { - KING_BONUS_ENGAME - } else { - KING_BONUS - } - _ => panic!("Unreachable") - }; - total + bitboard.serialize().fold(0., |acc, square| { - let pst_index = match color { - Color::White => square.mirror(), - Color::Black => square, - } as usize; - acc + pst[pst_index] - }) - }) + self.board.pieces_by_color(color).iter().enumerate().fold( + 0., + |total, (piece_index, bitboard)| { + let pst = match Piece::from(piece_index).without_color() { + Piece::Pawn => { + if is_endgame && (bitboard & self.passer_mask(color) > 0) { + PAWN_BONUS_PASSER_ENDGAME + } else { + PAWN_BONUS + } + } + Piece::Knight => KNIGHT_BONUS, + Piece::Bishop => BISHOP_BONUS, + Piece::Rook => ROOK_BONUS, + Piece::Queen => QUEEN_BONUS, + Piece::King => { + if is_endgame { + KING_BONUS_ENGAME + } else { + KING_BONUS + } + } + _ => panic!("Unreachable"), + }; + total + + bitboard.serialize().fold(0., |acc, square| { + let pst_index = match color { + Color::White => square.mirror(), + Color::Black => square, + } as usize; + acc + pst[pst_index] + }) + }, + ) } /// 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 - }) + 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 @@ -193,24 +216,27 @@ impl Grossmeister { 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 + 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() - }) + 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) -> Score { let color = self.board.color(); @@ -220,7 +246,7 @@ impl Grossmeister { let loseable = self.board.is_theoretically_winnable(opponent_color); if !winnable && !loseable { - return 0.0 + return 0.0; } let material_advantage = self.material(color) - self.material(opponent_color); @@ -229,22 +255,21 @@ impl Grossmeister { let pawn_islands_advantage = self.pawn_islands(opponent_color) - self.pawn_islands(color); // Middlegame eval, assumming all pieces are on the Board - let middlegame_eval = - mobility_advantage * 0.05 + - pawn_shield_advantage * 0.20 + - pawn_islands_advantage * 0.10 + - (self.pst_bonus(color, false) - self.pst_bonus(opponent_color, false)); + let middlegame_eval = mobility_advantage * 0.05 + + pawn_shield_advantage * 0.20 + + pawn_islands_advantage * 0.10 + + (self.pst_bonus(color, false) - self.pst_bonus(opponent_color, false)); // Engame eval, assuming no pieces are left on the Board (only kings and pawns) - let endgame_eval = - mobility_advantage * 0.03 + - pawn_shield_advantage * 0.05 + - pawn_islands_advantage * 0.15 + - (self.pst_bonus(color, true) - self.pst_bonus(opponent_color, true)); + let endgame_eval = mobility_advantage * 0.03 + + pawn_shield_advantage * 0.05 + + pawn_islands_advantage * 0.15 + + (self.pst_bonus(color, true) - self.pst_bonus(opponent_color, true)); // Interpolate evalutaion based on amount of pieces to remove discontinuity let phase = self.phase(); - let tapered_eval = (middlegame_eval * phase as f32 + endgame_eval * (240 - phase) as f32) / 240.; + let tapered_eval = + (middlegame_eval * phase as f32 + endgame_eval * (240 - phase) as f32) / 240.; let eval = (material_advantage + tapered_eval) .min(if winnable { INFINITY } else { 0.0 }) // Can not score > 0 if not winnable @@ -279,7 +304,9 @@ impl Grossmeister { let ep_bitboard = match self.board.ep_target { Some(square) => { let rank = square.rank(); - if (rank == 2 && color == Color::Black) || (rank == 5 && color == Color::White) { + if (rank == 2 && color == Color::Black) + || (rank == 5 && color == Color::White) + { square.to_bitboard() } else { 0 @@ -287,20 +314,30 @@ impl Grossmeister { } None => 0, }; - mobility += (self.board.attacks.pawn[color as usize][source as usize] & (opponent_occupancy | ep_bitboard)).pop_count() as f32; - mobility += (self.board.attacks.pawn_pushes[color as usize][source as usize] & empty).pop_count() as f32; + mobility += (self.board.attacks.pawn[color as usize][source as usize] + & (opponent_occupancy | ep_bitboard)) + .pop_count() as f32; + mobility += (self.board.attacks.pawn_pushes[color as usize] + [source as usize] + & empty) + .pop_count() as f32; } let able_to_double_push_mask = match color { Color::White => empty >> 8, Color::Black => empty << 8, }; for source in (*piece & able_to_double_push_mask).serialize() { - mobility += (self.board.attacks.pawn_double_pushes[color as usize][source as usize] & empty).pop_count() as f32; + mobility += (self.board.attacks.pawn_double_pushes[color as usize] + [source as usize] + & empty) + .pop_count() as f32; } } Piece::King => { for source in piece.serialize() { - mobility += (self.board.attacks.king[source as usize] & (empty | opponent_occupancy)).pop_count() as f32; + mobility += (self.board.attacks.king[source as usize] + & (empty | opponent_occupancy)) + .pop_count() as f32; // Castling let king_home_position = match color { @@ -308,56 +345,79 @@ impl Grossmeister { Color::Black => Square::E8, }; if *piece == king_home_position.to_bitboard() { - for rook_square in player_pieces[Piece::Rook as usize] - .serialize() - .filter(|rook_square| rook_square.rank() == king_home_position.rank()) - { - match rook_square.file() { - 0 => { - let castle_line = [ - king_home_position.west_one(), - king_home_position.west_one().west_one(), - ]; - - let all_empty = castle_line.iter().all(|square| empty & square.to_bitboard() > 0); - let any_checks = castle_line.iter().any(|square| self.board.is_square_attacked(*square, color.flip())); - - if all_empty && !any_checks && self.board.castling_rights[color as usize][CastlingSide::Queen as usize] { - mobility += 1.; - } - }, - 7 => { - let castle_line = [ - king_home_position.east_one(), - king_home_position.east_one().east_one(), - ]; - - let all_empty = castle_line.iter().all(|square| empty & square.to_bitboard() > 0); - let any_checks = castle_line.iter().any(|square| self.board.is_square_attacked(*square, color.flip())); - - if all_empty && !any_checks && self.board.castling_rights[color as usize][CastlingSide::King as usize] { - mobility += 1.; - } - }, - _ => {}, + for rook_square in + player_pieces[Piece::Rook as usize].serialize().filter( + |rook_square| rook_square.rank() == king_home_position.rank(), + ) + { + match rook_square.file() { + 0 => { + let castle_line = [ + king_home_position.west_one(), + king_home_position.west_one().west_one(), + ]; + + let all_empty = castle_line + .iter() + .all(|square| empty & square.to_bitboard() > 0); + let any_checks = castle_line.iter().any(|square| { + self.board.is_square_attacked(*square, color.flip()) + }); + + if all_empty + && !any_checks + && self.board.castling_rights[color as usize] + [CastlingSide::Queen as usize] + { + mobility += 1.; + } + } + 7 => { + let castle_line = [ + king_home_position.east_one(), + king_home_position.east_one().east_one(), + ]; + + let all_empty = castle_line + .iter() + .all(|square| empty & square.to_bitboard() > 0); + let any_checks = castle_line.iter().any(|square| { + self.board.is_square_attacked(*square, color.flip()) + }); + + if all_empty + && !any_checks + && self.board.castling_rights[color as usize] + [CastlingSide::King as usize] + { + mobility += 1.; + } } + _ => {} } + } } } } Piece::Knight => { for source in piece.serialize() { - mobility += (self.board.attacks.knight[source as usize] & (empty | opponent_occupancy)).pop_count() as f32; + mobility += (self.board.attacks.knight[source as usize] + & (empty | opponent_occupancy)) + .pop_count() as f32; } } Piece::Bishop => { for source in piece.serialize() { - mobility += (self.board.attacks.bishop(self.board.occupancy, source) & (empty | opponent_occupancy)).pop_count() as f32; + mobility += (self.board.attacks.bishop(self.board.occupancy, source) + & (empty | opponent_occupancy)) + .pop_count() as f32; } } Piece::Rook => { for source in piece.serialize() { - mobility += (self.board.attacks.rook(self.board.occupancy, source) & (empty | opponent_occupancy)).pop_count() as f32; + mobility += (self.board.attacks.rook(self.board.occupancy, source) + & (empty | opponent_occupancy)) + .pop_count() as f32; } } Piece::Queen => { @@ -372,7 +432,10 @@ impl Grossmeister { #[cfg(test)] mod tests { - use crate::{board::{Board, io::IO}, moves::{Move, MoveKind}}; + use crate::{ + board::{io::IO, Board}, + moves::{Move, MoveKind}, + }; use super::*; @@ -407,7 +470,6 @@ mod tests { let board = Board::new(); let gm = Grossmeister::new(board); assert_eq!(gm.material(Color::Black), gm.material(Color::White)); - } #[test] @@ -421,7 +483,11 @@ mod tests { fn king_tropism() { let board = Board::new(); let mut gm = Grossmeister::new(board); - gm.board.make_move(Move { source: Square::D1, target: Square::F5, kind: MoveKind::Quiet }); + gm.board.make_move(Move { + source: Square::D1, + target: Square::F5, + kind: MoveKind::Quiet, + }); let score = gm.evaluate(); gm.board.print(); println!("Score {}", score); @@ -482,7 +548,8 @@ mod tests { #[test] fn discourage_edge_knights() { let score1 = { - let fen = String::from("r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3"); + let fen = + String::from("r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3"); let board = Board::from_FEN(fen); let gm = Grossmeister::new(board); let score = gm.evaluate(); @@ -492,7 +559,8 @@ mod tests { }; let score2 = { - let fen = String::from("r1bqkbnr/pppp1ppp/2n5/4p3/4P3/7N/PPPP1PPP/RNBQKB1R w KQkq - 2 3"); + let fen = + String::from("r1bqkbnr/pppp1ppp/2n5/4p3/4P3/7N/PPPP1PPP/RNBQKB1R w KQkq - 2 3"); let board = Board::from_FEN(fen); let gm = Grossmeister::new(board); let score = gm.evaluate(); @@ -507,7 +575,8 @@ mod tests { #[test] fn mirrored_evaluation() { let score1 = { - let fen = String::from("r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1"); + let fen = + String::from("r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1"); let board = Board::from_FEN(fen); let gm = Grossmeister::new(board); let score = gm.evaluate(); @@ -517,7 +586,8 @@ mod tests { }; let score2 = { - let fen = String::from("r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1 "); + let fen = + String::from("r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1 "); let board = Board::from_FEN(fen); let gm = Grossmeister::new(board); let score = gm.evaluate(); -- cgit v1.2.3