openpql_prelude/rng/
card_gen.rs1use super::{Card, Card64, Vec};
2
3#[derive(Clone, Debug, Default)]
4pub struct CardGen {
5 init: Vec<Card>,
6 used: Vec<Card>,
7 unused: Vec<Card>,
8}
9
10impl CardGen {
11 pub fn new<const SD: bool>(dead_cards: Card64) -> Self {
12 let mut unused = vec![];
13
14 for card in Card64::all::<SD>().iter() {
15 if !dead_cards.contains_card(card) {
16 unused.push(card);
17 }
18 }
19
20 Self {
21 init: unused.clone(),
22 used: vec![],
23 unused,
24 }
25 }
26
27 pub fn deal(&mut self, rng: &mut impl rand::Rng) -> Option<Card> {
28 let n = self.unused.len();
29 if n == 0 {
30 return None;
31 }
32
33 let idx = rng.random_range(0..n);
34 let card = self.unused.remove(idx);
35 self.used.push(card);
36
37 Some(card)
38 }
39
40 pub fn unset(&mut self, c64: Card64) {
41 for c in c64.iter() {
42 self.unset_card(c);
43 }
44 }
45
46 pub fn unset_card(&mut self, card: Card) {
47 debug_assert!(!self.unused.contains(&card));
48
49 self.used.retain(|&c| c != card);
50 self.unused.push(card);
51 }
52
53 pub fn reset(&mut self) {
54 self.unused = self.init.clone();
55 }
56}
57
58#[cfg(test)]
59#[cfg_attr(coverage_nightly, coverage(off))]
60pub mod tests {
61 use super::*;
62
63 fn mk_exhausted_card_gen() -> CardGen {
64 let mut g = CardGen::new::<false>(Card64::default());
65 (g.used, g.unused) = (g.unused, g.used);
66
67 g
68 }
69
70 fn deal_all_to_c64(rng: &mut impl rand::Rng, g: &mut CardGen) -> Card64 {
71 (0..Card::N_CARDS).filter_map(|_| g.deal(rng)).collect()
72 }
73
74 #[test]
75 fn test_deal_all() {
76 const SD: bool = false;
77 let mut rng = rand::rng();
78 let mut g = CardGen::new::<SD>(Card64::default());
79 let mut dealt = Card64::default();
80
81 for _ in 0..Card::N_CARDS {
82 dealt.set(g.deal(&mut rng).unwrap());
83 }
84
85 assert_eq!(dealt, Card64::all::<SD>());
86 }
87
88 #[test]
89 fn test_deal_all_sd() {
90 const SD: bool = true;
91 let mut rng = rand::rng();
92 let mut g = CardGen::new::<SD>(Card64::default());
93 let mut dealt = Card64::default();
94
95 for _ in 0..Card::N_CARDS_SD {
96 dealt.set(g.deal(&mut rng).unwrap());
97 }
98
99 assert_eq!(dealt, Card64::all::<SD>());
100 }
101
102 #[quickcheck]
103 fn test_unset(cards: Card64) {
104 let mut rng = rand::rng();
105
106 let mut g = mk_exhausted_card_gen();
107
108 g.unset(cards);
109
110 assert_eq!(deal_all_to_c64(&mut rng, &mut g), cards);
111
112 let mut g = mk_exhausted_card_gen();
113
114 for card in cards.iter() {
115 g.unset_card(card);
116 }
117
118 assert_eq!(deal_all_to_c64(&mut rng, &mut g), cards);
119 }
120
121 #[quickcheck]
122 fn test_dead_and_reset(available: Card64) {
123 let mut rng = rand::rng();
124
125 let mut g = CardGen::new::<false>(!available);
126
127 assert_eq!(deal_all_to_c64(&mut rng, &mut g), available);
128 assert_eq!(deal_all_to_c64(&mut rng, &mut g), Card64::default());
129
130 g.reset();
131
132 assert_eq!(deal_all_to_c64(&mut rng, &mut g), available);
133 }
134}