fudd/types/arrays/
six_card.rs

1use crate::analysis::eval::Eval;
2use crate::analysis::evals::Evals;
3use crate::types::arrays::five_card::FiveCard;
4use crate::types::arrays::three_card::ThreeCard;
5use crate::types::arrays::two_card::TwoCard;
6use crate::types::arrays::{Evaluable, Vectorable};
7use crate::types::playing_card::PlayingCard;
8use crate::types::playing_cards::PlayingCards;
9use crate::types::poker_cards::PokerCards;
10use crate::types::U32Card;
11use ckc_rs::{CardNumber, HandError, PokerCard};
12
13#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
14pub struct SixCard([U32Card; 6]);
15
16impl SixCard {
17    /// permutations to evaluate all 6 card combinations.
18    pub const PERMUTATIONS: [[u8; 5]; 6] = [
19        [0, 1, 2, 3, 4],
20        [0, 1, 2, 3, 5],
21        [0, 1, 2, 4, 5],
22        [0, 1, 3, 4, 5],
23        [0, 2, 3, 4, 5],
24        [1, 2, 3, 4, 5],
25    ];
26
27    #[must_use]
28    pub fn from_1_and_2_and_3(one: U32Card, two: TwoCard, three: ThreeCard) -> SixCard {
29        SixCard::from([
30            one,
31            two.first(),
32            two.second(),
33            three.first(),
34            three.second(),
35            three.third(),
36        ])
37    }
38
39    //region getters
40    #[must_use]
41    pub fn first(&self) -> U32Card {
42        self.0[0]
43    }
44
45    #[must_use]
46    pub fn second(&self) -> U32Card {
47        self.0[1]
48    }
49
50    #[must_use]
51    pub fn third(&self) -> U32Card {
52        self.0[2]
53    }
54
55    #[must_use]
56    pub fn forth(&self) -> U32Card {
57        self.0[3]
58    }
59
60    #[must_use]
61    pub fn fifth(&self) -> U32Card {
62        self.0[4]
63    }
64
65    #[must_use]
66    pub fn sixth(&self) -> U32Card {
67        self.0[5]
68    }
69    //endregion
70}
71
72impl Evaluable for SixCard {
73    fn evals(&self) -> Evals {
74        let mut evals = Evals::default();
75        let mut subhand: [U32Card; 5] = [CardNumber::BLANK; 5];
76
77        for ids in &crate::types::arrays::six_card::SixCard::PERMUTATIONS {
78            for i in 0..5 {
79                subhand[i] = self.0[ids[i] as usize];
80            }
81            let (hand, eval) = FiveCard::from(subhand).evaluate();
82            evals.push(Eval::raw(hand, eval));
83        }
84        evals
85    }
86}
87
88impl From<[PlayingCard; 6]> for SixCard {
89    fn from(array: [PlayingCard; 6]) -> Self {
90        SixCard::from([
91            array[0].as_u32(),
92            array[1].as_u32(),
93            array[2].as_u32(),
94            array[3].as_u32(),
95            array[4].as_u32(),
96            array[5].as_u32(),
97        ])
98    }
99}
100
101impl From<[U32Card; 6]> for SixCard {
102    fn from(value: [U32Card; 6]) -> Self {
103        SixCard(value)
104    }
105}
106
107impl TryFrom<&PlayingCards> for SixCard {
108    type Error = HandError;
109
110    fn try_from(playing_cards: &PlayingCards) -> Result<Self, Self::Error> {
111        match playing_cards.len() {
112            0..=5 => Err(HandError::NotEnoughCards),
113            6 => Ok(SixCard::from([
114                *playing_cards.get_index(0).unwrap(),
115                *playing_cards.get_index(1).unwrap(),
116                *playing_cards.get_index(2).unwrap(),
117                *playing_cards.get_index(3).unwrap(),
118                *playing_cards.get_index(4).unwrap(),
119                *playing_cards.get_index(5).unwrap(),
120            ])),
121            _ => Err(HandError::TooManyCards),
122        }
123    }
124}
125
126impl TryFrom<&PokerCards> for SixCard {
127    type Error = HandError;
128
129    fn try_from(poker_cards: &PokerCards) -> Result<Self, Self::Error> {
130        SixCard::try_from(&PlayingCards::from(poker_cards))
131    }
132}
133
134impl TryFrom<&'static str> for SixCard {
135    type Error = HandError;
136
137    /// Returns a valid `CactusKevHand` if the entered index string splits out into exactly
138    /// five valid `Card`
139    ///
140    /// ```
141    /// use std::convert::TryFrom;
142    /// use fudd::types::arrays::five_card::FiveCard;
143    ///
144    /// let royal_flush = FiveCard::try_from("AS KS QS JS TS").unwrap();
145    /// let s = format!("{}", royal_flush);
146    ///
147    /// assert_eq!(s, "A♠ K♠ Q♠ J♠ T♠");
148    /// ```
149    ///
150    /// # Errors
151    ///
152    /// Returns a `HandError::InvalidCard` error if it doesn't recognize the cards in the passed in
153    /// index string:
154    ///
155    /// ```
156    /// use std::convert::TryFrom;
157    /// use fudd::types::arrays::five_card::FiveCard;
158    /// use ckc_rs::HandError;
159    ///
160    /// let invalid_hand = FiveCard::try_from("AR KE QS JS TS");
161    ///
162    /// assert!(invalid_hand.is_err());
163    /// assert_eq!(invalid_hand.unwrap_err(), HandError::InvalidCard);
164    /// ```
165    ///
166    /// Will return a `HandError::NotEnoughCards` if there are less than five cards passed in.
167    ///
168    /// ```
169    /// use std::convert::TryFrom;
170    /// use fudd::types::arrays::five_card::FiveCard;
171    /// use ckc_rs::HandError;
172    ///
173    /// let invalid_hand = FiveCard::try_from("A♠ K♦ Q♣ J♥");
174    ///
175    /// assert!(invalid_hand.is_err());
176    /// assert_eq!(invalid_hand.unwrap_err(), HandError::NotEnoughCards);
177    /// ```
178    ///
179    /// Will return a `HandError::TooManyCards` if there are more than five cards passed in.
180    ///
181    /// ```
182    /// use std::convert::TryFrom;
183    /// use fudd::types::arrays::five_card::FiveCard;
184    /// use ckc_rs::HandError;
185    ///
186    /// let invalid_hand = FiveCard::try_from("A♠ K♦ Q♣ J♥ T♦ 2♣");
187    ///
188    /// assert!(invalid_hand.is_err());
189    /// assert_eq!(invalid_hand.unwrap_err(), HandError::TooManyCards);
190    /// ```
191    ///
192    /// # Panics
193    ///
194    /// Shouldn't be able to panic. (fingers crossed)
195    ///
196    fn try_from(value: &'static str) -> Result<Self, Self::Error> {
197        match PokerCards::try_from(value) {
198            Ok(cards) => SixCard::try_from(&cards),
199            Err(e) => Err(e),
200        }
201    }
202}
203
204impl Vectorable for SixCard {
205    #[must_use]
206    fn to_vec(&self) -> Vec<U32Card> {
207        self.0.to_vec()
208    }
209}
210
211#[cfg(test)]
212#[allow(non_snake_case)]
213mod types_arrays_six_card_tests {
214    use super::*;
215    use ckc_rs::hand_rank::HandRankClass;
216    use rstest::rstest;
217
218    #[test]
219    fn eval() {
220        let ckcs = SixCard::try_from("6H AH KH QH JH TH").unwrap().eval();
221
222        assert_eq!(ckcs.rank.class, HandRankClass::RoyalFlush);
223    }
224
225    #[rstest]
226    #[case("9H AH KH QH JH TH", "AH KH QH JH TH")]
227    #[case("9H AH KS QH JD TH", "A♥ K♠ Q♥ J♦ T♥")]
228    #[case("9H AH KS QH JD TH", "A♥ K♠ Q♥ J♦ T♥")]
229    #[case("9H TD KS QH 9D TH", "TH TD 9H 9D KS")]
230    fn eval__many(#[case] index: &'static str, #[case] best_index: &'static str) {
231        let hand = SixCard::try_from(index).unwrap().eval();
232
233        let expected = FiveCard::try_from(best_index).unwrap();
234
235        assert_eq!(hand.hand, expected);
236    }
237
238    #[test]
239    fn try_from__poker_cards() {
240        let poker_cards = PokerCards::try_from("9H AS KS QS JS TS").unwrap();
241
242        let a = SixCard::try_from(&poker_cards).unwrap();
243
244        assert_eq!(*poker_cards.get(0).unwrap(), a.first());
245        assert_eq!(*poker_cards.get(1).unwrap(), a.second());
246        assert_eq!(*poker_cards.get(2).unwrap(), a.third());
247        assert_eq!(*poker_cards.get(3).unwrap(), a.forth());
248        assert_eq!(*poker_cards.get(4).unwrap(), a.fifth());
249        assert_eq!(*poker_cards.get(5).unwrap(), a.sixth());
250    }
251}