1use super::{
2 BitAnd, BitAndAssign, BitOr, BitOrAssign, Card, CardIter, Hash, MASK64_2,
3 MASK64_ALL, Not, OFFSET_C, OFFSET_D, OFFSET_H, OFFSET_S, OFFSET_SUIT,
4 PQLCardCount, RANK_NAMES, Rank, Rank16, Rank16Iter, SUIT_NAMES, Suit, fmt,
5 prim, u16_to_rank_str,
6};
7
8#[cfg(any(test, feature = "benchmark"))]
9#[macro_export]
10macro_rules! c64 {
11 ($s:expr) => {
12 $crate::Card64::from($crate::cards![$s].as_ref())
13 };
14}
15
16#[derive(
31 Copy,
32 Clone,
33 PartialEq,
34 Eq,
35 Hash,
36 BitAnd,
37 BitAndAssign,
38 BitOr,
39 BitOrAssign,
40 Default,
41)]
42pub struct Card64(u64);
43
44impl Card64 {
45 #[must_use]
61 #[inline]
62 pub const fn from_u64(v: u64) -> Self {
63 Self(v)
64 }
65
66 #[must_use]
79 #[inline]
80 pub const fn to_u64(self) -> u64 {
81 self.0
82 }
83
84 #[must_use]
96 #[inline]
97 pub const fn is_empty(self) -> bool {
98 self.0 == 0
99 }
100
101 #[must_use]
113 #[inline]
114 pub const fn all() -> Self {
115 Self(MASK64_ALL)
116 }
117
118 #[must_use]
133 #[inline]
134 pub fn contains(self, other: Self) -> bool {
135 other & self == other
136 }
137
138 #[must_use]
151 #[inline]
152 pub const fn contains_card(self, c: Card) -> bool {
153 let v = Self::u64_from_ranksuit_i8(c.rank as i8, c.suit as i8);
154 v & self.0 == v
155 }
156
157 #[inline]
170 pub const fn set(&mut self, c: Card) {
171 self.0 |= Self::u64_from_ranksuit_i8(c.rank as i8, c.suit as i8);
172 }
173
174 #[inline]
187 pub const fn unset(&mut self, c: Card) {
188 self.0 &= !Self::u64_from_ranksuit_i8(c.rank as i8, c.suit as i8);
189 }
190
191 #[must_use]
215 #[inline]
216 pub const fn count(&self) -> PQLCardCount {
217 self.0.count_ones().to_le_bytes()[0]
218 }
219
220 pub const fn count_by_rank(self, r: Rank) -> PQLCardCount {
232 (self.0 & MASK64_2 << r as u8).count_ones().to_le_bytes()[0]
233 }
234
235 pub const fn count_by_suit(self, s: Suit) -> PQLCardCount {
247 #[inline]
248 const fn count_ones(v: u8) -> u8 {
249 v.count_ones().to_le_bytes()[0]
250 }
251
252 let bytes = self.to_u64().to_le_bytes();
253
254 match s {
255 Suit::S => count_ones(bytes[0]) + count_ones(bytes[1]),
256 Suit::H => count_ones(bytes[2]) + count_ones(bytes[3]),
257 Suit::D => count_ones(bytes[4]) + count_ones(bytes[5]),
258 Suit::C => count_ones(bytes[6]) + count_ones(bytes[7]),
259 }
260 }
261
262 pub(crate) const fn u64_from_ranksuit_i8(r: i8, s: i8) -> u64 {
263 1 << r << (s * OFFSET_SUIT)
264 }
265
266 #[allow(unused)]
268 #[inline]
269 pub(crate) fn set_available_card_by_rank(&mut self, r: Rank) {
270 for s in Suit::ARR_ALL {
271 let c = Card::new(r, s);
272
273 if !self.contains_card(c) {
274 return self.set(c);
275 }
276 }
277 }
278
279 #[allow(unused)]
281 #[inline]
282 pub(crate) const fn normalize(&mut self) {
283 self.0 = u64::from_le_bytes(prim::normalize_u64(self.0));
284 }
285
286 #[inline]
287 pub(crate) const fn ranks_by_suit(self, s: Suit) -> Rank16 {
288 let bytes = self.0.to_le_bytes();
289
290 match s {
291 Suit::S => {
292 Rank16::from_u16(u16::from_le_bytes([bytes[0], bytes[1]]))
293 }
294 Suit::H => {
295 Rank16::from_u16(u16::from_le_bytes([bytes[2], bytes[3]]))
296 }
297 Suit::D => {
298 Rank16::from_u16(u16::from_le_bytes([bytes[4], bytes[5]]))
299 }
300 Suit::C => {
301 Rank16::from_u16(u16::from_le_bytes([bytes[6], bytes[7]]))
302 }
303 }
304 }
305
306 #[inline]
321 #[must_use]
322 pub const fn from_ranks(rs: Rank16) -> Self {
323 let v = rs.to_u16() as u64;
324
325 Self(v << OFFSET_S | v << OFFSET_H | v << OFFSET_D | v << OFFSET_C)
326 }
327
328 #[inline]
343 #[must_use]
344 pub const fn ranks(self) -> Rank16 {
345 let arr = self.0.to_le_bytes();
346
347 let lo = arr[0] | arr[2] | arr[4] | arr[6];
348 let hi = arr[1] | arr[3] | arr[5] | arr[7];
349
350 Rank16::from_u16(u16::from_le_bytes([lo, hi]))
351 }
352
353 pub const fn iter(self) -> CardIter {
366 CardIter::new(self)
367 }
368
369 pub const fn iter_ranks(self) -> Rank16Iter {
386 Rank16Iter::new(self)
387 }
388}
389
390impl Not for Card64 {
391 type Output = Self;
392
393 fn not(self) -> Self::Output {
394 Self(!self.0 & MASK64_ALL)
395 }
396}
397
398impl fmt::Debug for Card64 {
399 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400 #[inline]
401 fn to_s(v: u16) -> String {
402 let s = u16_to_rank_str(v);
403 if s.is_empty() { "_".into() } else { s }
404 }
405
406 #[inline]
407 const fn truncate_i8(v: usize) -> i8 {
408 i8::from_le_bytes([v.to_le_bytes()[0]])
409 }
410
411 let n = self.0.count_ones();
412
413 if n == 1 {
414 for (sv, s) in SUIT_NAMES.iter().enumerate() {
415 for (rv, r) in RANK_NAMES.iter().enumerate() {
416 if self.0
417 == Self::u64_from_ranksuit_i8(
418 truncate_i8(rv),
419 truncate_i8(sv),
420 )
421 {
422 return f.write_str(&format!("Card64<{r}{s}>"));
423 }
424 }
425 }
426 }
427
428 let bs = self.0.to_le_bytes();
429
430 f.debug_tuple("Card64")
431 .field(&format_args!(
432 "{}",
433 to_s(u16::from_le_bytes([bs[0], bs[1]]))
434 ))
435 .field(&format_args!(
436 "{}",
437 to_s(u16::from_le_bytes([bs[2], bs[3]]))
438 ))
439 .field(&format_args!(
440 "{}",
441 to_s(u16::from_le_bytes([bs[4], bs[5]]))
442 ))
443 .field(&format_args!(
444 "{}",
445 to_s(u16::from_le_bytes([bs[6], bs[7]]))
446 ))
447 .finish()
448 }
449}
450
451impl From<&[Card]> for Card64 {
452 fn from(cs: &[Card]) -> Self {
453 let mut res = Self::default();
454
455 for c in cs {
456 res.0 |= Self::u64_from_ranksuit_i8(c.rank as i8, c.suit as i8);
457 }
458
459 res
460 }
461}
462
463impl From<Card> for Card64 {
464 fn from(c: Card) -> Self {
465 Self::from_u64(Self::u64_from_ranksuit_i8(c.rank as i8, c.suit as i8))
466 }
467}
468
469#[cfg(test)]
470mod tests {
471 use super::*;
472 use crate::*;
473
474 impl Arbitrary for Card64 {
475 fn arbitrary(g: &mut quickcheck::Gen) -> Self {
476 let inner = u64::arbitrary(g);
477
478 Self(MASK64_ALL & inner)
479 }
480 }
481
482 #[test]
483 fn test_empty() {
484 assert_eq!(Card64::default(), Card64(0));
485 assert!(Card64::default().is_empty());
486 assert!(!Card64(1).is_empty());
487 }
488
489 #[quickcheck]
490 fn test_all(c: Card) {
491 let all = Card64::all();
492
493 assert!(all.contains_card(c));
494 }
495
496 #[quickcheck]
497 fn test_u64(i: u64) -> TestResult {
498 if i & MASK64_ALL != i {
499 return TestResult::discard();
500 }
501
502 assert_eq!(Card64(i), Card64::from_u64(i));
503 assert_eq!(i, Card64(i).to_u64());
504
505 TestResult::passed()
506 }
507
508 #[quickcheck]
509 fn test_set_and_contains_card(c1: Card, c2: Card) {
510 let mut c64 = Card64::default();
511 c64.set(c1);
512 c64.set(c2);
513
514 assert!(c64.contains_card(c1));
515 assert!(c64.contains_card(c2));
516
517 c64.unset(c1);
518
519 assert!(!c64.contains_card(c1));
520 assert_eq!(c64.contains_card(c2), c2 != c1);
521 }
522
523 #[quickcheck]
565 fn test_from_card(c1: Card, c2: Card) {
566 let cards = Card64::from(c1);
567
568 assert!(cards.contains_card(c1));
569
570 let cards = Card64::from([c1, c2].as_ref());
571
572 assert!(cards.contains_card(c1));
573 assert!(cards.contains_card(c2));
574 }
575
576 #[quickcheck]
577 fn test_bit_not(c: Card) {
578 let c64 = Card64::from(c);
579 let c64_complement = !c64;
580
581 assert!(c64.contains_card(c));
582 assert!(!c64_complement.contains_card(c));
583 assert_eq!(c64 | c64_complement, Card64::all());
584 assert_eq!(c64, !c64_complement);
585 }
586
587 #[quickcheck]
588 fn test_bit_and(c1: Card, c2: Card) {
589 let mut a = Card64::from(c1);
590 let b = Card64::from(c2);
591
592 assert_eq!((a & b).is_empty(), c1 != c2);
593
594 a &= Card64::default();
595
596 assert_eq!(a, Card64::default());
597 }
598
599 #[quickcheck]
600 fn test_bit_or(c1: Card, c2: Card) {
601 let mut a = Card64::from(c1);
602 let b = Card64::from(c2);
603
604 assert!((a | b).contains_card(c1));
605 assert!((a | b).contains_card(c2));
606
607 a |= Card64::all();
608
609 assert_eq!(a, Card64::all());
610 }
611
612 #[quickcheck]
613 fn test_count(c1: Card, c2: Card) {
614 let c = Card64::from([c1, c2].as_ref());
615
616 let count = if c1 == c2 { 1 } else { 2 };
617
618 assert_eq!(count, c.count());
619 }
620
621 #[quickcheck]
622 fn test_count_by_rank(cards: CardN<20>) -> TestResult {
623 let c: Card64 = cards.clone().into();
624
625 for r in Rank::ARR_ALL {
626 let count = cards.as_ref().iter().filter(|c| c.rank == r).count();
627
628 assert_eq!(count, c.count_by_rank(r) as usize);
629 }
630
631 TestResult::passed()
632 }
633
634 #[quickcheck]
635 fn test_count_by_suit(cards: CardN<5>) -> TestResult {
636 let c: Card64 = cards.clone().into();
637
638 for s in Suit::ARR_ALL {
639 let count = cards.as_ref().iter().filter(|c| c.suit == s).count();
640
641 assert_eq!(count, c.count_by_suit(s) as usize);
642 }
643
644 TestResult::passed()
645 }
646
647 #[quickcheck]
648 fn test_set_available_card_by_rank(mut c64: Card64, r: Rank) -> TestResult {
649 let n = c64.count_by_rank(r);
650
651 c64.set_available_card_by_rank(r);
652
653 let m = c64.count_by_rank(r);
654
655 TestResult::from_bool(m == n + 1 || n == 4 && m == 4)
656 }
657
658 #[quickcheck]
659 fn test_normalize(mut c64: Card64) {
660 let rank_count = Rank::ARR_ALL
661 .into_iter()
662 .map(|r| (r, c64.count_by_rank(r)))
663 .collect::<Vec<_>>();
664
665 c64.normalize();
666
667 for (r, count) in rank_count {
668 assert_eq!(c64.contains_card(Card::new(r, Suit::S)), count > 0);
669 assert_eq!(c64.contains_card(Card::new(r, Suit::H)), count > 1);
670 assert_eq!(c64.contains_card(Card::new(r, Suit::D)), count > 2);
671 assert_eq!(c64.contains_card(Card::new(r, Suit::C)), count > 3);
672 }
673 }
674
675 #[quickcheck]
676 fn test_from_ranks_and_ranks(ranks: Rank16) {
677 let c = Card64::from_ranks(ranks);
678
679 for r in Rank::ARR_ALL {
680 if ranks.contains_rank(r) {
681 assert_eq!(4, c.count_by_rank(r));
682 } else {
683 assert_eq!(0, c.count_by_rank(r));
684 }
685 }
686
687 assert_eq!(ranks, c.ranks());
688 }
689
690 #[quickcheck]
691 fn test_contains(c1: Card64, c2: Card64) -> TestResult {
692 let combined = c1 | c2;
693
694 assert!(combined.contains(c1));
695 assert!(combined.contains(c2));
696 assert!(Card64::all().contains(c1));
697
698 if (c1 & c2).is_empty() && !c2.is_empty() {
699 assert!(!c1.contains(c2));
700 }
701
702 TestResult::passed()
703 }
704
705 #[test]
706 fn test_iter() {
707 let empty = Card64::default();
708 assert_eq!(empty.iter().count(), 0);
709
710 let single = c64!("As");
711 let cards: Vec<Card> = single.iter().collect();
712 assert_eq!(cards.len(), 1);
713 assert_eq!(cards[0], cards!("As")[0]);
714
715 let multiple = c64!("As Kh 2d");
716 let cards: Vec<Card> = multiple.iter().collect();
717 assert_eq!(cards.len(), 3);
718 assert!(cards.contains(&cards!("As")[0]));
719 assert!(cards.contains(&cards!("Kh")[0]));
720 assert!(cards.contains(&cards!("2d")[0]));
721
722 let all = Card64::all();
723 assert_eq!(all.iter().count(), constants::N_CARDS as usize);
724 }
725
726 #[test]
727 fn test_iter_ranks() {
728 let empty = Card64::default();
729 assert_eq!(empty.iter_ranks().count(), 4);
730
731 let single = c64!("As");
732 let ranks: Vec<(Rank16, Suit)> = single.iter_ranks().collect();
733 assert_eq!(ranks.len(), 4);
734 assert!(ranks[0].0.contains_rank(Rank::RA));
735 assert_eq!(ranks[0].1, Suit::S);
736
737 let same_rank = c64!("As Ah Ad");
738 let ranks: Vec<(Rank16, Suit)> = same_rank.iter_ranks().collect();
739 assert_eq!(ranks.len(), 4);
740 assert!(ranks[0].0.contains_rank(Rank::RA));
741 assert!(ranks[1].0.contains_rank(Rank::RA));
742 assert!(ranks[2].0.contains_rank(Rank::RA));
743 assert!(!ranks[3].0.contains_rank(Rank::RA));
744
745 let multiple = c64!("As Kh 2d");
746 let ranks: Vec<(Rank16, Suit)> = multiple.iter_ranks().collect();
747 assert_eq!(ranks.len(), 4);
748
749 let (spade_ranks, spade) = ranks[0];
750 assert_eq!(spade, Suit::S);
751 assert!(spade_ranks.contains_rank(Rank::RA));
752 assert!(!spade_ranks.contains_rank(Rank::RK));
753 assert!(!spade_ranks.contains_rank(Rank::R2));
754
755 let (heart_ranks, heart) = ranks[1];
756 assert_eq!(heart, Suit::H);
757 assert!(!heart_ranks.contains_rank(Rank::RA));
758 assert!(heart_ranks.contains_rank(Rank::RK));
759 assert!(!heart_ranks.contains_rank(Rank::R2));
760
761 let (diamond_ranks, diamond) = ranks[2];
762 assert_eq!(diamond, Suit::D);
763 assert!(!diamond_ranks.contains_rank(Rank::RA));
764 assert!(!diamond_ranks.contains_rank(Rank::RK));
765 assert!(diamond_ranks.contains_rank(Rank::R2));
766 }
767
768 #[test]
769 fn test_debug() {
770 let s = format!("{:?}", c64!("As"));
771 assert_eq!(s, "Card64<As>");
772
773 let s = format!("{:?}", c64!("As 9h"));
774 assert_eq!(s, "Card64(A, 9, _, _)");
775 }
776}