use std::ops::{Add, AddAssign};
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)]
pub struct Reward(f64);
impl Reward {
pub const WIN: Self = Self(1.0);
pub const LOSS: Self = Self(-1.0);
pub const DRAW: Self = Self(0.0);
pub fn new(value: f64) -> Self {
Self(value)
}
pub fn value(self) -> f64 {
self.0
}
}
impl Default for Reward {
fn default() -> Self {
Self::DRAW
}
}
impl Add for Reward {
type Output = Self;
fn add(self, other: Self) -> Self {
Self(self.0 + other.0)
}
}
impl AddAssign for Reward {
fn add_assign(&mut self, other: Self) {
self.0 += other.0;
}
}
impl From<f64> for Reward {
fn from(value: f64) -> Self {
Self(value)
}
}
impl std::fmt::Display for Reward {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reward_arithmetic() {
let a = Reward::new(0.5);
let b = Reward::new(0.3);
let sum = a + b;
assert!((sum.value() - 0.8).abs() < f64::EPSILON);
}
#[test]
fn reward_add_assign() {
let mut r = Reward::DRAW;
r += Reward::WIN;
assert!((r.value() - 1.0).abs() < f64::EPSILON);
}
#[test]
fn reward_constants() {
assert!((Reward::WIN.value() - 1.0).abs() < f64::EPSILON);
assert!((Reward::LOSS.value() + 1.0).abs() < f64::EPSILON);
assert!(Reward::DRAW.value().abs() < f64::EPSILON);
}
#[test]
fn reward_default() {
assert_eq!(Reward::default(), Reward::DRAW);
}
#[test]
fn reward_from_f64() {
let r: Reward = 0.42.into();
assert!((r.value() - 0.42).abs() < f64::EPSILON);
}
}