1use crate::{
2 PlayingCard, CharacterCard, ActionCard, Card, Element,
3 EquipmentCard, TalentCard,
4 EventCard, ElementalResonanceCard,
5};
6use super::cards::CardOrd;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct Deck {
11 characters: [CharacterCard; 3],
12 actions: [ActionCard; 30],
13}
14
15impl Deck {
16 pub fn has_character(&self, card: CharacterCard) -> bool {
17 let x = self.characters;
18
19 card == x[0] || card == x[1] || card == x[2]
20 }
21
22 pub fn contains(&self, card: ActionCard) -> bool {
23 for i in 0..30 {
24 if card == self.actions[i] { return true }
25 }
26
27 false
28 }
29
30 pub fn iter(&self) -> IterAction<'_> {
31 IterAction { array: &self.actions, index: 0, unique: false }
32 }
33
34 pub fn iter_unique(&self) -> IterAction<'_> {
35 IterAction { array: &self.actions, index: 0, unique: true }
36 }
37
38 pub fn from_iter(iter: impl IntoIterator<Item=Card>) -> Result<Self, DeckError> {
39 let mut cards = iter.into_iter();
40
41 let mut char_vec = Vec::with_capacity(3);
42 let mut action_vec = Vec::with_capacity(30);
43
44 while let Some(card) = cards.next() {
45 match card {
46 Card::Character(character) => {
47 if char_vec.len() == 3 {
48 return Err(DeckError::TooManyCharacterCards)
49 } else {
50 char_vec.push(character)
51 }
52 },
53 Card::Action(action) => {
54 if action_vec.len() == 30 {
55 return Err(DeckError::TooManyActionCards)
56 } else {
57 action_vec.push(action)
58 }
59 }
60 }
61 }
62
63 if char_vec.len() != 3 { return Err(DeckError::NotEnoughCharacterCards(char_vec.len() as u8)) }
64 if action_vec.len() != 30 { return Err(DeckError::NotEnoughActionCards(action_vec.len() as u8)) }
65
66 char_vec.sort_by(|a, b| a.cmp(b));
67 action_vec.sort_by(|a, b| a.cmp(b));
68
69 let characters = <[CharacterCard; 3]>::try_from(char_vec).unwrap();
70 let actions = <[ActionCard; 30]>::try_from(action_vec).unwrap();
71
72 Deck::verify(&characters, &actions)?;
73
74 Ok(Self { characters, actions })
75 }
76
77 pub fn from_exact(mut characters: [CharacterCard; 3], mut actions: [ActionCard; 30]) -> Result<Self, DeckError> {
78 characters.sort_by(|a, b| a.cmp(b));
79 actions.sort_by(|a, b| a.cmp(b));
80
81 Deck::verify(&characters, &actions)?;
82
83 Ok(Self { characters, actions })
84 }
85
86 fn verify(characters: &[CharacterCard; 3], actions: &[ActionCard; 30]) -> Result<(), DeckError> {
87 if characters[0] == characters[1] || characters[1] == characters[2] {
88 return Err(DeckError::CharacterAppearsMoreThanOnce(characters[1]))
91 }
92
93 for i in 0..28 {
94 if actions[i] == actions[i+1] && actions[i+1] == actions[i+2] {
97 return Err(DeckError::ActionCardAppearsMoreThanTwice(actions[i]))
98 }
99 }
100
101 let resonance: Option<Element> = {
104 let el1 = characters[0].element();
105 let el2 = characters[1].element();
106 let el3 = characters[2].element();
107
108 if el1 == el2 {
109 Some(el1)
110 } else if el2 == el3 {
111 Some(el2)
112 } else if el3 == el1 {
113 Some(el3)
114 } else {
115 None
116 }
117 };
118
119 for i in 0..30 {
120 if let ActionCard::Equipment(EquipmentCard::Talent(talent)) = actions[i] {
121 let required = talent.character();
122
123 if !characters.contains(&required) {
124 return Err(DeckError::TalentRequiresCharacter(talent))
125 }
126 }
127
128 if let ActionCard::Event(EventCard::Resonance(elemental)) = actions[i] {
129 let required = elemental.element();
130
131 if resonance != Some(required) {
132 return Err(DeckError::ResonanceRequiresAtLeastTwo(elemental))
133 }
134 }
135 }
136
137 Ok(())
138 }
139}
140
141#[derive(PartialEq, Eq)]
142pub enum DeckError {
143 TooManyCharacterCards,
145 TooManyActionCards,
147 NotEnoughCharacterCards(u8),
149 NotEnoughActionCards(u8),
151 TalentRequiresCharacter(TalentCard),
153 ResonanceRequiresAtLeastTwo(ElementalResonanceCard),
155 CharacterAppearsMoreThanOnce(CharacterCard),
157 ActionCardAppearsMoreThanTwice(ActionCard),
159}
160
161use std::fmt;
162
163impl fmt::Display for DeckError {
164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165 let errstr = match self {
166 Self::TalentRequiresCharacter(card) => {
167 let talent_name = card.name();
168 let char_name = card.character().name();
169
170 format!("`{talent_name}` requires `{char_name}` to be present in the deck")
171 },
172 Self::ResonanceRequiresAtLeastTwo(card) => {
173 let res_name = card.name();
174 let element = card.element();
175
176 format!("`{res_name}` requires at least two {element:?} characters in the deck")
177 }
178 Self::CharacterAppearsMoreThanOnce(card) => {
179 let char_name = card.name();
180
181 format!("deck contains more than one `{char_name}`")
182 },
183 Self::ActionCardAppearsMoreThanTwice(card) => {
184 let card_name = card.name();
185
186 format!("deck contains more than two `{card_name}`")
187 },
188 Self::TooManyCharacterCards => "deck has more than three character cards".into(),
189 Self::TooManyActionCards => "deck has more than 30 action cards".into(),
190 Self::NotEnoughCharacterCards(x) => {
191 format!("decks require 3 character cards, only retrieved {x}")
192 },
193 Self::NotEnoughActionCards(x) => {
194 format!("decks require 30 action cards, only retrieved {x}")
195 },
196 };
197
198 write!(f, "{errstr}")
199 }
200}
201
202impl fmt::Debug for DeckError {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 fmt::Display::fmt(self, f)
205 }
206}
207
208impl std::error::Error for DeckError {}
209
210pub struct IterAction<'d> {
217 array: &'d [ActionCard; 30],
218 index: usize,
219 unique: bool,
220}
221
222impl Iterator for IterAction<'_> {
223 type Item = ActionCard;
224
225 fn next(&mut self) -> Option<Self::Item> {
226 if self.index < 30 {
227 let card = self.array[self.index];
228
229 if self.unique && self.index < 29 {
230 if card == self.array[self.index + 1] {
231 self.index += 2; } else {
233 self.index += 1;
234 }
235 } else {
236 self.index += 1;
237 }
238
239 Some(card)
240 } else {
241 None
242 }
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 #![allow(dead_code)]
249
250 use rand::prelude::*;
251 use crate::*;
252
253 const CH: CharacterCard = CharacterCard::Chongyun;
254 const XI: CharacterCard = CharacterCard::Xingqiu;
255 const FI: CharacterCard = CharacterCard::Fischl;
256 const KE: CharacterCard = CharacterCard::Keqing;
257 const RA: CharacterCard = CharacterCard::Razor;
258 const LA: CharacterCard = CharacterCard::StonehideLawachurl;
259 const NO: CharacterCard = CharacterCard::Noelle;
260 const CO: CharacterCard = CharacterCard::Collei;
261 const AG: CharacterCard = CharacterCard::FatuiPyroAgent;
262 const YO: CharacterCard = CharacterCard::Yoimiya;
263
264 const GA: ActionCard = ActionCard::Equipment(EquipmentCard::Artifact(ArtifactCard::GamblersEarrings));
265 const LU: ActionCard = ActionCard::Equipment(EquipmentCard::Artifact(ArtifactCard::LuckyDogsSilverCirclet));
266 const DE: ActionCard = ActionCard::Equipment(EquipmentCard::Artifact(ArtifactCard::DeepwoodMemories));
267 const VI: ActionCard = ActionCard::Equipment(EquipmentCard::Artifact(ArtifactCard::ViridescentVenerer));
268 const TH: ActionCard = ActionCard::Equipment(EquipmentCard::Talent(TalentCard::TheScentRemained));
269 const AW: ActionCard = ActionCard::Equipment(EquipmentCard::Talent(TalentCard::Awakening));
270 const IG: ActionCard = ActionCard::Equipment(EquipmentCard::Talent(TalentCard::IGotYourBack));
271 const SH: ActionCard = ActionCard::Equipment(EquipmentCard::Talent(TalentCard::ShakenNotPurred));
272 const AQ: ActionCard = ActionCard::Equipment(EquipmentCard::Weapon(WeaponCard::AquilaFavonia));
273 const WO: ActionCard = ActionCard::Equipment(EquipmentCard::Weapon(WeaponCard::WolfsGravestone));
274 const WH: ActionCard = ActionCard::Equipment(EquipmentCard::Weapon(WeaponCard::WhiteTassel));
275 const LO: ActionCard = ActionCard::Event(EventCard::Food(FoodCard::LotusFlowerCrisp));
276 const MI: ActionCard = ActionCard::Event(EventCard::Food(FoodCard::MintyMeatRolls));
277 const AD: ActionCard = ActionCard::Event(EventCard::Food(FoodCard::AdeptusTemptation));
278 const JU: ActionCard = ActionCard::Event(EventCard::Food(FoodCard::JueyunGuoba));
279 const LE: ActionCard = ActionCard::Event(EventCard::Normal(NormalEventCard::LeaveItToMe));
280 const ST: ActionCard = ActionCard::Event(EventCard::Normal(NormalEventCard::Strategize));
281 const MA: ActionCard = ActionCard::Event(EventCard::Normal(NormalEventCard::MasterOfWeaponry));
282 const AB: ActionCard = ActionCard::Event(EventCard::Normal(NormalEventCard::AbyssalSummons));
283 const HI: ActionCard = ActionCard::Event(EventCard::Resonance(ElementalResonanceCard::HighVoltage));
284 const EN: ActionCard = ActionCard::Event(EventCard::Resonance(ElementalResonanceCard::EnduringRock));
285 const PA: ActionCard = ActionCard::Support(SupportCard::Companion(CompanionCard::Paimon));
286 const LI: ActionCard = ActionCard::Support(SupportCard::Companion(CompanionCard::Liben));
287 const TI: ActionCard = ActionCard::Support(SupportCard::Companion(CompanionCard::Timaeus));
288 const TU: ActionCard = ActionCard::Support(SupportCard::Companion(CompanionCard::Tubby));
289 const NR: ActionCard = ActionCard::Support(SupportCard::Item(ItemCard::NRE));
290 const JA: ActionCard = ActionCard::Support(SupportCard::Location(LocationCard::JadeChamber));
291 const FA: ActionCard = ActionCard::Support(SupportCard::Location(LocationCard::FavoniusCathedral));
292 const DA: ActionCard = ActionCard::Support(SupportCard::Location(LocationCard::DawnWinery));
293 const WA: ActionCard = ActionCard::Support(SupportCard::Location(LocationCard::WangshuInn));
294
295 fn iter(characters: &[CharacterCard], actions: &[ActionCard]) -> Vec<Card> {
296 characters.iter().map(|x| Card::from(*x))
297 .chain(actions.iter().map(|x| Card::from(*x)))
298 .collect()
299 }
300
301 #[test]
302 fn eq_works() {
303 let characters = [LA, CO, NO];
304 let actions = [ST, PA, VI, DA, LU, WO, IG, NR, WA, JU, JA, WA, MI, WH, FA, LE, GA, LO, MA, AD, LI, TU, IG, TI, AQ, AB, TU, AB, EN, DE];
305
306 let deck = iter(&characters, &actions);
307 let original_deck = Deck::from_iter(deck.iter().copied());
308
309 let mut rng = thread_rng();
310
311 for _ in 0..5 {
312 let mut shuffled = deck.clone();
313 shuffled.shuffle(&mut rng);
314
315 let shuffled_deck = Deck::from_iter(shuffled.iter().copied());
316
317 if original_deck != shuffled_deck {
320 panic!("These vec iterators produce different decks:\n{original_deck:?}\n{shuffled_deck:?}")
321 }
322 }
323 }
324
325 #[test]
326 fn wrong_amounts() {
327 let not_enough_chars = iter(
328 &[LA, NO],
329 &[ST, PA, VI, DA, LU, WO, IG, NR, WA, JU, JA, WA, MI, WH, FA, LE, GA, LO, MA, AD, LI, TU, IG, TI, AQ, AB, TU, AB, EN, DE]
330 );
331
332 let not_enough_actions = iter(
333 &[LA, CO, NO],
334 &[ST, PA, VI, DA, LU, WO, IG, NR, WA, JU, JA, WA, MI, WH, FA, LE, GA, LO, MA, AD, LI, TU, TI, AQ, AB, TU, AB, EN, DE]
335 );
336
337 let too_many_chars = iter(
338 &[LA, CO, NO, CH],
339 &[ST, PA, VI, DA, LU, WO, IG, NR, WA, JU, JA, WA, MI, WH, FA, LE, GA, LO, MA, AD, LI, TU, IG, TI, AQ, AB, TU, AB, EN, DE]
340 );
341
342 let too_many_actions = iter(
343 &[LA, CO, NO],
344 &[ST, PA, VI, DA, LU, WO, IG, NR, WA, JU, JA, WA, MI, WH, FA, LE, GA, LO, MA, AD, LI, LI, TU, IG, TI, AQ, AB, TU, AB, EN, DE]
345 );
346
347 assert_eq!(Deck::from_iter(not_enough_chars), Err(DeckError::NotEnoughCharacterCards(2)));
348 assert_eq!(Deck::from_iter(not_enough_actions), Err(DeckError::NotEnoughActionCards(29)));
349 assert_eq!(Deck::from_iter(too_many_chars), Err(DeckError::TooManyCharacterCards));
350 assert_eq!(Deck::from_iter(too_many_actions), Err(DeckError::TooManyActionCards));
351 }
352
353 #[test]
354 fn talent_error() {
355 let talent_missing_character = iter(
356 &[FI, RA, AG],
357 &[ST, PA, VI, DA, LU, WO, IG, NR, WA, JU, JA, WA, MI, WH, FA, LE, GA, LO, MA, AD, LI, TU, IG, TI, AQ, AB, TU, AB, AQ, DE]
358 );
359
360 assert_eq!(
361 Deck::from_iter(talent_missing_character),
362 Err(DeckError::TalentRequiresCharacter(TalentCard::IGotYourBack))
363 );
364
365 let this_works = iter(
367 &[FI, NO, AG],
368 &[ST, PA, VI, DA, LU, WO, IG, NR, WA, JU, JA, WA, MI, WH, FA, LE, GA, LO, MA, AD, LI, TU, IG, TI, AQ, AB, TU, AB, AQ, DE]
369 );
370
371 assert!(Deck::from_iter(this_works).is_ok());
372 }
373
374 #[test]
375 fn resonance_error() {
376 let actions = [ST, PA, VI, HI, LU, WO, WH, NR, WA, JU, JA, WA, MI, WH, FA, LE, GA, LO, MA, AD, HI, TU, MI, TI, AQ, AB, TU, AB, AQ, DE];
377
378 let resonance_missing_chars = iter(&[FI, CH, XI], &actions);
379
380 assert_eq!(
381 Deck::from_iter(resonance_missing_chars),
382 Err(DeckError::ResonanceRequiresAtLeastTwo(ElementalResonanceCard::HighVoltage))
383 );
384
385 let resonance_with_two = iter(&[RA, FI, XI], &actions);
387 let resonance_with_three = iter(&[KE, RA, FI], &actions);
388
389 assert!(Deck::from_iter(resonance_with_two).is_ok());
390 assert!(Deck::from_iter(resonance_with_three).is_ok());
391
392 }
393
394 #[test]
395 fn multiple_error() {
396 let duplicate_char = iter(
397 &[YO, AG, YO],
398 &[ST, PA, VI, DE, LU, WO, WH, NR, WA, JU, JA, WA, MI, WH, FA, LE, GA, LO, MA, AD, PA, TU, MI, TI, AQ, AB, TU, AB, AQ, DE]
399 );
400
401 assert_eq!(
402 Deck::from_iter(duplicate_char),
403 Err(DeckError::CharacterAppearsMoreThanOnce(CharacterCard::Yoimiya)),
404 );
405
406 let triplicate_card = iter(
407 &[LA, CO, NO],
408 &[ST, PA, VI, TU, LU, WO, WH, NR, WA, JU, JA, WA, MI, WH, FA, LE, GA, LO, MA, AD, HI, TU, MI, TI, AQ, AB, TU, AB, AQ, DE]
409 );
410
411 assert_eq!(
412 Deck::from_iter(triplicate_card),
413 Err(DeckError::ActionCardAppearsMoreThanTwice(TU)),
414 );
415 }
416
417 #[test]
418 fn from_exact_works() {
419 let characters = [LA, CO, NO];
420 let actions = [ST, PA, VI, DA, LU, WO, IG, NR, WA, JU, JA, WA, MI, WH, FA, LE, GA, LO, MA, AD, LI, TU, IG, TI, AQ, AB, TU, AB, EN, DE];
421
422 let card_vec = iter(&characters, &actions);
423
424 assert_eq!(
425 Deck::from_iter(card_vec),
426 Deck::from_exact(characters, actions),
427 );
428 }
429}