1use crate::card::*;
17use crate::find::FindSets;
18use crate::pair_iter::PairIter;
19use crate::shuffle::Shuffle;
20use std::cmp;
21
22pub const DECK_SIZE: usize = 81;
23
24pub fn cards() -> Vec<Card> {
26 (0..DECK_SIZE).map(Card::new).collect()
27}
28
29#[derive(Default, Clone)]
30pub struct Deck { stock: Vec<Card> }
31
32impl Deck {
33 pub fn new() -> Deck {
35 let mut cards = cards();
36 cards.shuffle();
37 Deck { stock: cards }
38 }
39
40 pub fn simplify(&mut self) {
43 self.stock.retain(|card| card.shading() == Shading::Solid);
44 }
45
46 pub fn is_empty(&self) -> bool {
47 self.stock.is_empty()
48 }
49
50 pub fn remainder(&self) -> usize {
51 self.stock.len()
52 }
53
54 pub fn draw(&mut self, n: usize) -> Vec<Card> {
55 let r = self.remainder();
56 let x = cmp::min(n, r);
57 self.stock.split_off(r - x)
58 }
59}
60
61impl Deck {
62 pub fn draw_guaranteeing_set(&mut self, hand: &[Card]) -> Option<Vec<Card>> {
92 assert_eq!(hand.len(), 15);
93 assert!(self.stock.len() >= 6);
94
95 let mut draw = self.draw(3);
98 let mut test = hand.to_owned();
99 test.append(&mut draw.clone());
100
101 if test.contains_set() {
102 return Some(draw);
103 } else {
104 self.stock.append(&mut draw);
106 }
107
108 self.fix_one_card(hand)
109 .or_else(|| self.fix_two_cards(hand))
110 .or_else(|| self.fix_three_cards())
111 }
112
113 fn fix_one_card(&mut self, hand: &[Card]) -> Option<Vec<Card>> {
114 let mut hand = hand.to_owned();
117 hand.shuffle();
118
119 for c in hand.pairs().map(|pair| pair.complete_set()) {
120 if let Some(ix) = self.stock.iter().position(|&obj| obj == c) {
121 let last_ix = self.stock.len() - 1;
123 self.stock.swap(ix, last_ix);
124
125 let mut draw = self.draw(3);
127
128 draw.shuffle();
130 return Some(draw);
131 }
132 }
133
134 None
135 }
136
137 fn fix_two_cards(&mut self, hand: &[Card]) -> Option<Vec<Card>> {
138 if let Some((&a, &b)) = self.stock.pairs()
139 .filter(|&pair| hand.contains(&pair.complete_set()))
140 .nth(0)
141 {
142 let mut result = vec![a, b];
143 self.stock.retain(|&n| n != a && n != b);
145
146 result.append(&mut self.draw(1));
148
149 result.shuffle();
151 Some(result)
152 } else {
153 None
154 }
155 }
156
157 fn fix_three_cards(&mut self) -> Option<Vec<Card>> {
158 if let Some(set) = self.stock.find_first_set() {
159 let (a,b,c) = set.cards();
160 self.stock.retain(|&n| n != a && n != b && n != c);
161 Some(vec![a, b, c])
162 } else {
163 None
164 }
165 }
166}
167
168#[cfg(test)]
173mod tests {
174 use super::*;
175 use crate::card::Card;
176 use crate::find::{FindSets, FindSuperSets};
177
178 #[test]
179 fn count_sets() {
180 let sets = cards().find_all_sets();
181 assert_eq!(sets.len(), 1080);
182 assert_eq!(cards().count_sets(), 1080);
183 }
184
185 #[test]
186 fn count_supersets() {
187 let supersets = cards().find_all_supersets();
188 assert_eq!(supersets.len(), 63180);
189 assert_eq!(cards().count_supersets(), 63180);
190 }
191
192 #[test]
193 fn check_draw_cards() {
194 let mut deck = Deck::new();
195 let mut r = deck.remainder();
196
197 let mut deal = deck.draw(12);
198 assert_eq!(deal.len(), 12);
199 assert_eq!(deck.remainder(), r - 12);
200
201 r = deck.remainder();
202 deal = deck.draw(r + 10);
203 assert_eq!(deal.len(), r);
204 assert!(deck.is_empty());
205
206 deal = deck.draw(3);
207 assert!(deal.is_empty());
208 }
209
210 trait AsCards {
211 fn as_cards(&self) -> Vec<Card>;
212 }
213
214 impl AsCards for [usize] {
215 fn as_cards(&self) -> Vec<Card> {
216 self.iter()
217 .map(|&ix| Card::new(ix))
218 .collect()
219 }
220 }
221
222 #[test]
223 fn check_fixers() {
224 const A: usize = 21;
226 const B: usize = 41;
227 const C: usize = 58;
228 let set = [A, B, C].as_cards();
229 assert!(set.contains_set());
230
231 let indices = vec![11, 19, 31, 34, 64, 72, A, B, C];
233 let cards = indices.as_cards();
234 assert_eq!(cards.count_sets(), 1);
235
236 let hand = [11, A, B].as_cards(); let stock = [C, 19, 31, 34, 64, 72].as_cards(); assert!(!hand.contains_set());
244 assert!(!stock.contains_set());
245
246 let mut deck = Deck { stock };
247 match deck.fix_one_card(&hand) {
248 None => panic!("Could not guarantee set!"),
249 Some(mut draw) => {
250 let mut test = hand.clone();
251 test.append(&mut draw);
252 assert!(test.contains_set());
253 test.sort_by_key(|c| c.index());
254 assert_eq!(test, [11, A, 34, B, C, 64].as_cards());
255 assert_eq!(deck.stock, [72, 19, 31].as_cards());
256 }
257 }
258
259 let hand = [11, 19, A].as_cards(); let stock = [B, 31, 34, C, 64, 72].as_cards(); assert!(!hand.contains_set());
267 assert!(!stock.contains_set());
268
269 let mut deck = Deck { stock };
270 match deck.fix_two_cards(&hand) {
271 None => panic!("Could not guarantee set!"),
272 Some(mut draw) => {
273 let mut test = hand.clone();
274 test.append(&mut draw);
275 assert!(test.contains_set());
276 test.sort_by_key(|c| c.index());
277 assert_eq!(test, [11, 19, A, B, C, 72].as_cards());
278 assert_eq!(deck.stock, [31, 34, 64].as_cards());
279 }
280 }
281
282 let stock = [34, A, B, C, 64, 72].as_cards(); let mut deck = Deck { stock };
289 match deck.fix_three_cards() {
290 None => panic!("Could not guarantee set!"),
291 Some(mut draw) => {
292 assert!(draw.contains_set());
293 draw.sort_by_key(|c| c.index());
294 assert_eq!(draw, set);
295 assert_eq!(deck.stock, [34, 64, 72].as_cards());
296 }
297 }
298 }
299
300 #[test]
301 fn check_guarantee() {
302 let indices = vec![0,1,3,4,9,13,14,15,19,34,38,39,40,44,49,50,52,53,60,74];
304
305 let mut complement: Vec<usize> = (0..81).collect();
307 for &ix in indices.iter().rev() {
308 complement.remove(ix);
309 }
310
311 let mut hand = indices.as_cards();
313 let rest = complement.as_cards();
314
315 assert_eq!(hand.len(), 20);
316 assert!(!hand.contains_set());
317
318 let mut stock = hand.split_off(15);
319 assert_eq!(stock.len(), 5);
320
321 stock.insert(0, rest[0]);
323
324 for &x in &rest {
327 stock[0] = x;
328 let mut deck = Deck { stock: stock.clone() };
329
330 match deck.draw_guaranteeing_set(&hand) {
331 None => panic!("Could not guarantee set!"),
332 Some(mut draw) => {
333 let mut test = hand.clone();
334 test.append(&mut draw);
335 assert_eq!(test.len(), 18);
336 assert!(test.contains_set());
337 }
338 }
339 }
340 }
341}