open_pql/base/
hand_n.rs

1use super::{
2    Card, Card64, CardCount, From, HandIter, Hash, Index, Into, Rank, Vec, fmt,
3    iter, mem, slice,
4};
5
6/// A hand of N cards
7#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, From, Into)]
8pub struct HandN<const N: usize>(pub(crate) [Card; N]);
9
10impl<const N: usize> HandN<N> {
11    /// Creates a new hand from a sorted array of cards
12    pub(crate) fn new(array: [Card; N]) -> Self {
13        debug_assert!(
14            array.is_sorted(),
15            "Hand initialized from unsorted array {array:?}"
16        );
17        Self(array)
18    }
19
20    /// Creates a hand from a slice of cards
21    pub fn from_slice(cs: &[Card]) -> Self {
22        debug_assert!(
23            cs.len() >= N,
24            "from_slice: not enough cards for Hand<{}> slice has {} elements",
25            N,
26            cs.len()
27        );
28
29        let mut cards = [Card::default(); N];
30        cards.copy_from_slice(&cs[..N]);
31        cards.sort_unstable();
32
33        Self(cards)
34    }
35
36    /// Returns the underlying card array
37    pub const fn as_slice(&self) -> &[Card] {
38        &self.0
39    }
40
41    pub fn to_vec(&self) -> Vec<Card> {
42        self.0.to_vec()
43    }
44
45    /// Returns an iterator over the cards in the hand
46    pub fn iter(&self) -> impl Iterator<Item = Card> + '_ {
47        self.0.iter().copied()
48    }
49
50    /// Returns the number of cards in the hand
51    pub const fn len(&self) -> usize {
52        N
53    }
54
55    /// Returns true if the hand is empty
56    pub const fn is_empty(&self) -> bool {
57        N == 0
58    }
59
60    pub fn iter_all_short() -> HandIter<true, N> {
61        HandIter::default()
62    }
63
64    pub fn iter_all() -> HandIter<false, N> {
65        HandIter::default()
66    }
67}
68
69impl HandN<2> {
70    pub const fn to_u16(&self) -> u16 {
71        (self.0[0].to_u8() as u16) | (self.0[1].to_u8() as u16) << 8
72    }
73
74    pub fn from_u16(v: u16) -> Self {
75        let [c0, c1] = v.to_le_bytes();
76        Self::from_slice(&[Card::from_u8(c0), Card::from_u8(c1)])
77    }
78}
79
80impl HandN<3> {
81    pub(crate) fn count_by_rank(self, rank: Rank) -> CardCount {
82        CardCount::from(self[0].rank == rank)
83            + CardCount::from(self[1].rank == rank)
84            + CardCount::from(self[2].rank == rank)
85    }
86
87    pub(crate) fn sorted_ranks(self) -> (Rank, Rank, Rank) {
88        let (mut x, mut y, mut z) = (self[0].rank, self[1].rank, self[2].rank);
89
90        if x < y {
91            mem::swap(&mut x, &mut y);
92        }
93
94        if y < z {
95            mem::swap(&mut y, &mut z);
96        }
97
98        if x < y {
99            mem::swap(&mut x, &mut y);
100        }
101
102        (x, y, z)
103    }
104}
105
106impl<const N: usize> Index<usize> for HandN<N> {
107    type Output = Card;
108
109    fn index(&self, index: usize) -> &Self::Output {
110        &self.0[index]
111    }
112}
113
114impl<'a, const N: usize> IntoIterator for &'a HandN<N> {
115    type Item = Card;
116    type IntoIter = iter::Copied<slice::Iter<'a, Card>>;
117
118    fn into_iter(self) -> Self::IntoIter {
119        self.0.iter().copied()
120    }
121}
122
123impl<const N: usize> fmt::Debug for HandN<N> {
124    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125        write!(f, "Hand<")?;
126        for c in &self.0 {
127            write!(f, "{c}")?;
128        }
129        write!(f, ">")
130    }
131}
132
133impl<const N: usize> fmt::Display for HandN<N> {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        for card in &self.0 {
136            write!(f, "{card}")?;
137        }
138
139        Ok(())
140    }
141}
142
143impl<const N: usize> From<HandN<N>> for Card64 {
144    fn from(hand: HandN<N>) -> Self {
145        let mut card64 = Self::default();
146        for card in hand.iter() {
147            card64 |= Self::from(card);
148        }
149        card64
150    }
151}
152
153impl From<(Card, Card, Card)> for HandN<3> {
154    fn from(cs: (Card, Card, Card)) -> Self {
155        Self::from_slice(&[cs.0, cs.1, cs.2])
156    }
157}
158
159#[cfg(test)]
160mod tests {
161    use super::*;
162    use crate::*;
163
164    #[test]
165    fn test_hand() {
166        let cards = cards!("2s Kc Ad Kh");
167        let [c1, c2, c3, c4] = cards.clone().try_into().unwrap();
168
169        let hand: HandN<3> = HandN::from_slice(&cards);
170
171        assert_eq!(hand.as_slice(), &[c1, c2, c3]);
172
173        let hand: HandN<4> = HandN::from_slice(&cards);
174
175        assert_eq!(hand.as_slice(), &[c1, c4, c2, c3]);
176    }
177
178    #[test]
179    #[should_panic(expected = "not enough")]
180    fn test_hand_n3_not_enough_cards() {
181        let cards = cards!("2s Kc");
182
183        let _hand: HandN<3> = HandN::from_slice(&cards);
184    }
185
186    // ... existing tests ...
187
188    #[test]
189    fn test_hand_iter() {
190        let cards = cards!("2s Kc Ad");
191        let hand: HandN<3> = HandN::from_slice(&cards);
192
193        let collected: Vec<Card> = hand.iter().collect();
194        assert_eq!(collected, cards!("2s Kc Ad"));
195    }
196
197    #[test]
198    fn test_hand_into_iter() {
199        let cards = cards!("2s Kc Ad");
200        let hand: HandN<3> = HandN::from_slice(&cards);
201
202        let collected: Vec<Card> = (&hand).into_iter().collect();
203        assert_eq!(collected, cards!("2s Kc Ad"));
204    }
205
206    #[test]
207    fn test_hand_index() {
208        let cards = cards!("2s Kc Ad");
209        let hand: HandN<3> = HandN::from_slice(&cards);
210
211        assert_eq!(hand[0], cards!("2s")[0]);
212        assert_eq!(hand[1], cards!("Kc")[0]);
213        assert_eq!(hand[2], cards!("Ad")[0]);
214    }
215
216    #[test]
217    fn test_hand_len_and_is_empty() {
218        let cards = cards!("2s Kc Ad");
219        let hand3: HandN<3> = HandN::from_slice(&cards);
220        assert_eq!(hand3.len(), 3);
221        assert!(!hand3.is_empty());
222
223        let empty_cards = cards!("2s Kc Ad");
224        let hand0: HandN<0> = HandN::from_slice(&empty_cards);
225        assert_eq!(hand0.len(), 0);
226        assert!(hand0.is_empty());
227    }
228
229    #[test]
230    fn test_hand_debug_and_display() {
231        let cards = cards!("2s Kc Ad");
232        let hand: HandN<3> = HandN::from_slice(&cards);
233
234        // Test Debug implementation
235        let debug_str = format!("{hand:?}");
236        assert_eq!(debug_str, "Hand<2sKcAd>");
237    }
238
239    #[test]
240    fn test_hand_sorting() {
241        // Test that cards are sorted when creating a hand
242        let unsorted_cards = cards!("Ad Kc 2s");
243        let hand: HandN<3> = HandN::from_slice(&unsorted_cards);
244
245        // Cards should be sorted by rank and suit
246        assert_eq!(hand[0], cards!("2s")[0]);
247        assert_eq!(hand[1], cards!("Kc")[0]);
248        assert_eq!(hand[2], cards!("Ad")[0]);
249    }
250
251    #[test]
252    fn test_hand_equality() {
253        let cards1 = cards!("2s Kc Ad");
254        let cards2 = cards!("Ad Kc 2s"); // Same cards but different order
255
256        let hand1: HandN<3> = HandN::from_slice(&cards1);
257        let hand2: HandN<3> = HandN::from_slice(&cards2);
258
259        // Hands should be equal because they contain the same cards
260        // and Hand sorts the cards internally
261        assert_eq!(hand1, hand2);
262
263        // Different hands should not be equal
264        let cards3 = cards!("2s Kc Ah");
265        let hand3: HandN<3> = HandN::from_slice(&cards3);
266        assert_ne!(hand1, hand3);
267    }
268
269    #[quickcheck]
270    fn test_hand2_to_u16((c0, c1): (Card, Card)) {
271        if c0 != c1 {
272            let hand = HandN::<2>::from_slice(&<[Card; 2]>::from((c0, c1)));
273            assert_eq!(hand, HandN::<2>::from_u16(hand.to_u16()));
274        }
275    }
276
277    #[test]
278    #[should_panic(expected = "Hand initialized from unsorted array")]
279    #[cfg(debug_assertions)]
280    fn test_new_unsorted_array_debug_assert() {
281        // Create an unsorted array of cards
282        let unsorted = [
283            Card::from_str("Ad").unwrap(),
284            Card::from_str("2s").unwrap(),
285            Card::from_str("Kc").unwrap(),
286        ];
287
288        // This should panic in debug mode because the array is not sorted
289        let _hand = HandN::new(unsorted);
290    }
291
292    #[test]
293    #[should_panic(expected = "not enough cards for Hand")]
294    #[cfg(debug_assertions)]
295    fn test_from_slice_not_enough_cards_debug_assert() {
296        let cards = cards!("2s Kc"); // Only 2 cards
297
298        // This should panic in debug mode because we need 3 cards for Hand<3>
299        let _hand: HandN<3> = HandN::from_slice(&cards);
300    }
301
302    #[test]
303    fn test_from_slice_sorts_cards() {
304        let unsorted_cards = cards!("Ad Kc 2s");
305        let hand: HandN<3> = HandN::from_slice(&unsorted_cards);
306
307        // Verify that the cards are sorted in the resulting hand
308        let expected_order = cards!("2s Kc Ad");
309        for (i, card) in expected_order.iter().enumerate() {
310            assert_eq!(hand[i], *card);
311        }
312    }
313}