1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use crate::{CharacterCard, ActionCard, Card, EquipmentCard, TalentCard};
use super::cards::CardOrd;
#[derive(Debug, Clone)]
pub struct Deck {
characters: [CharacterCard; 3],
actions: [ActionCard; 30],
}
impl Deck {
pub fn characters(&self) -> &[CharacterCard; 3] {
&self.characters
}
pub fn action_cards(&self) -> &[ActionCard; 30] {
&self.actions
}
pub fn from_iter(iter: impl IntoIterator<Item=Card>) -> Result<Self, DeckError> {
let mut cards = iter.into_iter();
let mut char_vec = Vec::with_capacity(3);
let mut action_vec = Vec::with_capacity(30);
while let Some(card) = cards.next() {
match card {
Card::Character(character) => {
if char_vec.len() == 3 {
return Err(DeckError::TooManyCharacterCards)
} else {
char_vec.push(character)
}
},
Card::Action(action) => {
if action_vec.len() == 30 {
return Err(DeckError::TooManyActionCards)
} else {
action_vec.push(action)
}
}
}
}
if char_vec.len() != 3 { return Err(DeckError::NotEnoughCharacterCards(char_vec.len() as u8)) }
if action_vec.len() != 30 { return Err(DeckError::NotEnoughActionCards(action_vec.len() as u8)) }
char_vec.sort_by(|a, b| a.cmp(b));
action_vec.sort_by(|a, b| a.cmp(b));
let characters = <[CharacterCard; 3]>::try_from(char_vec).unwrap();
let actions = <[ActionCard; 30]>::try_from(action_vec).unwrap();
Deck::verify(&characters, &actions)?;
Ok(Self { characters, actions })
}
fn verify(characters: &[CharacterCard; 3], actions: &[ActionCard; 30]) -> Result<(), DeckError> {
if characters[0] == characters[1] || characters[1] == characters[2] {
return Err(DeckError::CharacterAppearsMoreThanOnce(characters[1]))
}
for i in 0..28 {
if actions[i] == actions[i+1] && actions[i+1] == actions[i+2] {
return Err(DeckError::ActionCardAppearsMoreThanTwice(actions[i]))
}
}
for i in 0..30 {
if let ActionCard::Equipment(EquipmentCard::Talent(talent)) = actions[i] {
let required = talent.character();
if !characters.contains(&required) {
return Err(DeckError::TalentRequiresCharacter(talent))
}
}
}
Ok(())
}
}
pub enum DeckError {
TooManyCharacterCards,
TooManyActionCards,
NotEnoughCharacterCards(u8),
NotEnoughActionCards(u8),
TalentRequiresCharacter(TalentCard),
CharacterAppearsMoreThanOnce(CharacterCard),
ActionCardAppearsMoreThanTwice(ActionCard),
}
use std::fmt;
impl fmt::Display for DeckError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let errstr = match self {
Self::TalentRequiresCharacter(card) => {
let talent_name = card.name();
let char_name = card.character().name();
format!("`{talent_name}` requires `{char_name}` to be present in the deck")
},
Self::CharacterAppearsMoreThanOnce(card) => {
let char_name = card.name();
format!("deck contains more than one `{char_name}`")
},
Self::ActionCardAppearsMoreThanTwice(card) => {
let card_name = card.name();
format!("deck contains more than two `{card_name}`")
},
Self::TooManyCharacterCards => "deck has more than three character cards".into(),
Self::TooManyActionCards => "deck has more than 30 action cards".into(),
Self::NotEnoughCharacterCards(x) => {
format!("decks require 3 character cards, only retrieved {x}")
},
Self::NotEnoughActionCards(x) => {
format!("decks require 30 action cards, only retrieved {x}")
},
};
write!(f, "{errstr}")
}
}
impl fmt::Debug for DeckError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl std::error::Error for DeckError {}