cribbage_core/pegging/
mod.rs

1mod four_card_pegging;
2mod one_card_pegging;
3mod three_card_pegging;
4mod two_card_pegging;
5
6pub use self::four_card_pegging::FourCardPegging;
7pub use self::one_card_pegging::OneCardPegging;
8pub use self::three_card_pegging::ThreeCardPegging;
9pub use self::two_card_pegging::TwoCardPegging;
10
11use crate::card::Card;
12use crate::CribbageCoreError;
13
14#[derive(Default)]
15pub struct Pegger {
16    count: u8,
17    played_cards: Vec<Card>,
18}
19
20impl Pegger {
21    pub fn new() -> Pegger {
22        Pegger {
23            count: 0,
24            played_cards: Vec::new(),
25        }
26    }
27
28    fn is_run(cards: &[Card]) -> bool {
29        if cards.len() < 3 {
30            return false;
31        }
32
33        let mut sorted = cards.to_vec();
34        sorted.sort();
35
36        for i in 1..sorted.len() {
37            if sorted[i].rank().ordinal() != sorted[i - 1].rank().ordinal() + 1 {
38                return false;
39            }
40        }
41
42        true
43    }
44
45    pub fn count(&self) -> u8 {
46        self.count
47    }
48
49    /*
50    Note: Caller must implement logic to assign the "go" point to the appropriate player
51          whenever a count of 31 isn't reached exactly. In the event that a count of 31 is reached
52          exactly, this method returns the 1 point (expecting the caller to add 1 point for
53          the "go").
54    */
55    pub fn play_card(&mut self, card: Card) -> Result<u8, CribbageCoreError> {
56        let new_count = self.count + card.rank().value();
57        if new_count > 31 {
58            return Err(CribbageCoreError::InvalidCard);
59        }
60
61        self.count = new_count;
62
63        let mut points = match self.count {
64            15 => 2,
65            31 => 1,
66            _ => 0,
67        };
68
69        let mut cards_with_same_rank = 0;
70        for played_card in self.played_cards.iter().rev() {
71            if played_card.rank() == card.rank() {
72                cards_with_same_rank += 1;
73            } else {
74                break;
75            }
76        }
77
78        self.played_cards.push(card);
79
80        points += match cards_with_same_rank {
81            1 => 2,
82            2 => 6,
83            3 => 12,
84            _ => 0,
85        };
86
87        for i in 0..self.played_cards.len() {
88            let card_slice = &self.played_cards[i..self.played_cards.len()];
89            if Pegger::is_run(card_slice) {
90                points += card_slice.len() as u8;
91                break;
92            }
93        }
94
95        Ok(points)
96    }
97
98    pub fn reset(&mut self) {
99        self.count = 0;
100        self.played_cards.clear();
101    }
102}
103
104#[cfg(test)]
105mod test {
106    use crate::card::{Card, Rank, Suit};
107    use crate::CribbageCoreError;
108    use crate::Pegger;
109
110    #[test]
111    fn test_is_run() {
112        assert_eq!(Pegger::is_run(&[]), false);
113        assert_eq!(Pegger::is_run(&[Card::new(Rank::Ace, Suit::Spades)]), false);
114        assert_eq!(
115            Pegger::is_run(&[
116                Card::new(Rank::Ace, Suit::Spades),
117                Card::new(Rank::Two, Suit::Spades)
118            ]),
119            false
120        );
121        assert_eq!(
122            Pegger::is_run(&[
123                Card::new(Rank::Ace, Suit::Spades),
124                Card::new(Rank::Two, Suit::Spades),
125                Card::new(Rank::Three, Suit::Spades)
126            ]),
127            true
128        );
129        assert_eq!(
130            Pegger::is_run(&[
131                Card::new(Rank::Ace, Suit::Spades),
132                Card::new(Rank::Two, Suit::Spades),
133                Card::new(Rank::Four, Suit::Spades)
134            ]),
135            false
136        );
137        assert_eq!(
138            Pegger::is_run(&[
139                Card::new(Rank::Two, Suit::Spades),
140                Card::new(Rank::Three, Suit::Spades),
141                Card::new(Rank::Ace, Suit::Spades)
142            ]),
143            true
144        );
145        assert_eq!(
146            Pegger::is_run(&[
147                Card::new(Rank::Ace, Suit::Hearts),
148                Card::new(Rank::Two, Suit::Clubs),
149                Card::new(Rank::Three, Suit::Diamonds),
150                Card::new(Rank::Four, Suit::Spades)
151            ]),
152            true
153        );
154        assert_eq!(
155            Pegger::is_run(&[
156                Card::new(Rank::Four, Suit::Hearts),
157                Card::new(Rank::Two, Suit::Clubs),
158                Card::new(Rank::Ace, Suit::Diamonds),
159                Card::new(Rank::Three, Suit::Spades)
160            ]),
161            true
162        );
163        assert_eq!(
164            Pegger::is_run(&[
165                Card::new(Rank::Ace, Suit::Spades),
166                Card::new(Rank::Two, Suit::Spades),
167                Card::new(Rank::Three, Suit::Spades),
168                Card::new(Rank::Five, Suit::Spades)
169            ]),
170            false
171        );
172    }
173
174    #[test]
175    fn test_play_card() {
176        let mut pegger = Pegger::new();
177        assert_eq!(
178            pegger
179                .play_card(Card::new(Rank::Ace, Suit::Spades))
180                .unwrap(),
181            0
182        );
183        assert_eq!(
184            pegger
185                .play_card(Card::new(Rank::Ace, Suit::Hearts))
186                .unwrap(),
187            2
188        );
189        assert_eq!(
190            pegger.play_card(Card::new(Rank::Ace, Suit::Clubs)).unwrap(),
191            6
192        );
193        assert_eq!(
194            pegger
195                .play_card(Card::new(Rank::Ace, Suit::Diamonds))
196                .unwrap(),
197            12
198        );
199        assert_eq!(
200            pegger.play_card(Card::new(Rank::Two, Suit::Clubs)).unwrap(),
201            0
202        );
203        assert_eq!(
204            pegger
205                .play_card(Card::new(Rank::Three, Suit::Spades))
206                .unwrap(),
207            3
208        );
209        assert_eq!(
210            pegger
211                .play_card(Card::new(Rank::Four, Suit::Diamonds))
212                .unwrap(),
213            4
214        );
215        assert_eq!(
216            pegger
217                .play_card(Card::new(Rank::Two, Suit::Hearts))
218                .unwrap(),
219            5
220        );
221        assert_eq!(
222            pegger
223                .play_card(Card::new(Rank::Eight, Suit::Clubs))
224                .unwrap(),
225            0
226        );
227        assert_eq!(
228            pegger
229                .play_card(Card::new(Rank::Eight, Suit::Spades))
230                .unwrap(),
231            3
232        );
233        pegger.reset();
234
235        assert_eq!(
236            pegger
237                .play_card(Card::new(Rank::Ten, Suit::Spades))
238                .unwrap(),
239            0
240        );
241        assert_eq!(
242            pegger
243                .play_card(Card::new(Rank::Five, Suit::Spades))
244                .unwrap(),
245            2
246        );
247        assert_eq!(
248            pegger.play_card(Card::new(Rank::Ten, Suit::Clubs)).unwrap(),
249            0
250        );
251        assert_eq!(
252            pegger
253                .play_card(Card::new(Rank::Five, Suit::Diamonds))
254                .unwrap(),
255            0
256        );
257        assert_eq!(
258            pegger
259                .play_card(Card::new(Rank::Ace, Suit::Hearts))
260                .unwrap(),
261            1
262        );
263        assert_eq!(
264            pegger.play_card(Card::new(Rank::Ace, Suit::Spades)),
265            Err(CribbageCoreError::InvalidCard)
266        );
267    }
268}