use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
use super::{Card, FlatDeck};
use std::fmt::Debug;
use rand::{Rng, RngExt};
#[cfg(feature = "serde")]
use serde::ser::SerializeSeq;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct CardBitSet {
cards: u64,
}
const FIFTY_TWO_ONES: u64 = (1 << 52) - 1;
#[inline]
pub(crate) fn pdep(val: u64, mask: u64) -> u64 {
#[cfg(all(target_arch = "x86_64", target_feature = "bmi2"))]
{
unsafe {
use core::arch::x86_64::_pdep_u64;
return _pdep_u64(val, mask);
}
}
#[allow(unreachable_code)]
pdep_fallback(val, mask)
}
#[inline]
fn pdep_fallback(mut val: u64, mut mask: u64) -> u64 {
let mut result = 0u64;
while mask != 0 {
let lowest = mask & mask.wrapping_neg();
if val & 1 != 0 {
result |= lowest;
}
val >>= 1;
mask &= mask - 1;
}
result
}
impl CardBitSet {
pub fn new() -> Self {
Self { cards: 0 }
}
pub fn insert(&mut self, card: Card) {
self.cards |= 1 << u8::from(card);
}
pub fn remove(&mut self, card: Card) {
self.cards &= !(1 << u8::from(card));
}
pub fn contains(&self, card: Card) -> bool {
(self.cards & (1 << u8::from(card))) != 0
}
pub fn is_empty(&self) -> bool {
self.cards == 0
}
pub fn count(&self) -> usize {
self.cards.count_ones() as usize
}
pub fn clear(&mut self) {
self.cards = 0;
}
pub(crate) fn from_u64(cards: u64) -> Self {
Self { cards }
}
pub(crate) fn to_u64(self) -> u64 {
self.cards
}
pub fn sample_one<R: Rng>(&self, rng: &mut R) -> Option<Card> {
let count = self.count();
if count == 0 {
return None;
}
let idx = rng.random_range(0..count) as u32;
Some(Card::from(self.nth_set_bit(idx) as u8))
}
#[inline]
fn nth_set_bit(&self, n: u32) -> u32 {
pdep(1u64 << n, self.cards).trailing_zeros()
}
}
impl Default for CardBitSet {
fn default() -> Self {
Self {
cards: FIFTY_TWO_ONES,
}
}
}
impl FromIterator<Card> for CardBitSet {
fn from_iter<I: IntoIterator<Item = Card>>(iter: I) -> Self {
let mut set = Self::new();
for card in iter {
set.insert(card);
}
set
}
}
impl From<FlatDeck> for CardBitSet {
fn from(deck: FlatDeck) -> Self {
deck[..].iter().copied().collect()
}
}
impl From<&FlatDeck> for CardBitSet {
fn from(deck: &FlatDeck) -> Self {
deck[..].iter().copied().collect()
}
}
impl From<CardBitSet> for FlatDeck {
fn from(value: CardBitSet) -> Self {
value.into_iter().collect::<Vec<Card>>().into()
}
}
impl Debug for CardBitSet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_set().entries(*self).finish()
}
}
impl BitOr<CardBitSet> for CardBitSet {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self {
cards: self.cards | rhs.cards,
}
}
}
impl BitOr<Card> for CardBitSet {
type Output = Self;
fn bitor(self, rhs: Card) -> Self::Output {
Self {
cards: self.cards | (1 << u8::from(rhs)),
}
}
}
impl BitOrAssign<CardBitSet> for CardBitSet {
fn bitor_assign(&mut self, rhs: Self) {
self.cards |= rhs.cards;
}
}
impl BitOrAssign<Card> for CardBitSet {
fn bitor_assign(&mut self, rhs: Card) {
self.cards |= 1 << u8::from(rhs);
}
}
impl BitXor for CardBitSet {
type Output = Self;
fn bitxor(self, rhs: Self) -> Self::Output {
Self {
cards: self.cards ^ rhs.cards,
}
}
}
impl BitXor<Card> for CardBitSet {
type Output = Self;
fn bitxor(self, rhs: Card) -> Self::Output {
Self {
cards: self.cards ^ (1 << u8::from(rhs)),
}
}
}
impl BitXorAssign<Card> for CardBitSet {
fn bitxor_assign(&mut self, rhs: Card) {
self.cards ^= 1 << u8::from(rhs);
}
}
impl BitXorAssign<CardBitSet> for CardBitSet {
fn bitxor_assign(&mut self, rhs: Self) {
self.cards ^= rhs.cards;
}
}
impl BitAnd for CardBitSet {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
Self {
cards: self.cards & rhs.cards,
}
}
}
impl BitAndAssign for CardBitSet {
fn bitand_assign(&mut self, rhs: Self) {
self.cards &= rhs.cards;
}
}
impl Not for CardBitSet {
type Output = Self;
fn not(self) -> Self::Output {
Self {
cards: !self.cards & FIFTY_TWO_ONES, }
}
}
pub struct CardBitSetIter(u64);
impl IntoIterator for CardBitSet {
type Item = Card;
type IntoIter = CardBitSetIter;
fn into_iter(self) -> Self::IntoIter {
CardBitSetIter(self.cards)
}
}
impl Iterator for CardBitSetIter {
type Item = Card;
fn next(&mut self) -> Option<Self::Item> {
if self.0 == 0 {
return None;
}
let card = self.0.trailing_zeros();
self.0 &= !(1 << card);
Some(Card::from(card as u8))
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for CardBitSet {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut seq = serializer.serialize_seq(Some(self.count()))?;
for card in (*self).into_iter() {
seq.serialize_element(&card)?;
}
seq.end()
}
}
#[cfg(feature = "serde")]
struct CardBitSetVisitor;
#[cfg(feature = "serde")]
impl<'de> serde::de::Visitor<'de> for CardBitSetVisitor {
type Value = CardBitSet;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a sequence of cards")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut deck = CardBitSet::new();
while let Some(card) = seq.next_element()? {
deck.insert(card);
}
Ok(deck)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for CardBitSet {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_seq(CardBitSetVisitor)
}
}
#[cfg(test)]
mod tests {
use core::panic;
use std::collections::HashSet;
use rand::{SeedableRng, rngs::StdRng};
use crate::core::Deck;
use super::*;
#[test]
fn test_empty() {
let cards = CardBitSet::new();
assert!(cards.is_empty());
}
#[test]
fn test_insert_all() {
let mut all_cards = CardBitSet::new();
for card in Deck::default() {
let mut single_card = CardBitSet::new();
single_card.insert(card);
all_cards |= single_card;
assert!(single_card.contains(card));
}
assert_eq!(all_cards.count(), 52);
for card in Deck::default() {
assert!(all_cards.contains(card));
}
}
#[test]
fn test_xor_is_remove() {
let mut all_cards = CardBitSet::new();
for card in Deck::default() {
all_cards |= card;
}
for card in Deck::default() {
let xor_masked_set: CardBitSet = all_cards ^ card;
assert!(!xor_masked_set.contains(card));
let mut removed_set = all_cards;
removed_set.remove(card);
assert_eq!(removed_set, xor_masked_set);
}
assert_eq!(52, all_cards.count());
}
#[test]
fn test_bit_or() {
let mut cards = CardBitSet::new();
cards.insert(Card::from(17));
cards.insert(Card::from(18));
let mut cards2 = CardBitSet::new();
cards2.insert(Card::from(1));
cards2.insert(Card::from(2));
cards2.insert(Card::from(17));
let or = cards | cards2;
assert_eq!(or.count(), 4);
assert!(or.contains(Card::from(17)));
assert!(or.contains(Card::from(18)));
assert!(or.contains(Card::from(1)));
assert!(or.contains(Card::from(2)));
assert!(!or.is_empty());
}
#[test]
fn test_bit_or_assign() {
let mut cards = CardBitSet::new();
cards.insert(Card::from(17));
cards.insert(Card::from(18));
let mut cards2 = CardBitSet::new();
cards2.insert(Card::from(1));
cards2.insert(Card::from(2));
cards2.insert(Card::from(17));
cards |= cards2;
assert_eq!(cards.count(), 4);
assert!(cards.contains(Card::from(17)));
assert!(cards.contains(Card::from(18)));
assert!(cards.contains(Card::from(1)));
assert!(cards.contains(Card::from(2)));
assert!(!cards.is_empty());
assert_eq!(cards, cards | cards2);
}
#[test]
fn test_remove() {
let mut cards = CardBitSet::new();
cards.insert(Card::from(17));
cards.insert(Card::from(18));
assert!(cards.contains(Card::from(17)));
cards.remove(Card::from(17));
assert!(!cards.contains(Card::from(17)));
assert!(cards.contains(Card::from(18)));
assert_eq!(1, cards.count());
assert!(!cards.is_empty());
cards.remove(Card::from(18));
assert!(!cards.contains(Card::from(18)));
assert!(!cards.contains(Card::from(17)));
assert_eq!(0, cards.count());
}
#[test]
fn test_is_empty() {
let empty = CardBitSet::new();
assert!(empty.is_empty());
}
#[test]
fn test_not_empty() {
let mut cards = CardBitSet::new();
cards.insert(Card::from(17));
assert!(!cards.is_empty());
}
#[test]
fn test_add_cards_iter() {
let mut hash_set: HashSet<Card> = HashSet::new();
let mut bit_set = CardBitSet::new();
let deck = FlatDeck::from(Deck::default());
for card in deck.sample(13) {
hash_set.insert(card);
bit_set.insert(card);
}
assert_eq!(hash_set.len(), bit_set.count());
for card in hash_set.clone() {
assert!(bit_set.contains(card));
}
for card in bit_set {
assert!(hash_set.contains(&card));
}
}
#[test]
fn test_default_contains() {
let mut bitset_cards = CardBitSet::default();
assert_eq!(52, bitset_cards.count());
for card in Deck::default() {
assert!(bitset_cards.contains(card));
bitset_cards.remove(card);
}
assert_eq!(0, bitset_cards.count());
assert!(bitset_cards.is_empty());
}
#[test]
fn test_formatting_cards() {
let mut cards = CardBitSet::new();
cards.insert(Card::new(crate::core::Value::Ace, crate::core::Suit::Club));
cards.insert(Card::new(
crate::core::Value::King,
crate::core::Suit::Diamond,
));
cards.insert(Card::new(
crate::core::Value::Three,
crate::core::Suit::Heart,
));
assert_eq!(format!("{cards:?}"), "{Card(Ac), Card(3h), Card(Kd)}");
}
#[test]
fn test_bit_and() {
let mut cards = CardBitSet::new();
cards.insert(Card::new(crate::core::Value::Ace, crate::core::Suit::Club));
cards.insert(Card::new(
crate::core::Value::King,
crate::core::Suit::Diamond,
));
let mut cards2 = CardBitSet::new();
cards2.insert(Card::new(
crate::core::Value::Three,
crate::core::Suit::Heart,
));
cards2.insert(Card::new(
crate::core::Value::King,
crate::core::Suit::Diamond,
));
let and = cards & cards2;
assert_eq!(and.count(), 1);
assert!(and.contains(Card::new(
crate::core::Value::King,
crate::core::Suit::Diamond,
)));
assert!(!and.contains(Card::new(crate::core::Value::Ace, crate::core::Suit::Club,)));
}
#[test]
fn test_bit_and_assign() {
let mut cards = CardBitSet::new();
cards.insert(Card::new(crate::core::Value::Ace, crate::core::Suit::Club));
cards.insert(Card::new(
crate::core::Value::King,
crate::core::Suit::Diamond,
));
let mut cards2 = CardBitSet::new();
cards2.insert(Card::new(
crate::core::Value::Three,
crate::core::Suit::Heart,
));
cards2.insert(Card::new(
crate::core::Value::King,
crate::core::Suit::Diamond,
));
cards &= cards2;
assert_eq!(cards.count(), 1);
assert!(cards.contains(Card::new(
crate::core::Value::King,
crate::core::Suit::Diamond,
)));
assert!(!cards.contains(Card::new(crate::core::Value::Ace, crate::core::Suit::Club,)));
assert!(!cards.contains(Card::new(
crate::core::Value::Three,
crate::core::Suit::Heart,
)));
}
#[test]
fn test_bit_xor_assign() {
let mut cards = CardBitSet::new();
cards.insert(Card::new(crate::core::Value::Ace, crate::core::Suit::Club));
cards.insert(Card::new(
crate::core::Value::King,
crate::core::Suit::Diamond,
));
let mut cards2 = CardBitSet::new();
cards2.insert(Card::new(
crate::core::Value::Three,
crate::core::Suit::Heart,
));
cards2.insert(Card::new(
crate::core::Value::King,
crate::core::Suit::Diamond,
));
cards ^= cards2;
assert_eq!(cards.count(), 2);
assert!(cards.contains(Card::new(crate::core::Value::Ace, crate::core::Suit::Club,)));
assert!(cards.contains(Card::new(
crate::core::Value::Three,
crate::core::Suit::Heart,
)));
}
#[test]
fn test_pick_one() {
let mut rng = rand::rng();
let mut cards = CardBitSet::new();
cards.insert(Card::new(crate::core::Value::Ace, crate::core::Suit::Club));
let card = cards.sample_one(&mut rng);
assert!(card.is_some(), "Card should be present");
assert_eq!(
card.unwrap(),
Card::new(crate::core::Value::Ace, crate::core::Suit::Club)
);
}
#[test]
fn test_pick_one_all() {
let mut rng = rand::rng();
let mut cards = CardBitSet::default();
let mut picked: HashSet<Card> = HashSet::new();
for _i in 0..10 {
let card = cards.sample_one(&mut rng);
if let Some(c) = card {
cards.remove(c);
assert!(
!picked.contains(&c),
"Card already picked: {c:?} picked = {picked:?}"
);
picked.insert(c);
} else {
panic!("No more cards to pick");
}
}
assert_eq!(cards.count(), 42); }
#[test]
fn test_can_pick_one_for_all() {
let mut rng = rand::rng();
let mut cards_one = CardBitSet::default();
let mut cards_two = CardBitSet::default();
let mut picked_one = Vec::new();
let mut picked_two = Vec::new();
while cards_one.count() > 0 && cards_two.count() > 0 {
if let Some(card_one) = cards_one.sample_one(&mut rng) {
picked_one.push(card_one);
cards_one.remove(card_one);
}
if let Some(card_two) = cards_two.sample_one(&mut rng) {
picked_two.push(card_two);
cards_two.remove(card_two);
}
}
assert!(cards_one.is_empty(), "Cards one should be empty");
assert!(cards_two.is_empty(), "Cards two should be empty");
assert_eq!(picked_one.len(), 52);
assert_eq!(picked_two.len(), 52);
assert_ne!(picked_one, picked_two, "Picked cards should be different");
let unique_one: HashSet<_> = picked_one.iter().cloned().collect();
let unique_two: HashSet<_> = picked_two.iter().cloned().collect();
assert_eq!(
unique_one.len(),
picked_one.len(),
"Picked cards one should be unique"
);
assert_eq!(
unique_two.len(),
picked_two.len(),
"Picked cards two should be unique"
);
}
#[test]
fn test_from_card_bit_set_to_flat_deck() {
use crate::core::FlatDeck;
let mut cbs = CardBitSet::new();
let ace_spade = Card::new(crate::core::Value::Ace, crate::core::Suit::Spade);
let king_heart = Card::new(crate::core::Value::King, crate::core::Suit::Heart);
cbs.insert(ace_spade);
cbs.insert(king_heart);
let fd: FlatDeck = cbs.into();
assert_eq!(fd.len(), 2);
}
#[test]
fn test_from_flat_deck_to_card_bit_set() {
let fd = FlatDeck::from(Deck::default());
let cbs: CardBitSet = CardBitSet::from(fd);
assert_eq!(cbs.count(), 52);
for card in Deck::default() {
assert!(cbs.contains(card));
}
}
#[test]
fn test_from_flat_deck_ref_to_card_bit_set() {
let fd = FlatDeck::from(Deck::default());
let cbs: CardBitSet = CardBitSet::from(&fd);
assert_eq!(cbs.count(), 52);
for card in Deck::default() {
assert!(cbs.contains(card));
}
}
#[test]
fn test_flat_deck_card_bit_set_round_trip() {
let fd = FlatDeck::from(Deck::default());
let cbs: CardBitSet = CardBitSet::from(&fd);
let fd2: FlatDeck = cbs.into();
assert_eq!(fd.len(), fd2.len());
}
#[test]
fn test_bitor_card() {
let mut cards = CardBitSet::new();
let ace = Card::new(crate::core::Value::Ace, crate::core::Suit::Club);
let king = Card::new(crate::core::Value::King, crate::core::Suit::Diamond);
cards |= ace;
assert_eq!(cards.count(), 1);
assert!(cards.contains(ace));
cards |= king;
assert_eq!(cards.count(), 2);
assert!(cards.contains(ace));
assert!(cards.contains(king));
cards |= ace;
assert_eq!(cards.count(), 2);
}
#[test]
fn test_bitxor() {
let mut cards1 = CardBitSet::new();
let mut cards2 = CardBitSet::new();
let ace = Card::new(crate::core::Value::Ace, crate::core::Suit::Club);
let king = Card::new(crate::core::Value::King, crate::core::Suit::Diamond);
let queen = Card::new(crate::core::Value::Queen, crate::core::Suit::Heart);
cards1.insert(ace);
cards1.insert(king);
cards2.insert(king);
cards2.insert(queen);
let xor_result = cards1 ^ cards2;
assert_eq!(xor_result.count(), 2);
assert!(xor_result.contains(ace));
assert!(xor_result.contains(queen));
assert!(!xor_result.contains(king));
}
#[test]
fn test_bitxor_assign_card() {
let mut cards = CardBitSet::new();
let ace = Card::new(crate::core::Value::Ace, crate::core::Suit::Club);
cards ^= ace;
assert_eq!(cards.count(), 1);
assert!(cards.contains(ace));
cards ^= ace;
assert_eq!(cards.count(), 0);
assert!(!cards.contains(ace));
cards ^= ace;
assert_eq!(cards.count(), 1);
assert!(cards.contains(ace));
}
#[test]
fn test_not() {
let mut cards = CardBitSet::new();
let ace = Card::new(crate::core::Value::Ace, crate::core::Suit::Club);
let king = Card::new(crate::core::Value::King, crate::core::Suit::Diamond);
cards.insert(ace);
cards.insert(king);
let not_cards = !cards;
assert_eq!(not_cards.count(), 50);
assert!(!not_cards.contains(ace));
assert!(!not_cards.contains(king));
let queen = Card::new(crate::core::Value::Queen, crate::core::Suit::Heart);
assert!(not_cards.contains(queen));
}
#[cfg(feature = "serde")]
#[test]
fn test_serde() {
let mut cards = CardBitSet::new();
let ace = Card::new(crate::core::Value::Ace, crate::core::Suit::Club);
let king = Card::new(crate::core::Value::King, crate::core::Suit::Diamond);
cards.insert(ace);
cards.insert(king);
let json = serde_json::to_string(&cards).unwrap();
let deserialized: CardBitSet = serde_json::from_str(&json).unwrap();
assert_eq!(cards, deserialized);
assert_eq!(deserialized.count(), 2);
assert!(deserialized.contains(ace));
assert!(deserialized.contains(king));
}
#[cfg(feature = "serde")]
#[test]
fn test_serde_empty() {
let cards = CardBitSet::new();
let json = serde_json::to_string(&cards).unwrap();
let deserialized: CardBitSet = serde_json::from_str(&json).unwrap();
assert_eq!(cards, deserialized);
assert!(deserialized.is_empty());
}
#[test]
fn test_nth_set_bit_all_positions() {
let full = CardBitSet::default();
for i in 0..52 {
assert_eq!(full.nth_set_bit(i), i, "nth_set_bit({i}) on full deck");
}
}
#[test]
fn test_nth_set_bit_sparse() {
let mut cards = CardBitSet::new();
cards.insert(Card::from(3));
cards.insert(Card::from(17));
cards.insert(Card::from(42));
assert_eq!(cards.nth_set_bit(0), 3);
assert_eq!(cards.nth_set_bit(1), 17);
assert_eq!(cards.nth_set_bit(2), 42);
}
#[test]
fn test_nth_set_bit_single() {
for pos in 0..52u8 {
let mut cards = CardBitSet::new();
cards.insert(Card::from(pos));
assert_eq!(cards.nth_set_bit(0), pos as u32);
}
}
#[test]
fn test_nth_set_bit_adjacent() {
let mut cards = CardBitSet::new();
cards.insert(Card::from(30));
cards.insert(Card::from(31));
assert_eq!(cards.nth_set_bit(0), 30);
assert_eq!(cards.nth_set_bit(1), 31);
}
#[test]
fn test_sample_one_uniform_distribution() {
let mut rng = StdRng::seed_from_u64(12345);
let mut cards = CardBitSet::new();
let test_cards: Vec<Card> = (0..5).map(Card::from).collect();
for &c in &test_cards {
cards.insert(c);
}
let num_samples = 50_000;
let mut counts = [0u32; 5];
for _ in 0..num_samples {
let card = cards.sample_one(&mut rng).unwrap();
let idx = test_cards.iter().position(|&c| c == card).unwrap();
counts[idx] += 1;
}
let expected = num_samples as f64 / 5.0;
let chi_sq: f64 = counts
.iter()
.map(|&c| {
let diff = c as f64 - expected;
diff * diff / expected
})
.sum();
assert!(
chi_sq < 18.47,
"Chi-squared {chi_sq} exceeds critical value 18.47 (p<0.001). \
Counts: {counts:?}, expected: {expected}"
);
}
#[test]
fn test_sample_one_uniform_sparse() {
let mut rng = StdRng::seed_from_u64(67890);
let mut cards = CardBitSet::new();
cards.insert(Card::from(0)); cards.insert(Card::from(51));
let num_samples = 50_000;
let mut count_low = 0u32;
for _ in 0..num_samples {
let card = cards.sample_one(&mut rng).unwrap();
if card == Card::from(0) {
count_low += 1;
}
}
let expected = num_samples as f64 / 2.0;
let stddev = (num_samples as f64 * 0.25).sqrt(); let z = (count_low as f64 - expected).abs() / stddev;
assert!(
z < 3.89,
"z-score {z} exceeds 3.89 (p<0.0001). \
Low: {count_low}, High: {}, expected: {expected}",
num_samples - count_low
);
}
#[test]
fn test_sample_one_uniform_full_deck() {
let mut rng = StdRng::seed_from_u64(11111);
let cards = CardBitSet::default();
let num_samples = 520_000; let mut counts = [0u32; 52];
for _ in 0..num_samples {
let card = cards.sample_one(&mut rng).unwrap();
counts[u8::from(card) as usize] += 1;
}
let expected = num_samples as f64 / 52.0;
let chi_sq: f64 = counts
.iter()
.map(|&c| {
let diff = c as f64 - expected;
diff * diff / expected
})
.sum();
assert!(
chi_sq < 82.29,
"Chi-squared {chi_sq} exceeds critical value 82.29 (p<0.001). \
Min count: {}, Max count: {}, expected: {expected}",
counts.iter().min().unwrap(),
counts.iter().max().unwrap()
);
}
}