open_pql/base/
card64.rs

1use super::*;
2
3#[cfg(any(test, feature = "benchmark"))]
4#[macro_export]
5macro_rules! c64 {
6    ($s:expr) => {
7        $crate::Card64::from($crate::cards![$s].as_ref())
8    };
9}
10
11/// Card Set
12/// # Memory Layout:
13/// ```text
14/// [63, 48]:  xxxAKQJT 98765432  // Club
15/// [47, 32]:  xxxAKQJT 98765432  // Diamond
16/// [31, 16]:  xxxAKQJT 98765432  // Heart
17/// [15, 0]:   xxxAKQJT 98765432  // Spade, x: unused
18/// ```
19#[derive(
20    Copy,
21    Clone,
22    PartialEq,
23    Eq,
24    Hash,
25    BitAnd,
26    BitAndAssign,
27    BitOr,
28    BitOrAssign,
29    Default,
30)]
31pub struct Card64(u64);
32
33impl Card64 {
34    /// Constructs [Card64] from [u64]
35    ///
36    /// # Examples
37    ///
38    /// ```
39    /// use open_pql::{Card, Card64, Rank::*, Suit::*};
40    ///
41    /// let i: u64 = 0b11;
42    /// let c64: Card64 = Card64::from_u64(i);
43    ///
44    /// assert_eq!(
45    ///     c64,
46    ///     Card64::from([Card::new(R2, S), Card::new(R3, S)].as_ref())
47    /// );
48    /// ```
49    #[must_use]
50    #[inline]
51    pub const fn from_u64(v: u64) -> Self {
52        Self(v)
53    }
54
55    /// Returns the inner [u64]
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// use open_pql::{Card, Card64, Rank::*, Suit::*};
61    ///
62    /// let i: u64 = 0b11;
63    /// let c64: Card64 = Card64::from_u64(i);
64    ///
65    /// assert_eq!(i, c64.to_u64());
66    /// ```
67    #[must_use]
68    #[inline]
69    pub const fn to_u64(self) -> u64 {
70        self.0
71    }
72
73    /// Constructs an empty [Card64]
74    ///
75    /// # Examples
76    ///
77    /// ```
78    /// use open_pql::{Card, Card64, Rank::*, Suit::*};
79    ///
80    /// let c64: Card64 = Card64::empty();
81    ///
82    /// assert_eq!(c64, Card64::from([].as_ref()));
83    /// ```
84    #[must_use]
85    #[inline]
86    pub const fn empty() -> Self {
87        Self(0)
88    }
89
90    /// Checks whether all rank masks are unset
91    ///
92    /// # Examples
93    ///
94    /// ```
95    /// use open_pql::{Card, Card64, Rank::*, Suit::*};
96    ///
97    /// let c64: Card64 = Card64::from(Card::new(R2, S));
98    ///
99    /// assert!(!c64.is_empty());
100    /// ```
101    #[must_use]
102    #[inline]
103    pub const fn is_empty(self) -> bool {
104        self.0 == 0
105    }
106
107    /// Constructs [Card64] as the set of all 52 cards
108    ///
109    /// # Examples
110    ///
111    /// ```
112    /// use open_pql::{Card, Card64, Rank::*, Suit::*};
113    ///
114    /// let c64: Card64 = Card64::all();
115    ///
116    /// assert_eq!(c64.count(), 52);
117    /// ```
118    #[must_use]
119    #[inline]
120    pub const fn all() -> Self {
121        Self(MASK64_ALL)
122    }
123
124    /// checks whether another [Card64] is a subset
125    ///
126    /// # Examples
127    ///
128    /// ```
129    /// use open_pql::{Card, Card64, Rank::*, Suit::*};
130    ///
131    /// let c64_2s: Card64 = Card64::from(Card::new(R2, S));
132    /// let c64_2h: Card64 = Card64::from(Card::new(R2, H));
133    /// let c64_2s_2h: Card64 = c64_2s | c64_2h;
134    ///
135    /// assert!(c64_2s_2h.contains(c64_2h));
136    /// assert!(!c64_2s.contains(c64_2h));
137    /// ```
138    #[must_use]
139    #[inline]
140    pub fn contains(self, other: Self) -> bool {
141        other & self == other
142    }
143
144    /// checks whether a [Card] is in the set
145    ///
146    /// # Examples
147    ///
148    /// ```
149    /// use open_pql::{Card, Card64, Rank::*, Suit::*};
150    ///
151    /// let c64: Card64 = Card64::from(Card::new(R2, S));
152    ///
153    /// assert!(c64.contains_card(Card::new(R2, S)));
154    /// assert!(!c64.contains_card(Card::new(R2, H)));
155    /// ```
156    #[must_use]
157    #[inline]
158    pub const fn contains_card(self, c: Card) -> bool {
159        let v = Self::u64_from_ranksuit_i8(c.rank as i8, c.suit as i8);
160        v & self.0 == v
161    }
162
163    /// Marks a [Card]
164    ///
165    /// # Examples
166    ///
167    /// ```
168    /// use open_pql::{Card, Card64, Rank::*, Suit::*};
169    ///
170    /// let mut c64: Card64 = Card64::empty();
171    /// c64.set(Card::new(R2, S));
172    ///
173    /// assert_eq!(c64, Card64::from(Card::new(R2, S)));
174    /// ```
175    #[inline]
176    pub const fn set(&mut self, c: Card) {
177        self.0 |= Self::u64_from_ranksuit_i8(c.rank as i8, c.suit as i8);
178    }
179
180    /// Unmarks a [Card]
181    ///
182    /// # Examples
183    ///
184    /// ```
185    /// use open_pql::{Card, Card64, Rank::*, Suit::*};
186    ///
187    /// let mut c64: Card64 = Card64::from(Card::new(R2, S));
188    /// c64.unset(Card::new(R2, S));
189    ///
190    /// assert_eq!(c64, Card64::empty());
191    /// ```
192    #[inline]
193    pub const fn unset(&mut self, c: Card) {
194        self.0 &= !Self::u64_from_ranksuit_i8(c.rank as i8, c.suit as i8);
195    }
196
197    // /// Marks three Flop [Card]s
198    // #[inline]
199    // pub fn set_flop(&mut self, cs: Flop2) {
200    //     todo!()
201    // }
202
203    // /// Marks five Board [Card]s
204    // #[inline]
205    // pub fn set_board(&mut self, b: Board2) {
206    //     todo!()
207    // }
208
209    /// Returns the number of marked cards
210    ///
211    /// # Examples
212    ///
213    /// ```
214    /// use open_pql::{Card, Card64, Rank::*, Suit::*};
215    ///
216    /// let c64: Card64 = Card64::from(Card::new(R2, S));
217    ///
218    /// assert_eq!(c64.count(), 1);
219    /// ```
220    #[must_use]
221    #[inline]
222    pub const fn count(&self) -> PQLCardCount {
223        self.0.count_ones().to_le_bytes()[0]
224    }
225
226    /// Returns the number of marked cards of rank r
227    ///
228    /// # Examples
229    ///
230    /// ```
231    /// use open_pql::{Card, Card64, Rank::*, Suit::*};
232    ///
233    /// let c64: Card64 = Card64::all();
234    ///
235    /// assert_eq!(c64.count_by_rank(RA), 4);
236    /// ```
237    pub const fn count_by_rank(self, r: Rank) -> PQLCardCount {
238        (self.0 & MASK64_2 << r as u8).count_ones().to_le_bytes()[0]
239    }
240
241    /// Returns the number of marked cards of suit s
242    ///
243    /// # Examples
244    ///
245    /// ```
246    /// use open_pql::{Card, Card64, Rank::*, Suit::*};
247    ///
248    /// let c64: Card64 = Card64::all();
249    ///
250    /// assert_eq!(c64.count_by_suit(D), 13);
251    /// ```
252    pub const fn count_by_suit(self, s: Suit) -> PQLCardCount {
253        #[inline]
254        const fn count_ones(v: u8) -> u8 {
255            v.count_ones().to_le_bytes()[0]
256        }
257
258        let bytes = self.to_u64().to_le_bytes();
259
260        match s {
261            Suit::S => count_ones(bytes[0]) + count_ones(bytes[1]),
262            Suit::H => count_ones(bytes[2]) + count_ones(bytes[3]),
263            Suit::D => count_ones(bytes[4]) + count_ones(bytes[5]),
264            Suit::C => count_ones(bytes[6]) + count_ones(bytes[7]),
265        }
266    }
267
268    pub(crate) const fn u64_from_ranksuit_i8(r: i8, s: i8) -> u64 {
269        1 << r << (s * OFFSET_SUIT)
270    }
271
272    //pub(crate) fn set_cards(&mut self, cs: &[Card]) {
273    //    for c in cs {
274    //        self.set(*c);
275    //    }
276    //}
277
278    /// Attempts to mark a card of rank r in the order S, H, D, C
279    ///
280    /// # Examples
281    ///
282    /// ```
283    /// use open_pql::{Card, Card64, Rank::*, Suit::*};
284    ///
285    /// let mut c64: Card64 = Card64::from(Card::new(R2, S));
286    ///
287    /// c64.set_available_card_by_rank(R2);
288    ///
289    /// assert!(c64.contains_card(Card::new(R2, H)));
290    /// ```
291    #[inline]
292    pub fn set_available_card_by_rank(&mut self, r: Rank) {
293        for s in Suit::ARR_ALL {
294            let c = Card::new(r, s);
295
296            if !self.contains_card(c) {
297                return self.set(c);
298            }
299        }
300    }
301
302    /// Normalize u64 so that each u16 indicates rank count
303    ///
304    /// # Examples
305    ///
306    /// ```
307    /// use open_pql::{Card, Card64, Rank::*, Suit::*};
308    ///
309    /// let mut c64: Card64 =
310    ///     Card64::from([Card::new(R2, D), Card::new(R2, C)].as_ref());
311    ///
312    /// c64.normalize();
313    ///
314    /// assert_eq!(
315    ///     Card64::from([Card::new(R2, S), Card::new(R2, H)].as_ref()),
316    ///     c64
317    /// );
318    /// ```
319    #[inline]
320    pub const fn normalize(&mut self) {
321        self.0 = u64::from_le_bytes(prim::normalize_u64(self.0));
322    }
323
324    #[inline]
325    pub const fn ranks_by_suit(self, s: Suit) -> Rank16 {
326        let bytes = self.0.to_le_bytes();
327
328        match s {
329            Suit::S => {
330                Rank16::from_u16(u16::from_le_bytes([bytes[0], bytes[1]]))
331            }
332            Suit::H => {
333                Rank16::from_u16(u16::from_le_bytes([bytes[2], bytes[3]]))
334            }
335            Suit::D => {
336                Rank16::from_u16(u16::from_le_bytes([bytes[4], bytes[5]]))
337            }
338            Suit::C => {
339                Rank16::from_u16(u16::from_le_bytes([bytes[6], bytes[7]]))
340            }
341        }
342    }
343
344    #[inline]
345    #[must_use]
346    pub const fn from_ranks(rs: Rank16) -> Self {
347        let v = rs.to_u16() as u64;
348
349        Self(v << OFFSET_S | v << OFFSET_H | v << OFFSET_D | v << OFFSET_C)
350    }
351
352    #[inline]
353    #[must_use]
354    pub const fn ranks(self) -> Rank16 {
355        let arr = self.0.to_le_bytes();
356
357        let lo = arr[0] | arr[2] | arr[4] | arr[6];
358        let hi = arr[1] | arr[3] | arr[5] | arr[7];
359
360        Rank16::from_u16(u16::from_le_bytes([lo, hi]))
361    }
362
363    pub const fn iter(self) -> CardIter {
364        CardIter::new(self)
365    }
366
367    pub const fn iter_ranks(self) -> RanksIter {
368        RanksIter::new(self)
369    }
370}
371
372#[derive(Debug, Clone)]
373pub struct RanksIter {
374    c64: Card64,
375    suit_idx: u8,
376}
377
378impl RanksIter {
379    pub const fn new(c64: Card64) -> Self {
380        Self { c64, suit_idx: 0 }
381    }
382}
383
384impl Iterator for RanksIter {
385    type Item = (Rank16, Suit);
386
387    fn next(&mut self) -> Option<Self::Item> {
388        let suit = match self.suit_idx {
389            0 => Suit::S,
390            1 => Suit::H,
391            2 => Suit::D,
392            3 => Suit::C,
393            _ => return None,
394        };
395
396        self.suit_idx += 1;
397
398        Some((self.c64.ranks_by_suit(suit), suit))
399    }
400}
401
402#[derive(Debug, Clone)]
403pub struct CardIter {
404    c64: Card64,
405    idx: u8,
406}
407
408impl CardIter {
409    pub const fn new(c64: Card64) -> Self {
410        Self { c64, idx: 0 }
411    }
412}
413
414impl Iterator for CardIter {
415    type Item = Card;
416
417    fn next(&mut self) -> Option<Self::Item> {
418        while self.idx < N_CARDS {
419            let c = Card::ARR_ALL[self.idx as usize];
420            self.idx += 1;
421
422            if self.c64.contains_card(c) {
423                return Some(c);
424            }
425        }
426
427        None
428    }
429}
430
431impl Not for Card64 {
432    type Output = Self;
433
434    fn not(self) -> Self::Output {
435        Self(!self.0 & MASK64_ALL)
436    }
437}
438
439impl fmt::Debug for Card64 {
440    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
441        #[inline]
442        fn to_s(v: u16) -> String {
443            let s = u16_to_rank_str(v);
444            if s.is_empty() { "_".into() } else { s }
445        }
446
447        #[inline]
448        const fn truncate_i8(v: usize) -> i8 {
449            i8::from_le_bytes([v.to_le_bytes()[0]])
450        }
451
452        let n = self.0.count_ones();
453
454        if n == 1 {
455            for (sv, s) in SUIT_NAMES.iter().enumerate() {
456                for (rv, r) in RANK_NAMES.iter().enumerate() {
457                    if self.0
458                        == Self::u64_from_ranksuit_i8(
459                            truncate_i8(rv),
460                            truncate_i8(sv),
461                        )
462                    {
463                        return f.write_str(&format!("Card64<{r}{s}>"));
464                    }
465                }
466            }
467        }
468
469        let bs = self.0.to_le_bytes();
470
471        f.debug_tuple("Card64")
472            .field(&format_args!(
473                "{}",
474                to_s(u16::from_le_bytes([bs[0], bs[1]]))
475            ))
476            .field(&format_args!(
477                "{}",
478                to_s(u16::from_le_bytes([bs[2], bs[3]]))
479            ))
480            .field(&format_args!(
481                "{}",
482                to_s(u16::from_le_bytes([bs[4], bs[5]]))
483            ))
484            .field(&format_args!(
485                "{}",
486                to_s(u16::from_le_bytes([bs[6], bs[7]]))
487            ))
488            .finish()
489    }
490}
491
492impl From<&[Card]> for Card64 {
493    fn from(cs: &[Card]) -> Self {
494        let mut res = Self::empty();
495
496        for c in cs {
497            res.0 |= Self::u64_from_ranksuit_i8(c.rank as i8, c.suit as i8);
498        }
499
500        res
501    }
502}
503
504impl From<Card> for Card64 {
505    fn from(c: Card) -> Self {
506        Self::from_u64(Self::u64_from_ranksuit_i8(c.rank as i8, c.suit as i8))
507    }
508}
509
510#[cfg(test)]
511mod tests {
512    use quickcheck::{Arbitrary, TestResult};
513
514    use super::*;
515
516    impl Arbitrary for Card64 {
517        fn arbitrary(g: &mut quickcheck::Gen) -> Self {
518            let inner = u64::arbitrary(g);
519
520            Self(MASK64_ALL & inner)
521        }
522    }
523
524    #[test]
525    fn test_empty() {
526        assert_eq!(Card64::empty(), Card64(0));
527        assert!(Card64::empty().is_empty());
528        assert!(!Card64(1).is_empty());
529    }
530
531    #[quickcheck]
532    fn test_all(c: Card) {
533        let all = Card64::all();
534
535        assert!(all.contains_card(c));
536    }
537
538    #[quickcheck]
539    fn test_u64(i: u64) -> TestResult {
540        if i & MASK64_ALL != i {
541            return TestResult::discard();
542        }
543
544        assert_eq!(Card64(i), Card64::from_u64(i));
545        assert_eq!(i, Card64(i).to_u64());
546
547        TestResult::passed()
548    }
549
550    #[quickcheck]
551    fn test_set_and_contains_card(c1: Card, c2: Card) {
552        let mut c64 = Card64::empty();
553        c64.set(c1);
554        c64.set(c2);
555
556        assert!(c64.contains_card(c1));
557        assert!(c64.contains_card(c2));
558
559        c64.unset(c1);
560
561        assert!(!c64.contains_card(c1));
562        assert_eq!(c64.contains_card(c2), c2 != c1);
563    }
564
565    //#[quickcheck]
566    //fn test_set_flop_and_board(b: Board2) -> TestResult {
567    //if !board_distinct(b) {
568    //    return TestResult::discard();
569    //}
570
571    //let mut flop = Card64::empty();
572
573    //flop.set_flop(b.0);
574    //assert!(flop.contains_card(b.0 .0));
575    //assert!(flop.contains_card(b.0 .1));
576    //assert!(flop.contains_card(b.0 .2));
577
578    //let mut board = Card64::empty();
579
580    //board.set_board(b);
581    //assert!(board.contains_card(b.0 .0));
582    //assert!(board.contains_card(b.0 .1));
583    //assert!(board.contains_card(b.0 .2));
584    //assert!(board.contains_card(b.1));
585    //assert!(board.contains_card(b.2));
586
587    //assert!(board.contains(flop));
588
589    //TestResult::passed()
590    //}
591
592    //#[quickcheck]
593    //fn test_set_cards(cards: (Card, Card, Card, Card)) {
594    //    let mut lhs = Card64::empty();
595    //    lhs.set_cards([cards.0, cards.1, cards.2, cards.3].as_ref());
596
597    //    let mut rhs = Card64::empty();
598    //    rhs.set(cards.0);
599    //    rhs.set(cards.1);
600    //    rhs.set(cards.2);
601    //    rhs.set(cards.3);
602
603    //    assert_eq!(lhs, rhs);
604    //}
605
606    #[quickcheck]
607    fn test_from_card(c1: Card, c2: Card) {
608        let cards = Card64::from(c1);
609
610        assert!(cards.contains_card(c1));
611
612        let cards = Card64::from([c1, c2].as_ref());
613
614        assert!(cards.contains_card(c1));
615        assert!(cards.contains_card(c2));
616    }
617
618    #[quickcheck]
619    fn test_bit_not(c: Card) {
620        let c64 = Card64::from(c);
621        let c64_complement = !c64;
622
623        assert!(c64.contains_card(c));
624        assert!(!c64_complement.contains_card(c));
625        assert_eq!(c64 | c64_complement, Card64::all());
626        assert_eq!(c64, !c64_complement);
627    }
628
629    #[quickcheck]
630    fn test_bit_and(c1: Card, c2: Card) {
631        let mut a = Card64::from(c1);
632        let b = Card64::from(c2);
633
634        assert_eq!((a & b).is_empty(), c1 != c2);
635
636        a &= Card64::empty();
637
638        assert_eq!(a, Card64::empty());
639    }
640
641    #[quickcheck]
642    fn test_bit_or(c1: Card, c2: Card) {
643        let mut a = Card64::from(c1);
644        let b = Card64::from(c2);
645
646        assert!((a | b).contains_card(c1));
647        assert!((a | b).contains_card(c2));
648
649        a |= Card64::all();
650
651        assert_eq!(a, Card64::all());
652    }
653
654    #[quickcheck]
655    fn test_count(c1: Card, c2: Card) {
656        let c = Card64::from([c1, c2].as_ref());
657
658        let count = if c1 == c2 { 1 } else { 2 };
659
660        assert_eq!(count, c.count());
661    }
662
663    #[quickcheck]
664    fn test_count_by_rank(cards: CardN<20>) -> TestResult {
665        let c: Card64 = cards.clone().into();
666
667        for r in Rank::ARR_ALL {
668            let count = cards.as_ref().iter().filter(|c| c.rank == r).count();
669
670            assert_eq!(count, c.count_by_rank(r) as usize);
671        }
672
673        TestResult::passed()
674    }
675
676    #[quickcheck]
677    fn test_count_by_suit(cards: CardN<5>) -> TestResult {
678        let c: Card64 = cards.clone().into();
679
680        for s in Suit::ARR_ALL {
681            let count = cards.as_ref().iter().filter(|c| c.suit == s).count();
682
683            assert_eq!(count, c.count_by_suit(s) as usize);
684        }
685
686        TestResult::passed()
687    }
688
689    #[quickcheck]
690    fn test_set_available_card_by_rank(mut c64: Card64, r: Rank) -> TestResult {
691        let n = c64.count_by_rank(r);
692
693        c64.set_available_card_by_rank(r);
694
695        let m = c64.count_by_rank(r);
696
697        TestResult::from_bool(m == n + 1 || n == 4 && m == 4)
698    }
699
700    #[quickcheck]
701    fn test_normalize(mut c64: Card64) {
702        let rank_count = Rank::ARR_ALL
703            .into_iter()
704            .map(|r| (r, c64.count_by_rank(r)))
705            .collect::<Vec<_>>();
706
707        c64.normalize();
708
709        for (r, count) in rank_count {
710            assert_eq!(c64.contains_card(Card::new(r, Suit::S)), count > 0);
711            assert_eq!(c64.contains_card(Card::new(r, Suit::H)), count > 1);
712            assert_eq!(c64.contains_card(Card::new(r, Suit::D)), count > 2);
713            assert_eq!(c64.contains_card(Card::new(r, Suit::C)), count > 3);
714        }
715    }
716
717    #[quickcheck]
718    fn test_from_ranks_and_ranks(ranks: Rank16) {
719        let c = Card64::from_ranks(ranks);
720
721        for r in Rank::ARR_ALL {
722            if ranks.contains_rank(r) {
723                assert_eq!(4, c.count_by_rank(r));
724            } else {
725                assert_eq!(0, c.count_by_rank(r));
726            }
727        }
728
729        assert_eq!(ranks, c.ranks());
730    }
731
732    #[quickcheck]
733    fn test_contains(c1: Card64, c2: Card64) -> TestResult {
734        let combined = c1 | c2;
735
736        assert!(combined.contains(c1));
737        assert!(combined.contains(c2));
738        assert!(Card64::all().contains(c1));
739
740        if (c1 & c2).is_empty() && !c2.is_empty() {
741            assert!(!c1.contains(c2));
742        }
743
744        TestResult::passed()
745    }
746
747    #[test]
748    fn test_iter() {
749        let empty = Card64::empty();
750        assert_eq!(empty.iter().count(), 0);
751
752        let single = c64!("As");
753        let cards: Vec<Card> = single.iter().collect();
754        assert_eq!(cards.len(), 1);
755        assert_eq!(cards[0], cards!("As")[0]);
756
757        let multiple = c64!("As Kh 2d");
758        let cards: Vec<Card> = multiple.iter().collect();
759        assert_eq!(cards.len(), 3);
760        assert!(cards.contains(&cards!("As")[0]));
761        assert!(cards.contains(&cards!("Kh")[0]));
762        assert!(cards.contains(&cards!("2d")[0]));
763
764        let all = Card64::all();
765        assert_eq!(all.iter().count(), N_CARDS as usize);
766    }
767
768    #[test]
769    fn test_iter_ranks() {
770        let empty = Card64::empty();
771        assert_eq!(empty.iter_ranks().count(), 4);
772
773        let single = c64!("As");
774        let ranks: Vec<(Rank16, Suit)> = single.iter_ranks().collect();
775        assert_eq!(ranks.len(), 4);
776        assert!(ranks[0].0.contains_rank(Rank::RA));
777        assert_eq!(ranks[0].1, Suit::S);
778
779        let same_rank = c64!("As Ah Ad");
780        let ranks: Vec<(Rank16, Suit)> = same_rank.iter_ranks().collect();
781        assert_eq!(ranks.len(), 4);
782        assert!(ranks[0].0.contains_rank(Rank::RA));
783        assert!(ranks[1].0.contains_rank(Rank::RA));
784        assert!(ranks[2].0.contains_rank(Rank::RA));
785        assert!(!ranks[3].0.contains_rank(Rank::RA));
786
787        let multiple = c64!("As Kh 2d");
788        let ranks: Vec<(Rank16, Suit)> = multiple.iter_ranks().collect();
789        assert_eq!(ranks.len(), 4);
790
791        let (spade_ranks, spade) = ranks[0];
792        assert_eq!(spade, Suit::S);
793        assert!(spade_ranks.contains_rank(Rank::RA));
794        assert!(!spade_ranks.contains_rank(Rank::RK));
795        assert!(!spade_ranks.contains_rank(Rank::R2));
796
797        let (heart_ranks, heart) = ranks[1];
798        assert_eq!(heart, Suit::H);
799        assert!(!heart_ranks.contains_rank(Rank::RA));
800        assert!(heart_ranks.contains_rank(Rank::RK));
801        assert!(!heart_ranks.contains_rank(Rank::R2));
802
803        let (diamond_ranks, diamond) = ranks[2];
804        assert_eq!(diamond, Suit::D);
805        assert!(!diamond_ranks.contains_rank(Rank::RA));
806        assert!(!diamond_ranks.contains_rank(Rank::RK));
807        assert!(diamond_ranks.contains_rank(Rank::R2));
808    }
809
810    #[test]
811    fn test_debug() {
812        let s = format!("{:?}", c64!("As"));
813        assert_eq!(s, "Card64<As>");
814
815        let s = format!("{:?}", c64!("As 9h"));
816        assert_eq!(s, "Card64(A, 9, _, _)");
817    }
818}