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#[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 #[must_use]
50 #[inline]
51 pub const fn from_u64(v: u64) -> Self {
52 Self(v)
53 }
54
55 #[must_use]
68 #[inline]
69 pub const fn to_u64(self) -> u64 {
70 self.0
71 }
72
73 #[must_use]
85 #[inline]
86 pub const fn empty() -> Self {
87 Self(0)
88 }
89
90 #[must_use]
102 #[inline]
103 pub const fn is_empty(self) -> bool {
104 self.0 == 0
105 }
106
107 #[must_use]
119 #[inline]
120 pub const fn all() -> Self {
121 Self(MASK64_ALL)
122 }
123
124 #[must_use]
139 #[inline]
140 pub fn contains(self, other: Self) -> bool {
141 other & self == other
142 }
143
144 #[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 #[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 #[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 #[must_use]
221 #[inline]
222 pub const fn count(&self) -> PQLCardCount {
223 self.0.count_ones().to_le_bytes()[0]
224 }
225
226 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 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 #[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 #[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]
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}