1use std::cmp::Ordering;
6use std::fmt;
7use std::ops::{Add, Neg, Sub};
8
9use super::traits::Score;
10
11#[derive(Clone, Copy, PartialEq, Eq, Hash)]
33pub struct BendableScore<const H: usize, const S: usize> {
34 hard: [i64; H],
35 soft: [i64; S],
36}
37
38impl<const H: usize, const S: usize> BendableScore<H, S> {
39 pub const fn of(hard: [i64; H], soft: [i64; S]) -> Self {
41 BendableScore { hard, soft }
42 }
43
44 pub const fn zero() -> Self {
46 BendableScore {
47 hard: [0; H],
48 soft: [0; S],
49 }
50 }
51
52 pub const fn hard_levels_count(&self) -> usize {
54 H
55 }
56
57 pub const fn soft_levels_count(&self) -> usize {
59 S
60 }
61
62 pub const fn hard_score(&self, level: usize) -> i64 {
67 self.hard[level]
68 }
69
70 pub const fn soft_score(&self, level: usize) -> i64 {
75 self.soft[level]
76 }
77
78 pub const fn hard_scores(&self) -> &[i64; H] {
80 &self.hard
81 }
82
83 pub const fn soft_scores(&self) -> &[i64; S] {
85 &self.soft
86 }
87
88 pub const fn one_hard(level: usize) -> Self {
90 let mut hard = [0; H];
91 hard[level] = 1;
92 BendableScore { hard, soft: [0; S] }
93 }
94
95 pub const fn one_soft(level: usize) -> Self {
97 let mut soft = [0; S];
98 soft[level] = 1;
99 BendableScore { hard: [0; H], soft }
100 }
101}
102
103impl<const H: usize, const S: usize> Default for BendableScore<H, S> {
104 fn default() -> Self {
105 Self::zero()
106 }
107}
108
109impl<const H: usize, const S: usize> Score for BendableScore<H, S> {
110 fn is_feasible(&self) -> bool {
111 self.hard.iter().all(|&s| s >= 0)
112 }
113
114 fn zero() -> Self {
115 BendableScore::zero()
116 }
117
118 fn levels_count() -> usize {
119 H + S
120 }
121
122 fn to_level_numbers(&self) -> Vec<i64> {
123 let mut levels = Vec::with_capacity(H + S);
124 levels.extend_from_slice(&self.hard);
125 levels.extend_from_slice(&self.soft);
126 levels
127 }
128
129 fn from_level_numbers(levels: &[i64]) -> Self {
130 assert!(levels.len() >= H + S, "Not enough levels provided");
131 let mut hard = [0; H];
132 let mut soft = [0; S];
133 hard.copy_from_slice(&levels[..H]);
134 soft.copy_from_slice(&levels[H..H + S]);
135 BendableScore { hard, soft }
136 }
137
138 fn multiply(&self, multiplicand: f64) -> Self {
139 let mut hard = [0; H];
140 let mut soft = [0; S];
141 for (i, item) in hard.iter_mut().enumerate().take(H) {
142 *item = (self.hard[i] as f64 * multiplicand).round() as i64;
143 }
144 for (i, item) in soft.iter_mut().enumerate().take(S) {
145 *item = (self.soft[i] as f64 * multiplicand).round() as i64;
146 }
147 BendableScore { hard, soft }
148 }
149
150 fn divide(&self, divisor: f64) -> Self {
151 let mut hard = [0; H];
152 let mut soft = [0; S];
153 for (i, item) in hard.iter_mut().enumerate().take(H) {
154 *item = (self.hard[i] as f64 / divisor).round() as i64;
155 }
156 for (i, item) in soft.iter_mut().enumerate().take(S) {
157 *item = (self.soft[i] as f64 / divisor).round() as i64;
158 }
159 BendableScore { hard, soft }
160 }
161
162 fn abs(&self) -> Self {
163 let mut hard = [0; H];
164 let mut soft = [0; S];
165 for (i, item) in hard.iter_mut().enumerate().take(H) {
166 *item = self.hard[i].abs();
167 }
168 for (i, item) in soft.iter_mut().enumerate().take(S) {
169 *item = self.soft[i].abs();
170 }
171 BendableScore { hard, soft }
172 }
173}
174
175impl<const H: usize, const S: usize> Ord for BendableScore<H, S> {
176 fn cmp(&self, other: &Self) -> Ordering {
177 for i in 0..H {
179 match self.hard[i].cmp(&other.hard[i]) {
180 Ordering::Equal => continue,
181 ord => return ord,
182 }
183 }
184
185 for i in 0..S {
187 match self.soft[i].cmp(&other.soft[i]) {
188 Ordering::Equal => continue,
189 ord => return ord,
190 }
191 }
192
193 Ordering::Equal
194 }
195}
196
197impl<const H: usize, const S: usize> PartialOrd for BendableScore<H, S> {
198 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
199 Some(self.cmp(other))
200 }
201}
202
203impl<const H: usize, const S: usize> Add for BendableScore<H, S> {
204 type Output = Self;
205
206 fn add(self, other: Self) -> Self {
207 let mut hard = [0; H];
208 let mut soft = [0; S];
209 for (i, item) in hard.iter_mut().enumerate().take(H) {
210 *item = self.hard[i] + other.hard[i];
211 }
212 for (i, item) in soft.iter_mut().enumerate().take(S) {
213 *item = self.soft[i] + other.soft[i];
214 }
215 BendableScore { hard, soft }
216 }
217}
218
219impl<const H: usize, const S: usize> Sub for BendableScore<H, S> {
220 type Output = Self;
221
222 fn sub(self, other: Self) -> Self {
223 let mut hard = [0; H];
224 let mut soft = [0; S];
225 for (i, item) in hard.iter_mut().enumerate().take(H) {
226 *item = self.hard[i] - other.hard[i];
227 }
228 for (i, item) in soft.iter_mut().enumerate().take(S) {
229 *item = self.soft[i] - other.soft[i];
230 }
231 BendableScore { hard, soft }
232 }
233}
234
235impl<const H: usize, const S: usize> Neg for BendableScore<H, S> {
236 type Output = Self;
237
238 fn neg(self) -> Self {
239 let mut hard = [0; H];
240 let mut soft = [0; S];
241 for (i, item) in hard.iter_mut().enumerate().take(H) {
242 *item = -self.hard[i];
243 }
244 for (i, item) in soft.iter_mut().enumerate().take(S) {
245 *item = -self.soft[i];
246 }
247 BendableScore { hard, soft }
248 }
249}
250
251impl<const H: usize, const S: usize> fmt::Debug for BendableScore<H, S> {
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 write!(
254 f,
255 "BendableScore(hard: {:?}, soft: {:?})",
256 self.hard, self.soft
257 )
258 }
259}
260
261impl<const H: usize, const S: usize> fmt::Display for BendableScore<H, S> {
262 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
263 let hard_str: Vec<String> = self.hard.iter().map(|s| s.to_string()).collect();
264 let soft_str: Vec<String> = self.soft.iter().map(|s| s.to_string()).collect();
265
266 write!(
267 f,
268 "[{}]hard/[{}]soft",
269 hard_str.join("/"),
270 soft_str.join("/")
271 )
272 }
273}
274
275#[cfg(test)]
276mod tests {
277 use super::*;
278
279 #[test]
280 fn test_creation() {
281 let score: BendableScore<2, 3> = BendableScore::of([-1, -2], [-10, -20, -30]);
282 assert_eq!(score.hard_levels_count(), 2);
283 assert_eq!(score.soft_levels_count(), 3);
284 assert_eq!(score.hard_score(0), -1);
285 assert_eq!(score.hard_score(1), -2);
286 assert_eq!(score.soft_score(2), -30);
287 }
288
289 #[test]
290 fn test_feasibility() {
291 let feasible: BendableScore<2, 2> = BendableScore::of([0, 0], [-10, -20]);
292 let infeasible: BendableScore<2, 2> = BendableScore::of([0, -1], [0, 0]);
293
294 assert!(feasible.is_feasible());
295 assert!(!infeasible.is_feasible());
296 }
297
298 #[test]
299 fn test_comparison() {
300 let s1: BendableScore<2, 1> = BendableScore::of([-1, 0], [0]);
302 let s2: BendableScore<2, 1> = BendableScore::of([0, -100], [-1000]);
303 assert!(s2 > s1);
304
305 let s3: BendableScore<2, 1> = BendableScore::of([0, -10], [0]);
307 let s4: BendableScore<2, 1> = BendableScore::of([0, -5], [-100]);
308 assert!(s4 > s3);
309 }
310
311 #[test]
312 fn test_arithmetic() {
313 let s1: BendableScore<1, 2> = BendableScore::of([-1], [-10, -20]);
314 let s2: BendableScore<1, 2> = BendableScore::of([-2], [-5, -10]);
315
316 let sum = s1 + s2;
317 assert_eq!(sum.hard_scores(), &[-3]);
318 assert_eq!(sum.soft_scores(), &[-15, -30]);
319
320 let neg = -s1;
321 assert_eq!(neg.hard_scores(), &[1]);
322 assert_eq!(neg.soft_scores(), &[10, 20]);
323 }
324
325 #[test]
326 fn test_copy() {
327 let s1: BendableScore<1, 1> = BendableScore::of([-1], [-10]);
328 let s2 = s1; assert_eq!(s1, s2); }
331}