1use std::ops::{Index, IndexMut};
2
3use crate::CribbageCoreError;
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub enum TwoPlayers {
7 PlayerOne,
8 PlayerTwo,
9}
10
11pub struct TwoPlayerScore<T> {
12 scores: [T; 2],
13}
14
15impl<T> Index<TwoPlayers> for TwoPlayerScore<T> {
16 type Output = T;
17
18 fn index(&self, index: TwoPlayers) -> &Self::Output {
19 match index {
20 TwoPlayers::PlayerOne => &self.scores[0],
21 TwoPlayers::PlayerTwo => &self.scores[1],
22 }
23 }
24}
25
26impl<T> IndexMut<TwoPlayers> for TwoPlayerScore<T> {
27 fn index_mut(&mut self, index: TwoPlayers) -> &mut T {
28 match index {
29 TwoPlayers::PlayerOne => &mut self.scores[0],
30 TwoPlayers::PlayerTwo => &mut self.scores[1],
31 }
32 }
33}
34
35#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub enum ThreePlayers {
37 PlayerOne,
38 PlayerTwo,
39 PlayerThree,
40}
41
42pub struct ThreePlayerScore<T> {
43 scores: [T; 3],
44}
45
46impl<T> Index<ThreePlayers> for ThreePlayerScore<T> {
47 type Output = T;
48
49 fn index(&self, index: ThreePlayers) -> &Self::Output {
50 match index {
51 ThreePlayers::PlayerOne => &self.scores[0],
52 ThreePlayers::PlayerTwo => &self.scores[1],
53 ThreePlayers::PlayerThree => &self.scores[2],
54 }
55 }
56}
57
58impl<T> IndexMut<ThreePlayers> for ThreePlayerScore<T> {
59 fn index_mut(&mut self, index: ThreePlayers) -> &mut T {
60 match index {
61 ThreePlayers::PlayerOne => &mut self.scores[0],
62 ThreePlayers::PlayerTwo => &mut self.scores[1],
63 ThreePlayers::PlayerThree => &mut self.scores[2],
64 }
65 }
66}
67
68#[derive(Clone, Copy, Debug, Eq, PartialEq)]
69pub enum FourPlayers {
70 PlayerOne,
71 PlayerTwo,
72 PlayerThree,
73 PlayerFour,
74}
75
76pub struct FourPlayerScore<T> {
77 scores: [T; 4],
78}
79
80impl<T> Index<FourPlayers> for FourPlayerScore<T> {
81 type Output = T;
82
83 fn index(&self, index: FourPlayers) -> &Self::Output {
84 match index {
85 FourPlayers::PlayerOne => &self.scores[0],
86 FourPlayers::PlayerTwo => &self.scores[1],
87 FourPlayers::PlayerThree => &self.scores[2],
88 FourPlayers::PlayerFour => &self.scores[3],
89 }
90 }
91}
92
93impl<T> IndexMut<FourPlayers> for FourPlayerScore<T> {
94 fn index_mut(&mut self, index: FourPlayers) -> &mut T {
95 match index {
96 FourPlayers::PlayerOne => &mut self.scores[0],
97 FourPlayers::PlayerTwo => &mut self.scores[1],
98 FourPlayers::PlayerThree => &mut self.scores[2],
99 FourPlayers::PlayerFour => &mut self.scores[3],
100 }
101 }
102}
103
104pub trait Score: Copy + PartialEq + PartialOrd + Sized {
105 fn initial() -> Self;
106
107 fn saturating_add(self, other: Self) -> Self;
108
109 fn saturating_sub(self, other: Self) -> Self;
110}
111
112impl Score for u8 {
113 fn initial() -> Self {
114 0
115 }
116
117 fn saturating_add(self, other: Self) -> Self {
118 self.saturating_add(other)
119 }
120
121 fn saturating_sub(self, other: Self) -> Self {
122 self.saturating_sub(other)
123 }
124}
125
126pub struct Board<P, S>
127where
128 S: Index<P>,
129 S::Output: Sized,
130{
131 scores: S,
132 target: S::Output,
133 winner: Option<P>,
134}
135
136impl<P, S> Board<P, S>
137where
138 P: Copy,
139 S: Index<P> + IndexMut<P>,
140 S::Output: Score,
141{
142 pub fn add_points(&mut self, id: P, points: S::Output) -> Result<S::Output, CribbageCoreError> {
143 if self.winner.is_some() {
144 return Err(CribbageCoreError::WinnerExists);
145 }
146
147 self.scores[id] = self.scores[id].saturating_add(points);
148 if self.scores[id] > self.target {
149 self.scores[id] = self.target;
150 }
151
152 if self.scores[id] == self.target {
153 self.winner = Some(id);
154 }
155
156 Ok(self.scores[id])
157 }
158
159 pub fn subtract_points(
160 &mut self,
161 id: P,
162 points: S::Output,
163 ) -> Result<S::Output, CribbageCoreError> {
164 if self.winner.is_some() {
165 return Err(CribbageCoreError::WinnerExists);
166 }
167
168 self.scores[id] = self.scores[id].saturating_sub(points);
169 Ok(self.scores[id])
170 }
171
172 pub fn score(&self, id: P) -> S::Output {
173 self.scores[id]
174 }
175
176 pub fn winner(&self) -> Option<P> {
177 self.winner
178 }
179}
180
181pub fn custom_board<P, S>(scores: S, target: S::Output) -> Board<P, S>
182where
183 S: Index<P>,
184 S::Output: Sized,
185{
186 Board {
187 scores,
188 target,
189 winner: None,
190 }
191}
192
193pub fn standard_two_player_board() -> Board<TwoPlayers, TwoPlayerScore<u8>> {
194 custom_board(TwoPlayerScore { scores: [0; 2] }, 121)
195}
196
197pub fn standard_three_player_board() -> Board<ThreePlayers, ThreePlayerScore<u8>> {
198 custom_board(ThreePlayerScore { scores: [0; 3] }, 121)
199}
200
201pub fn standard_four_player_board() -> Board<FourPlayers, FourPlayerScore<u8>> {
202 custom_board(FourPlayerScore { scores: [0; 4] }, 121)
203}
204
205#[cfg(test)]
206mod tests {
207 use crate::board::{
208 standard_four_player_board, standard_three_player_board, standard_two_player_board,
209 FourPlayers, ThreePlayers, TwoPlayers,
210 };
211 use crate::CribbageCoreError;
212
213 #[test]
214 pub fn test_two_player_board() {
215 let mut board = standard_two_player_board();
216 assert_eq!(board.score(TwoPlayers::PlayerOne), 0);
217 assert_eq!(board.score(TwoPlayers::PlayerTwo), 0);
218
219 assert!(board.add_points(TwoPlayers::PlayerOne, 1).is_ok());
220 assert_eq!(board.score(TwoPlayers::PlayerOne), 1);
221 assert_eq!(board.score(TwoPlayers::PlayerTwo), 0);
222
223 assert!(board.add_points(TwoPlayers::PlayerOne, 119).is_ok());
224 assert_eq!(board.score(TwoPlayers::PlayerOne), 120);
225 assert_eq!(board.winner().is_some(), false);
226 assert_eq!(board.winner(), None);
227
228 assert!(board.add_points(TwoPlayers::PlayerOne, 2).is_ok());
229 assert_eq!(board.score(TwoPlayers::PlayerOne), 121);
230 assert_eq!(board.winner().is_some(), true);
231 assert_eq!(board.winner(), Some(TwoPlayers::PlayerOne));
232
233 assert_eq!(
234 board.add_points(TwoPlayers::PlayerOne, 1),
235 Err(CribbageCoreError::WinnerExists)
236 );
237
238 let mut board = standard_two_player_board();
239 assert!(board.add_points(TwoPlayers::PlayerTwo, 1).is_ok());
240 assert_eq!(board.score(TwoPlayers::PlayerOne), 0);
241 assert_eq!(board.score(TwoPlayers::PlayerTwo), 1);
242
243 assert!(board.add_points(TwoPlayers::PlayerTwo, 119).is_ok());
244 assert_eq!(board.score(TwoPlayers::PlayerTwo), 120);
245 assert_eq!(board.winner().is_some(), false);
246 assert_eq!(board.winner(), None);
247
248 assert!(board.add_points(TwoPlayers::PlayerTwo, 2).is_ok());
249 assert_eq!(board.score(TwoPlayers::PlayerTwo), 121);
250 assert_eq!(board.winner().is_some(), true);
251 assert_eq!(board.winner(), Some(TwoPlayers::PlayerTwo));
252
253 assert_eq!(
254 board.add_points(TwoPlayers::PlayerTwo, 1),
255 Err(CribbageCoreError::WinnerExists)
256 );
257 }
258
259 #[test]
260 pub fn test_three_player_board() {
261 let mut board = standard_three_player_board();
262 assert_eq!(board.score(ThreePlayers::PlayerOne), 0);
263 assert_eq!(board.score(ThreePlayers::PlayerTwo), 0);
264 assert_eq!(board.score(ThreePlayers::PlayerThree), 0);
265
266 assert!(board.add_points(ThreePlayers::PlayerOne, 1).is_ok());
267 assert_eq!(board.score(ThreePlayers::PlayerOne), 1);
268 assert_eq!(board.score(ThreePlayers::PlayerTwo), 0);
269 assert_eq!(board.score(ThreePlayers::PlayerThree), 0);
270
271 assert!(board.add_points(ThreePlayers::PlayerOne, 119).is_ok());
272 assert_eq!(board.score(ThreePlayers::PlayerOne), 120);
273 assert_eq!(board.winner().is_some(), false);
274 assert_eq!(board.winner(), None);
275
276 assert!(board.add_points(ThreePlayers::PlayerOne, 2).is_ok());
277 assert_eq!(board.score(ThreePlayers::PlayerOne), 121);
278 assert_eq!(board.winner().is_some(), true);
279 assert_eq!(board.winner(), Some(ThreePlayers::PlayerOne));
280
281 assert_eq!(
282 board.add_points(ThreePlayers::PlayerOne, 1),
283 Err(CribbageCoreError::WinnerExists)
284 );
285
286 let mut board = standard_three_player_board();
287 assert!(board.add_points(ThreePlayers::PlayerTwo, 1).is_ok());
288 assert_eq!(board.score(ThreePlayers::PlayerOne), 0);
289 assert_eq!(board.score(ThreePlayers::PlayerTwo), 1);
290 assert_eq!(board.score(ThreePlayers::PlayerThree), 0);
291
292 assert!(board.add_points(ThreePlayers::PlayerTwo, 119).is_ok());
293 assert_eq!(board.score(ThreePlayers::PlayerTwo), 120);
294 assert_eq!(board.winner().is_some(), false);
295 assert_eq!(board.winner(), None);
296
297 assert!(board.add_points(ThreePlayers::PlayerTwo, 2).is_ok());
298 assert_eq!(board.score(ThreePlayers::PlayerTwo), 121);
299 assert_eq!(board.winner().is_some(), true);
300 assert_eq!(board.winner(), Some(ThreePlayers::PlayerTwo));
301
302 assert_eq!(
303 board.add_points(ThreePlayers::PlayerTwo, 1),
304 Err(CribbageCoreError::WinnerExists)
305 );
306
307 let mut board = standard_three_player_board();
308 assert!(board.add_points(ThreePlayers::PlayerThree, 1).is_ok());
309 assert_eq!(board.score(ThreePlayers::PlayerOne), 0);
310 assert_eq!(board.score(ThreePlayers::PlayerTwo), 0);
311 assert_eq!(board.score(ThreePlayers::PlayerThree), 1);
312
313 assert!(board.add_points(ThreePlayers::PlayerThree, 119).is_ok());
314 assert_eq!(board.score(ThreePlayers::PlayerThree), 120);
315 assert_eq!(board.winner().is_some(), false);
316 assert_eq!(board.winner(), None);
317
318 assert!(board.add_points(ThreePlayers::PlayerThree, 2).is_ok());
319 assert_eq!(board.score(ThreePlayers::PlayerThree), 121);
320 assert_eq!(board.winner().is_some(), true);
321 assert_eq!(board.winner(), Some(ThreePlayers::PlayerThree));
322
323 assert_eq!(
324 board.add_points(ThreePlayers::PlayerThree, 1),
325 Err(CribbageCoreError::WinnerExists)
326 );
327 }
328
329 #[test]
330 pub fn test_four_player_board() {
331 let mut board = standard_four_player_board();
332 assert_eq!(board.score(FourPlayers::PlayerOne), 0);
333 assert_eq!(board.score(FourPlayers::PlayerTwo), 0);
334 assert_eq!(board.score(FourPlayers::PlayerThree), 0);
335 assert_eq!(board.score(FourPlayers::PlayerFour), 0);
336
337 assert!(board.add_points(FourPlayers::PlayerOne, 1).is_ok());
338 assert_eq!(board.score(FourPlayers::PlayerOne), 1);
339 assert_eq!(board.score(FourPlayers::PlayerTwo), 0);
340 assert_eq!(board.score(FourPlayers::PlayerThree), 0);
341 assert_eq!(board.score(FourPlayers::PlayerFour), 0);
342
343 assert!(board.add_points(FourPlayers::PlayerOne, 119).is_ok());
344 assert_eq!(board.score(FourPlayers::PlayerOne), 120);
345 assert_eq!(board.winner().is_some(), false);
346 assert_eq!(board.winner(), None);
347
348 assert!(board.add_points(FourPlayers::PlayerOne, 2).is_ok());
349 assert_eq!(board.score(FourPlayers::PlayerOne), 121);
350 assert_eq!(board.winner().is_some(), true);
351 assert_eq!(board.winner(), Some(FourPlayers::PlayerOne));
352
353 assert_eq!(
354 board.add_points(FourPlayers::PlayerOne, 1),
355 Err(CribbageCoreError::WinnerExists)
356 );
357
358 let mut board = standard_four_player_board();
359 assert!(board.add_points(FourPlayers::PlayerTwo, 1).is_ok());
360 assert_eq!(board.score(FourPlayers::PlayerOne), 0);
361 assert_eq!(board.score(FourPlayers::PlayerTwo), 1);
362 assert_eq!(board.score(FourPlayers::PlayerThree), 0);
363 assert_eq!(board.score(FourPlayers::PlayerFour), 0);
364
365 assert!(board.add_points(FourPlayers::PlayerTwo, 119).is_ok());
366 assert_eq!(board.score(FourPlayers::PlayerTwo), 120);
367 assert_eq!(board.winner().is_some(), false);
368 assert_eq!(board.winner(), None);
369
370 assert!(board.add_points(FourPlayers::PlayerTwo, 2).is_ok());
371 assert_eq!(board.score(FourPlayers::PlayerTwo), 121);
372 assert_eq!(board.winner().is_some(), true);
373 assert_eq!(board.winner(), Some(FourPlayers::PlayerTwo));
374
375 assert_eq!(
376 board.add_points(FourPlayers::PlayerTwo, 1),
377 Err(CribbageCoreError::WinnerExists)
378 );
379
380 let mut board = standard_four_player_board();
381 assert!(board.add_points(FourPlayers::PlayerThree, 1).is_ok());
382 assert_eq!(board.score(FourPlayers::PlayerOne), 0);
383 assert_eq!(board.score(FourPlayers::PlayerTwo), 0);
384 assert_eq!(board.score(FourPlayers::PlayerThree), 1);
385 assert_eq!(board.score(FourPlayers::PlayerFour), 0);
386
387 assert!(board.add_points(FourPlayers::PlayerThree, 119).is_ok());
388 assert_eq!(board.score(FourPlayers::PlayerThree), 120);
389 assert_eq!(board.winner().is_some(), false);
390 assert_eq!(board.winner(), None);
391
392 assert!(board.add_points(FourPlayers::PlayerThree, 2).is_ok());
393 assert_eq!(board.score(FourPlayers::PlayerThree), 121);
394 assert_eq!(board.winner().is_some(), true);
395 assert_eq!(board.winner(), Some(FourPlayers::PlayerThree));
396
397 assert_eq!(
398 board.add_points(FourPlayers::PlayerThree, 1),
399 Err(CribbageCoreError::WinnerExists)
400 );
401
402 let mut board = standard_four_player_board();
403 assert!(board.add_points(FourPlayers::PlayerFour, 1).is_ok());
404 assert_eq!(board.score(FourPlayers::PlayerOne), 0);
405 assert_eq!(board.score(FourPlayers::PlayerTwo), 0);
406 assert_eq!(board.score(FourPlayers::PlayerThree), 0);
407 assert_eq!(board.score(FourPlayers::PlayerFour), 1);
408
409 assert!(board.add_points(FourPlayers::PlayerFour, 119).is_ok());
410 assert_eq!(board.score(FourPlayers::PlayerFour), 120);
411 assert_eq!(board.winner().is_some(), false);
412 assert_eq!(board.winner(), None);
413
414 assert!(board.add_points(FourPlayers::PlayerFour, 2).is_ok());
415 assert_eq!(board.score(FourPlayers::PlayerFour), 121);
416 assert_eq!(board.winner().is_some(), true);
417 assert_eq!(board.winner(), Some(FourPlayers::PlayerFour));
418
419 assert_eq!(
420 board.add_points(FourPlayers::PlayerFour, 1),
421 Err(CribbageCoreError::WinnerExists)
422 );
423 }
424}