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]
157 #[inline]
158 pub const fn contains_card(self, c: Card) -> bool {
159 let v = Self::u64_from_ranksuit_i8(c.r as i8, c.s as i8);
160 v & self.0 == v
161 }
162
163 #[inline]
176 pub fn set(&mut self, c: Card) {
177 self.0 |= Self::u64_from_ranksuit_i8(c.r as i8, c.s as i8);
178 }
179
180 #[inline]
193 pub fn unset(&mut self, c: Card) {
194 self.0 &= !Self::u64_from_ranksuit_i8(c.r as i8, c.s 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 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() {
445 "_".into()
446 } else {
447 s
448 }
449 }
450
451 #[inline]
452 const fn truncate_i8(v: usize) -> i8 {
453 i8::from_le_bytes([v.to_le_bytes()[0]])
454 }
455
456 let n = self.0.count_ones();
457
458 if n == 1 {
459 for (sv, s) in SUIT_NAMES.iter().enumerate() {
460 for (rv, r) in RANK_NAMES.iter().enumerate() {
461 if self.0
462 == Self::u64_from_ranksuit_i8(
463 truncate_i8(rv),
464 truncate_i8(sv),
465 )
466 {
467 return f.write_str(&format!("Card64<{r}{s}>"));
468 }
469 }
470 }
471 }
472
473 let bs = self.0.to_le_bytes();
474
475 f.debug_tuple("Card64")
476 .field(&format_args!(
477 "{}",
478 to_s(u16::from_le_bytes([bs[0], bs[1]]))
479 ))
480 .field(&format_args!(
481 "{}",
482 to_s(u16::from_le_bytes([bs[2], bs[3]]))
483 ))
484 .field(&format_args!(
485 "{}",
486 to_s(u16::from_le_bytes([bs[4], bs[5]]))
487 ))
488 .field(&format_args!(
489 "{}",
490 to_s(u16::from_le_bytes([bs[6], bs[7]]))
491 ))
492 .finish()
493 }
494}
495
496impl From<&[Card]> for Card64 {
497 fn from(cs: &[Card]) -> Self {
498 let mut res = Self::empty();
499
500 for c in cs {
501 res.0 |= Self::u64_from_ranksuit_i8(c.r as i8, c.s as i8);
502 }
503
504 res
505 }
506}
507
508impl From<Card> for Card64 {
509 fn from(c: Card) -> Self {
510 Self::from_u64(Self::u64_from_ranksuit_i8(c.r as i8, c.s as i8))
511 }
512}
513
514#[cfg_attr(coverage_nightly, coverage(off))]
515#[cfg(test)]
516mod tests {
517 use quickcheck::{Arbitrary, TestResult};
518
519 use super::*;
520
521 impl Arbitrary for Card64 {
522 fn arbitrary(g: &mut quickcheck::Gen) -> Self {
523 let inner = u64::arbitrary(g);
524
525 Self(MASK64_ALL & inner)
526 }
527 }
528
529 #[test]
530 fn test_empty() {
531 assert_eq!(Card64::empty(), Card64(0));
532 assert!(Card64::empty().is_empty());
533 assert!(!Card64(1).is_empty());
534 }
535
536 #[quickcheck]
537 fn test_all(c: Card) {
538 let all = Card64::all();
539
540 assert!(all.contains_card(c));
541 }
542
543 #[quickcheck]
544 fn test_u64(i: u64) -> TestResult {
545 if i & MASK64_ALL != i {
546 return TestResult::discard();
547 }
548
549 assert_eq!(Card64(i), Card64::from_u64(i));
550 assert_eq!(i, Card64(i).to_u64());
551
552 TestResult::passed()
553 }
554
555 #[quickcheck]
556 fn test_set_and_contains_card(c1: Card, c2: Card) {
557 let mut c64 = Card64::empty();
558 c64.set(c1);
559 c64.set(c2);
560
561 assert!(c64.contains_card(c1));
562 assert!(c64.contains_card(c2));
563
564 c64.unset(c1);
565
566 assert!(!c64.contains_card(c1));
567 assert_eq!(c64.contains_card(c2), c2 != c1);
568 }
569
570 #[quickcheck]
612 fn test_from_card(c1: Card, c2: Card) {
613 let cards = Card64::from(c1);
614
615 assert!(cards.contains_card(c1));
616
617 let cards = Card64::from([c1, c2].as_ref());
618
619 assert!(cards.contains_card(c1));
620 assert!(cards.contains_card(c2));
621 }
622
623 #[quickcheck]
624 fn test_bit_not(c: Card) {
625 let c64 = Card64::from(c);
626 let c64_complement = !c64;
627
628 assert!(c64.contains_card(c));
629 assert!(!c64_complement.contains_card(c));
630 assert_eq!(c64 | c64_complement, Card64::all());
631 assert_eq!(c64, !c64_complement);
632 }
633
634 #[quickcheck]
635 fn test_bit_and(c1: Card, c2: Card) {
636 let mut a = Card64::from(c1);
637 let b = Card64::from(c2);
638
639 assert_eq!((a & b).is_empty(), c1 != c2);
640
641 a &= Card64::empty();
642
643 assert_eq!(a, Card64::empty());
644 }
645
646 #[quickcheck]
647 fn test_bit_or(c1: Card, c2: Card) {
648 let mut a = Card64::from(c1);
649 let b = Card64::from(c2);
650
651 assert!((a | b).contains_card(c1));
652 assert!((a | b).contains_card(c2));
653
654 a |= Card64::all();
655
656 assert_eq!(a, Card64::all());
657 }
658
659 #[quickcheck]
660 fn test_count(c1: Card, c2: Card) {
661 let c = Card64::from([c1, c2].as_ref());
662
663 let count = if c1 == c2 { 1 } else { 2 };
664
665 assert_eq!(count, c.count());
666 }
667
668 #[quickcheck]
669 fn test_count_by_rank(cards: CardN<20>) -> TestResult {
670 let c: Card64 = cards.clone().into();
671
672 for r in Rank::ARR_ALL {
673 let count = cards.as_ref().iter().filter(|c| c.r == r).count();
674
675 assert_eq!(count, c.count_by_rank(r) as usize);
676 }
677
678 TestResult::passed()
679 }
680
681 #[quickcheck]
682 fn test_count_by_suit(cards: CardN<5>) -> TestResult {
683 let c: Card64 = cards.clone().into();
684
685 for s in Suit::ARR_ALL {
686 let count = cards.as_ref().iter().filter(|c| c.s == s).count();
687
688 assert_eq!(count, c.count_by_suit(s) as usize);
689 }
690
691 TestResult::passed()
692 }
693
694 #[quickcheck]
695 fn test_set_available_card_by_rank(mut c64: Card64, r: Rank) -> TestResult {
696 let n = c64.count_by_rank(r);
697
698 c64.set_available_card_by_rank(r);
699
700 let m = c64.count_by_rank(r);
701
702 TestResult::from_bool(m == n + 1 || n == 4 && m == 4)
703 }
704
705 #[quickcheck]
706 fn test_normalize(mut c64: Card64) {
707 let rank_count = Rank::ARR_ALL
708 .into_iter()
709 .map(|r| (r, c64.count_by_rank(r)))
710 .collect::<Vec<_>>();
711
712 c64.normalize();
713
714 for (r, count) in rank_count {
715 assert_eq!(c64.contains_card(Card::new(r, Suit::S)), count > 0);
716 assert_eq!(c64.contains_card(Card::new(r, Suit::H)), count > 1);
717 assert_eq!(c64.contains_card(Card::new(r, Suit::D)), count > 2);
718 assert_eq!(c64.contains_card(Card::new(r, Suit::C)), count > 3);
719 }
720 }
721
722 #[quickcheck]
723 fn test_from_ranks_and_ranks(ranks: Rank16) {
724 let c = Card64::from_ranks(ranks);
725
726 for r in Rank::ARR_ALL {
727 if ranks.contains_rank(r) {
728 assert_eq!(4, c.count_by_rank(r));
729 } else {
730 assert_eq!(0, c.count_by_rank(r));
731 }
732 }
733
734 assert_eq!(ranks, c.ranks());
735 }
736
737 #[test]
738 fn test_debug() {
739 let s = format!("{:?}", c64!("As"));
740 assert_eq!(s, "Card64<As>");
741
742 let s = format!("{:?}", c64!("As 9h"));
743 assert_eq!(s, "Card64(A, 9, _, _)");
744 }
745}