solverforge_core/score/
simple.rs

1use super::Score;
2use crate::SolverForgeError;
3use serde::{Deserialize, Serialize};
4use std::cmp::Ordering;
5use std::fmt;
6use std::ops::{Add, Neg, Sub};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9pub struct SimpleScore {
10    pub score: i64,
11}
12
13impl SimpleScore {
14    pub const ZERO: SimpleScore = SimpleScore { score: 0 };
15    pub const ONE: SimpleScore = SimpleScore { score: 1 };
16
17    pub fn of(score: i64) -> Self {
18        Self { score }
19    }
20
21    pub fn parse(text: &str) -> Result<Self, SolverForgeError> {
22        let text = text.trim();
23        let score = text
24            .parse::<i64>()
25            .map_err(|e| SolverForgeError::Serialization(format!("Invalid SimpleScore: {}", e)))?;
26        Ok(Self { score })
27    }
28}
29
30impl Score for SimpleScore {
31    fn is_feasible(&self) -> bool {
32        self.score >= 0
33    }
34
35    fn is_solution_initialized(&self) -> bool {
36        true
37    }
38
39    fn zero() -> Self {
40        Self::ZERO
41    }
42
43    fn negate(&self) -> Self {
44        Self { score: -self.score }
45    }
46
47    fn add(&self, other: &Self) -> Self {
48        Self {
49            score: self.score + other.score,
50        }
51    }
52
53    fn subtract(&self, other: &Self) -> Self {
54        Self {
55            score: self.score - other.score,
56        }
57    }
58}
59
60impl PartialOrd for SimpleScore {
61    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
62        Some(self.cmp(other))
63    }
64}
65
66impl Ord for SimpleScore {
67    fn cmp(&self, other: &Self) -> Ordering {
68        self.score.cmp(&other.score)
69    }
70}
71
72impl fmt::Display for SimpleScore {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        write!(f, "{}", self.score)
75    }
76}
77
78impl Add for SimpleScore {
79    type Output = Self;
80    fn add(self, other: Self) -> Self {
81        Score::add(&self, &other)
82    }
83}
84
85impl Sub for SimpleScore {
86    type Output = Self;
87    fn sub(self, other: Self) -> Self {
88        Score::subtract(&self, &other)
89    }
90}
91
92impl Neg for SimpleScore {
93    type Output = Self;
94    fn neg(self) -> Self {
95        Score::negate(&self)
96    }
97}
98
99impl Default for SimpleScore {
100    fn default() -> Self {
101        Self::ZERO
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn test_of() {
111        assert_eq!(SimpleScore::of(42).score, 42);
112        assert_eq!(SimpleScore::of(-10).score, -10);
113    }
114
115    #[test]
116    fn test_constants() {
117        assert_eq!(SimpleScore::ZERO.score, 0);
118        assert_eq!(SimpleScore::ONE.score, 1);
119    }
120
121    #[test]
122    fn test_is_feasible() {
123        assert!(SimpleScore::of(0).is_feasible());
124        assert!(SimpleScore::of(10).is_feasible());
125        assert!(!SimpleScore::of(-1).is_feasible());
126    }
127
128    #[test]
129    fn test_arithmetic() {
130        let a = SimpleScore::of(10);
131        let b = SimpleScore::of(3);
132
133        assert_eq!(a + b, SimpleScore::of(13));
134        assert_eq!(a - b, SimpleScore::of(7));
135        assert_eq!(-a, SimpleScore::of(-10));
136    }
137
138    #[test]
139    fn test_comparison() {
140        assert!(SimpleScore::of(10) > SimpleScore::of(5));
141        assert!(SimpleScore::of(-5) < SimpleScore::of(0));
142        assert!(SimpleScore::of(5) == SimpleScore::of(5));
143    }
144
145    #[test]
146    fn test_parse() {
147        assert_eq!(SimpleScore::parse("42").unwrap(), SimpleScore::of(42));
148        assert_eq!(SimpleScore::parse("-10").unwrap(), SimpleScore::of(-10));
149        assert_eq!(SimpleScore::parse("  0  ").unwrap(), SimpleScore::ZERO);
150        assert!(SimpleScore::parse("invalid").is_err());
151    }
152
153    #[test]
154    fn test_display() {
155        assert_eq!(format!("{}", SimpleScore::of(42)), "42");
156        assert_eq!(format!("{}", SimpleScore::of(-10)), "-10");
157    }
158
159    #[test]
160    fn test_json_serialization() {
161        let score = SimpleScore::of(42);
162        let json = serde_json::to_string(&score).unwrap();
163        assert_eq!(json, r#"{"score":42}"#);
164
165        let parsed: SimpleScore = serde_json::from_str(&json).unwrap();
166        assert_eq!(parsed, score);
167    }
168}