chessfriend/core/src/score.rs
2025-07-12 20:27:47 -07:00

126 lines
2.6 KiB
Rust

// Eryn Wells <eryn@erynwells.me>
use std::{
fmt,
ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign},
};
pub(crate) type Value = i32;
/// A score for a position in centipawns.
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Score(Value);
impl Score {
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);
pub(crate) const CENTIPAWNS_PER_POINT: f32 = 100.0;
#[must_use]
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 {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Score(self.0 + rhs.0)
}
}
impl AddAssign for Score {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
impl Sub for Score {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Score(self.0 - rhs.0)
}
}
impl SubAssign for Score {
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}
impl Mul<Value> for Score {
type Output = Self;
fn mul(self, rhs: Value) -> Self::Output {
Score(self.0 * rhs)
}
}
impl Mul<Score> for Value {
type Output = Score;
fn mul(self, rhs: Score) -> Self::Output {
Score(self * rhs.0)
}
}
impl Neg for Score {
type Output = Self;
fn neg(self) -> Self::Output {
Score(-self.0)
}
}
impl From<Value> for Score {
fn from(value: Value) -> Self {
Score(value)
}
}
impl fmt::Display for Score {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let value = self.0;
if *self == Self::MAX {
write!(f, "INF")
} else if *self == Self::MIN {
write!(f, "-INF")
} else {
write!(f, "{value}cp")
}
}
}