aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreug-vs <eugene@eug-vs.xyz>2023-01-27 18:06:12 +0300
committereug-vs <eugene@eug-vs.xyz>2023-01-27 18:06:12 +0300
commit68536a7c80a5c8ce3af0969e7840198f85b3aa78 (patch)
treecf496e52ce80ab18bea9869190c76e7c91fd620f
parentfb142238613f0a2e0a581807d41089ac63793694 (diff)
downloadchessnost-68536a7c80a5c8ce3af0969e7840198f85b3aa78.tar.gz
feat: calculate pawn structure penalty
-rw-r--r--src/board/engine.rs42
1 files changed, 41 insertions, 1 deletions
diff --git a/src/board/engine.rs b/src/board/engine.rs
index 18fb731..2ff3aed 100644
--- a/src/board/engine.rs
+++ b/src/board/engine.rs
@@ -3,6 +3,8 @@ use crate::{bitboard::pop_count, board::*};
use super::ttable::{NodeType, TranspositionTableItem};
+static A_FILE: Bitboard = 0x0101010101010101;
+
#[derive(Debug, Default, PartialEq)]
pub struct PerftResult {
leaf_nodes: u64,
@@ -116,6 +118,42 @@ impl Board {
eval
}
+ /// 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.pieces[PieceType::Pawn as usize],
+ Color::Black => self.pieces[PieceType::PawnBlack as usize],
+ };
+
+ for file in 0..8 {
+ let file_mask = A_FILE << file;
+ let pawns_on_file = pop_count(pawns & file_mask) 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.occupancy >> 8,
+ Color::Black => self.occupancy << 8,
+ };
+ result += pop_count(pawns & blocked_mask) as f32;
+
+ result
+ }
+
/// Evaluate a position relative to the current player
pub fn evaluate(&self, precomputed_mobility: Option<f32>) -> f32 {
let opponent_mobility = self.mobility(self.color().flip());
@@ -127,7 +165,9 @@ impl Board {
let material_advantage = self.material_advantage();
- material_advantage + 0.1 * mobility_advantage
+ let pawn_structure_penalty = self.pawn_structure_penalty(self.color()) - self.pawn_structure_penalty(self.color().flip());
+
+ material_advantage + 0.1 * mobility_advantage - 0.5 * pawn_structure_penalty
}
/// Evaluate move for move ordering, prioritizing efficient captures