1use takparse::{Color, Piece};
2
3use crate::{
4 colors::Colors,
5 error::{StackError, TakeError},
6};
7
8#[derive(Clone, Copy, Debug, Hash, Default, PartialEq, Eq, PartialOrd, Ord)]
9pub struct Stack {
10 piece: Piece,
11 colors: Colors,
12}
13
14impl Stack {
15 #[must_use]
17 pub const fn new(piece: Piece, color: Color) -> Self {
18 Self {
19 piece,
20 colors: Colors::of_one(color),
21 }
22 }
23
24 #[must_use]
30 pub fn exact(piece: Piece, colors: Colors) -> Self {
31 assert!(!colors.is_empty());
32 Self { piece, colors }
33 }
34
35 #[must_use]
38 pub const fn is_empty(&self) -> bool {
39 self.colors.is_empty()
40 }
41
42 #[must_use]
44 pub const fn size(&self) -> u32 {
45 self.colors.len()
46 }
47
48 #[must_use]
50 pub fn top(&self) -> Option<(Piece, Color)> {
51 self.colors.top().map(|color| (self.piece, color))
52 }
53
54 #[must_use]
55 pub const fn colors(&self) -> Colors {
56 self.colors
57 }
58
59 #[must_use]
61 pub fn road(&self, color: Color) -> bool {
62 matches!(self.top(), Some((Piece::Flat | Piece::Cap, c)) if c == color)
63 }
64
65 pub fn stack(&mut self, piece: Piece, color: Color) -> Result<(), StackError> {
72 match self.piece {
74 Piece::Flat => Ok(()),
75 Piece::Wall => {
76 if matches!(piece, Piece::Cap) {
77 Ok(())
78 } else {
79 Err(StackError::Wall)
80 }
81 }
82 Piece::Cap => Err(StackError::Cap),
83 }?;
84
85 self.piece = piece;
86 self.colors.push(color);
87 Ok(())
88 }
89
90 pub fn take<const N: usize>(&mut self, amount: u32) -> Result<(Piece, Colors), TakeError> {
101 if amount == 0 {
102 return Err(TakeError::Zero);
103 } else if amount as usize > N {
104 return Err(TakeError::CarryLimit);
105 } else if amount > self.size() {
106 return Err(TakeError::StackSize);
107 }
108
109 let piece = self.piece;
110 self.piece = Piece::Flat;
111 Ok((
112 piece,
113 self.colors
114 .take(amount)
115 .expect("The amount should be small enough since we checked that above."),
116 ))
117 }
118}