fudd/types/arrays/
seven_card.rs

1use crate::analysis::eval::Eval;
2use crate::analysis::evals::Evals;
3use crate::types::arrays::five_card::FiveCard;
4use crate::types::arrays::two_card::TwoCard;
5use crate::types::arrays::{Evaluable, Vectorable};
6use crate::types::playing_card::PlayingCard;
7use crate::types::playing_cards::PlayingCards;
8use crate::types::poker_cards::PokerCards;
9use crate::types::U32Card;
10use ckc_rs::cards::seven::Seven;
11use ckc_rs::{CardNumber, HandError, PokerCard};
12use core::fmt;
13use serde::{Deserialize, Serialize};
14use std::fmt::Formatter;
15
16#[derive(
17    Serialize, Deserialize, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd,
18)]
19pub struct SevenCard([U32Card; 7]);
20
21impl SevenCard {
22    #[must_use]
23    pub fn new(two: TwoCard, five: FiveCard) -> SevenCard {
24        SevenCard([
25            two.first(),
26            two.second(),
27            five.first(),
28            five.second(),
29            five.third(),
30            five.forth(),
31            five.fifth(),
32        ])
33    }
34
35    //region getters
36    #[must_use]
37    pub fn first(&self) -> U32Card {
38        self.0[0]
39    }
40
41    #[must_use]
42    pub fn second(&self) -> U32Card {
43        self.0[1]
44    }
45
46    #[must_use]
47    pub fn third(&self) -> U32Card {
48        self.0[2]
49    }
50
51    #[must_use]
52    pub fn forth(&self) -> U32Card {
53        self.0[3]
54    }
55
56    #[must_use]
57    pub fn fifth(&self) -> U32Card {
58        self.0[4]
59    }
60
61    #[must_use]
62    pub fn sixth(&self) -> U32Card {
63        self.0[5]
64    }
65
66    #[must_use]
67    pub fn seventh(&self) -> U32Card {
68        self.0[6]
69    }
70    //endregion
71
72    #[must_use]
73    pub fn sort(&self) -> SevenCard {
74        let mut c = *self;
75        c.sort_in_place();
76        c
77    }
78
79    pub fn sort_in_place(&mut self) {
80        self.0.sort_unstable();
81        self.0.reverse();
82    }
83
84    #[must_use]
85    pub fn to_arr(&self) -> [U32Card; 7] {
86        self.0
87    }
88
89    #[must_use]
90    pub fn to_seven(&self) -> Seven {
91        Seven::from(self.to_arr())
92    }
93}
94
95impl fmt::Display for SevenCard {
96    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
97        write!(f, "{}", PlayingCards::from(&self.to_vec()))
98    }
99}
100
101impl Evaluable for SevenCard {
102    fn evals(&self) -> Evals {
103        let mut evals = Evals::default();
104        let mut subhand: [U32Card; 5] = [CardNumber::BLANK; 5];
105
106        for ids in &ckc_rs::cards::seven::Seven::FIVE_CARD_PERMUTATIONS {
107            for i in 0..5 {
108                subhand[i] = self.0[ids[i] as usize];
109            }
110            let (hand, eval) = FiveCard::from(subhand).evaluate();
111            evals.push(Eval::raw(hand, eval));
112        }
113        evals
114    }
115}
116
117impl From<[PlayingCard; 7]> for SevenCard {
118    fn from(array: [PlayingCard; 7]) -> Self {
119        SevenCard::from([
120            array[0].as_u32(),
121            array[1].as_u32(),
122            array[2].as_u32(),
123            array[3].as_u32(),
124            array[4].as_u32(),
125            array[5].as_u32(),
126            array[6].as_u32(),
127        ])
128    }
129}
130
131impl From<[U32Card; 7]> for SevenCard {
132    fn from(array: [U32Card; 7]) -> Self {
133        SevenCard(array)
134    }
135}
136
137impl TryFrom<&PlayingCards> for SevenCard {
138    type Error = HandError;
139
140    fn try_from(playing_cards: &PlayingCards) -> Result<Self, Self::Error> {
141        SevenCard::try_from(&PokerCards::from(playing_cards))
142    }
143}
144
145impl TryFrom<&PokerCards> for SevenCard {
146    type Error = HandError;
147
148    fn try_from(poker_cards: &PokerCards) -> Result<Self, Self::Error> {
149        match poker_cards.len() {
150            0..=6 => Err(HandError::NotEnoughCards),
151            7 => Ok(SevenCard::from([
152                *poker_cards.get(0).unwrap(),
153                *poker_cards.get(1).unwrap(),
154                *poker_cards.get(2).unwrap(),
155                *poker_cards.get(3).unwrap(),
156                *poker_cards.get(4).unwrap(),
157                *poker_cards.get(5).unwrap(),
158                *poker_cards.get(6).unwrap(),
159            ])),
160            _ => Err(HandError::TooManyCards),
161        }
162    }
163}
164
165impl TryFrom<&'static str> for SevenCard {
166    type Error = HandError;
167
168    /// Returns a valid `CactusKevHand` if the entered index string splits out into exactly
169    /// five valid `Card`
170    ///
171    /// ```
172    /// use std::convert::TryFrom;
173    /// use fudd::types::arrays::five_card::FiveCard;
174    ///
175    /// let royal_flush = FiveCard::try_from("AS KS QS JS TS").unwrap();
176    /// let s = format!("{}", royal_flush);
177    ///
178    /// assert_eq!(s, "A♠ K♠ Q♠ J♠ T♠");
179    /// ```
180    ///
181    /// # Errors
182    ///
183    /// Returns a `HandError::InvalidCard` error if it doesn't recognize the cards in the passed in
184    /// index string:
185    ///
186    /// ```
187    /// use std::convert::TryFrom;
188    /// use fudd::types::arrays::five_card::FiveCard;
189    /// use ckc_rs::HandError;
190    ///
191    /// let invalid_hand = FiveCard::try_from("AR KE QS JS TS");
192    ///
193    /// assert!(invalid_hand.is_err());
194    /// assert_eq!(invalid_hand.unwrap_err(), HandError::InvalidCard);
195    /// ```
196    ///
197    /// Will return a `HandError::NotEnoughCards` if there are less than five cards passed in.
198    ///
199    /// ```
200    /// use std::convert::TryFrom;
201    /// use fudd::types::arrays::five_card::FiveCard;
202    /// use ckc_rs::HandError;
203    ///
204    /// let invalid_hand = FiveCard::try_from("A♠ K♦ Q♣ J♥");
205    ///
206    /// assert!(invalid_hand.is_err());
207    /// assert_eq!(invalid_hand.unwrap_err(), HandError::NotEnoughCards);
208    /// ```
209    ///
210    /// Will return a `HandError::TooManyCards` if there are more than five cards passed in.
211    ///
212    /// ```
213    /// use std::convert::TryFrom;
214    /// use fudd::types::arrays::five_card::FiveCard;
215    /// use ckc_rs::HandError;
216    ///
217    /// let invalid_hand = FiveCard::try_from("A♠ K♦ Q♣ J♥ T♦ 2♣");
218    ///
219    /// assert!(invalid_hand.is_err());
220    /// assert_eq!(invalid_hand.unwrap_err(), HandError::TooManyCards);
221    /// ```
222    ///
223    /// # Panics
224    ///
225    /// Shouldn't be able to panic. (fingers crossed)
226    ///
227    fn try_from(value: &'static str) -> Result<Self, Self::Error> {
228        match PokerCards::try_from(value) {
229            Ok(cards) => SevenCard::try_from(&cards),
230            Err(e) => Err(e),
231        }
232    }
233}
234
235impl TryFrom<Vec<&PlayingCard>> for SevenCard {
236    type Error = HandError;
237
238    fn try_from(v: Vec<&PlayingCard>) -> Result<Self, Self::Error> {
239        SevenCard::try_from(&PlayingCards::from(v))
240    }
241}
242
243impl Vectorable for SevenCard {
244    #[must_use]
245    fn to_vec(&self) -> Vec<U32Card> {
246        self.0.to_vec()
247    }
248}
249
250#[cfg(test)]
251#[allow(non_snake_case)]
252mod types_arrays_seven_card_tests {
253    use super::*;
254    use ckc_rs::hand_rank::HandRank;
255    use ckc_rs::CardNumber;
256
257    #[test]
258    fn sort() {
259        let seven = SevenCard::try_from("9H AS KS QS JS TS 2H").unwrap().sort();
260
261        assert_eq!("A♠ K♠ Q♠ J♠ T♠ 9♥ 2♥", seven.to_string());
262    }
263
264    #[test]
265    fn sort_in_place() {
266        let mut seven = SevenCard::try_from("9H AS KS QS JS TS 2H").unwrap();
267
268        seven.sort_in_place();
269
270        assert_eq!("A♠ K♠ Q♠ J♠ T♠ 9♥ 2♥", seven.to_string());
271    }
272
273    #[test]
274    fn display() {
275        let playing_cards = SevenCard::try_from("9H AS KS QS JS TS 2H").unwrap();
276
277        assert_eq!("9♥ A♠ K♠ Q♠ J♠ T♠ 2♥", playing_cards.to_string());
278    }
279
280    #[test]
281    fn from__array() {
282        let expected = SevenCard([
283            CardNumber::ACE_CLUBS,
284            CardNumber::KING_CLUBS,
285            CardNumber::QUEEN_CLUBS,
286            CardNumber::JACK_CLUBS,
287            CardNumber::TEN_CLUBS,
288            CardNumber::NINE_CLUBS,
289            CardNumber::EIGHT_CLUBS,
290        ]);
291
292        let actual = SevenCard::from([
293            CardNumber::ACE_CLUBS,
294            CardNumber::KING_CLUBS,
295            CardNumber::QUEEN_CLUBS,
296            CardNumber::JACK_CLUBS,
297            CardNumber::TEN_CLUBS,
298            CardNumber::NINE_CLUBS,
299            CardNumber::EIGHT_CLUBS,
300        ]);
301
302        assert_eq!(expected, actual);
303    }
304
305    #[test]
306    fn eval() {
307        let five_cards = FiveCard::try_from("AC KC QC JC TC").unwrap();
308        let two_cards = TwoCard::try_from("9C 8C").unwrap();
309
310        let seven = SevenCard::new(two_cards, five_cards);
311
312        assert_eq!(five_cards.eval(), seven.eval());
313    }
314
315    #[test]
316    fn evaluable() {
317        let five_cards = FiveCard::try_from("AC KC QC JC TC").unwrap();
318        let two_cards = TwoCard::try_from("9C 8C").unwrap();
319
320        let seven = SevenCard::new(two_cards, five_cards);
321
322        let (hand, hand_rank) = seven.evaluate();
323
324        assert_eq!(HandRank::from(1), hand_rank);
325        assert_eq!(five_cards, hand);
326    }
327
328    #[test]
329    fn try_from__playing_cards() {
330        let playing_cards = PlayingCards::try_from("9H AS KS QS JS TS 2H").unwrap();
331
332        let a = SevenCard::try_from(&playing_cards).unwrap();
333
334        assert_eq!(playing_cards.get_index(0).unwrap().as_u32(), a.first());
335        assert_eq!(playing_cards.get_index(1).unwrap().as_u32(), a.second());
336        assert_eq!(playing_cards.get_index(2).unwrap().as_u32(), a.third());
337        assert_eq!(playing_cards.get_index(3).unwrap().as_u32(), a.forth());
338        assert_eq!(playing_cards.get_index(4).unwrap().as_u32(), a.fifth());
339        assert_eq!(playing_cards.get_index(5).unwrap().as_u32(), a.sixth());
340        assert_eq!(playing_cards.get_index(6).unwrap().as_u32(), a.seventh());
341    }
342
343    #[test]
344    fn try_from__poker_cards() {
345        let poker_cards = PokerCards::try_from("9H AS KS QS JS TS 2H").unwrap();
346
347        let a = SevenCard::try_from(&poker_cards).unwrap();
348
349        assert_eq!(*poker_cards.get(0).unwrap(), a.first());
350        assert_eq!(*poker_cards.get(1).unwrap(), a.second());
351        assert_eq!(*poker_cards.get(2).unwrap(), a.third());
352        assert_eq!(*poker_cards.get(3).unwrap(), a.forth());
353        assert_eq!(*poker_cards.get(4).unwrap(), a.fifth());
354        assert_eq!(*poker_cards.get(5).unwrap(), a.sixth());
355        assert_eq!(*poker_cards.get(6).unwrap(), a.seventh());
356    }
357
358    #[test]
359    fn try_from__vec_playing_card() {
360        let v = vec![
361            &PlayingCard::ACE_SPADES,
362            &PlayingCard::KING_SPADES,
363            &PlayingCard::QUEEN_SPADES,
364            &PlayingCard::JACK_SPADES,
365            &PlayingCard::TEN_SPADES,
366            &PlayingCard::NINE_SPADES,
367            &PlayingCard::EIGHT_SPADES,
368        ];
369
370        let seven = SevenCard::try_from(v).unwrap();
371
372        assert_eq!("A♠ K♠ Q♠ J♠ T♠ 9♠ 8♠", seven.to_string())
373    }
374}