diff --git a/core/src/colors.rs b/core/src/colors.rs index 53e2c1e..e1255b7 100644 --- a/core/src/colors.rs +++ b/core/src/colors.rs @@ -1,6 +1,6 @@ // Eryn Wells -use crate::{Direction, score::ScoreInner}; +use crate::{Direction, score}; use std::fmt; use thiserror::Error; @@ -59,7 +59,7 @@ impl Color { } #[must_use] - pub const fn score_factor(self) -> ScoreInner { + pub const fn score_factor(self) -> score::Value { match self { Color::White => 1, Color::Black => -1, diff --git a/core/src/score.rs b/core/src/score.rs index a7f24cd..2dfd7c9 100644 --- a/core/src/score.rs +++ b/core/src/score.rs @@ -5,22 +5,53 @@ use std::{ ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign}, }; -pub(crate) type ScoreInner = i32; +pub(crate) type Value = i32; /// A score for a position in centipawns. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] -pub struct Score(ScoreInner); +pub struct Score(Value); impl Score { - #[must_use] - pub const fn zero() -> Self { - Self(0) - } + pub const ZERO: Score = Score(0); + + /// The minimum possible value of a score. Notably, this is *not* the + /// minimum value for the inner integer value so negation works correctly. + /// This property is important during search, which relies on being able to + /// negate "infinity". + /// + /// ## Examples + /// + /// ``` + /// use chessfriend_core::score::Score; + /// assert_eq!(!Score::MIN, Score::MAX); + /// ``` + /// + pub const MIN: Score = Score(Value::MIN + 1); + + /// The maximum possible value of a score. + pub const MAX: Score = Score(Value::MAX); + + const CENTIPAWNS_PER_POINT: f32 = 100.0; #[must_use] - pub const fn new(value: ScoreInner) -> Self { + pub const fn new(value: Value) -> Self { Self(value) } + + /// Returns `true` if this [`Score`] is zero. + /// + /// ## Examples + /// + /// ``` + /// use chessfriend_core::score::Score; + /// assert!(Score::ZERO.is_zero()); + /// assert!(Score::new(0).is_zero()); + /// ``` + /// + #[must_use] + pub const fn is_zero(&self) -> bool { + self.0 == 0 + } } impl Add for Score { @@ -51,15 +82,15 @@ impl SubAssign for Score { } } -impl Mul for Score { - type Output = Score; +impl Mul for Score { + type Output = Self; - fn mul(self, rhs: ScoreInner) -> Self::Output { + fn mul(self, rhs: Value) -> Self::Output { Score(self.0 * rhs) } } -impl Mul for ScoreInner { +impl Mul for Value { type Output = Score; fn mul(self, rhs: Score) -> Self::Output { @@ -67,8 +98,16 @@ impl Mul for ScoreInner { } } -impl From for Score { - fn from(value: ScoreInner) -> Self { +impl Neg for Score { + type Output = Self; + + fn neg(self) -> Self::Output { + Score(-self.0) + } +} + +impl From for Score { + fn from(value: Value) -> Self { Score(value) } } diff --git a/position/src/evaluation.rs b/position/src/evaluation.rs index 883398b..b776777 100644 --- a/position/src/evaluation.rs +++ b/position/src/evaluation.rs @@ -19,10 +19,10 @@ impl Evaluator { fn material_balance(board: &Board, color: Color) -> Score { let other_color = color.other(); - Shape::into_iter().fold(Score::zero(), |acc, shape| { + Shape::into_iter().fold(Score::ZERO, |acc, shape| { let (active_pieces, other_pieces) = ( - board.count_piece(&Piece::new(color, shape)) as i32, - board.count_piece(&Piece::new(other_color, shape)) as i32, + i32::from(board.count_piece(&Piece::new(color, shape))), + i32::from(board.count_piece(&Piece::new(other_color, shape))), ); let factor = shape.score() * (active_pieces - other_pieces);