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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
use std::{collections::VecDeque, ops::{Deref, DerefMut}};
use crate::deck::{Card, Name, Suit};
use crate::card_collection::{CardCollection, CardCollectionContains};
/// Represents a turn in the game.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Turn {
/// The card drawn.
pub draw: Card,
/// The card discarded.
pub discard: Card,
} impl Turn {
/// Creates a new `Turn` instance.
/// # Arguments
/// * `draw` - A `Card` representing the card drawn.
/// * `discard` - A `Card` representing the card discarded.
/// # Returns
/// A new `Turn` instance.
pub fn new(draw: Card, discard: Card) -> Self {
Turn {draw: draw, discard: discard}
}
}
/// Represents a hand of cards.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Hand([Card; 7]);
impl Deref for Hand {
type Target = [Card; 7];
fn deref(&self) -> &Self::Target {
&self.0
}
} impl DerefMut for Hand {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
} impl<'a> IntoIterator for &'a Hand {
type Item = &'a Card;
type IntoIter = std::slice::Iter<'a, Card>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
} impl IntoIterator for Hand {
type Item = Card;
type IntoIter = std::array::IntoIter<Card, 7>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
} impl Hand {
/// Creates a new `Hand` instance.
/// # Arguments
/// * `hand` - A `[Card; 7]` representing all cards in the hand.
/// # Returns
/// A new `Hand` instance.
pub fn new(hand: [Card; 7]) -> Self {
Hand(hand)
}
/// Helper function for `Game` and `PartialGame`.
/// Replaces the card discarded with the card drawn in the hand.
pub(crate) fn play(&mut self, turn: &Turn) {
if let Some(index_to_replace) = self.iter().position(|card| *card == turn.discard) {
self[index_to_replace] = turn.draw;
} else {
unreachable!()
}
}
/// Calculates the maximum score of the hand.
/// Builds all possible card configurations of basic cards from wilds and cards that modify other cards.
/// Scores each configuration to find the maximum score.
/// # Arguments
/// * `discard_pile` - An `&CardCollection` representing the cards in the discard pile.
/// # Returns
/// An `i16` representing the score of the hand.
pub fn score(&self, discard_pile: &CardCollection) -> i16 {
let mut queue: VecDeque<ProcessingHand> = VecDeque::from(
[ProcessingHand::new(0, self.to_vec())]
);
let mut possible_hands: Vec<Vec<Card>> = Vec::new();
while let Some(hand) = queue.pop_front() {
let mut new_elements: Vec<Vec<Card>> = Vec::new();
if let Some(adder) = hand.card().adder {
new_elements.extend(adder(&hand.hand, discard_pile));
} else {
new_elements.push(hand.hand.clone());
}
if hand.index == hand.hand.len() - 1 {
possible_hands.extend(new_elements);
} else {
queue.extend(new_elements
.into_iter()
.map(|item| ProcessingHand::new(hand.index + 1, item))
.collect::<Vec<ProcessingHand>>());
}
}
let mut queue: VecDeque<ProcessingHand> = VecDeque::from(
possible_hands
.into_iter()
.map(|hand| ProcessingHand::new(0, hand))
.collect::<Vec<ProcessingHand>>()
);
let mut possible_hands: Vec<Vec<Card>> = Vec::new();
while let Some(hand) = queue.pop_front() {
let mut new_elements: Vec<Vec<Card>> = Vec::new();
if let Some(wild) = hand.card().wild {
new_elements.extend(wild(&hand.hand, hand.index));
} else {
new_elements.push(hand.hand.clone());
}
if hand.index == hand.hand.len() - 1 {
possible_hands.extend(new_elements);
} else {
queue.extend(new_elements
.into_iter()
.map(|item| ProcessingHand::new(hand.index + 1, item))
.collect::<Vec<ProcessingHand>>());
}
}
let mut queue: VecDeque<ProcessingHand> = VecDeque::from(
possible_hands
.into_iter()
.map(|hand| ProcessingHand::new(0, hand))
.collect::<Vec<ProcessingHand>>()
);
let mut possible_hands: Vec<Vec<Card>> = Vec::new();
while let Some(hand) = queue.pop_front() {
let mut new_elements: Vec<Vec<Card>> = Vec::new();
if let Some(modifier) = hand.card().modifier {
new_elements.extend(modifier(&hand.hand));
} else {
new_elements.push(hand.hand.clone());
}
if hand.index == hand.hand.len() - 1 {
possible_hands.extend(new_elements);
} else {
queue.extend(new_elements
.into_iter()
.map(|item| ProcessingHand::new(hand.index + 1, item))
.collect::<Vec<ProcessingHand>>());
}
}
possible_hands
.into_iter()
.map(|hand| Hand::build_scoring_hand(hand).score())
.max()
.unwrap_or(0)
}
/// A helper function for `score` that builds a `ScoringHand`.
fn build_scoring_hand(mut cards: Vec<Card>) -> ScoringHand {
let mut immunity_cards = CardCollection::new();
let mut blanked_cards = CardCollection::new();
for _ in 0..2 {
for card in cards.iter() {
if let Some(immunity) = card.immunity {
immunity(&mut immunity_cards);
}
if let Some(blanks) = card.blanks {
blanks(&cards, &immunity_cards, &mut blanked_cards);
}
}
cards.retain(|card| !blanked_cards.contains(card.name));
}
ScoringHand {cards: cards, immunity: immunity_cards}
}
}
/// Represents a collection of cards in the process of
/// being expanded into all possible hands containg only basic cards.
struct ProcessingHand {
/// The index of the card being analized.
index: usize,
/// The current hand of cards.
hand: Vec<Card>,
} impl ProcessingHand {
/// Creates a new `ProcessingHand` instance.
/// # Arguments
/// * `index` - A `usize` representing the index of the card being processed.
/// * `hand` - A `Vec<Card>` representing the hand being expanded.
/// # Returns
/// A new `ProcessingHand` instance.
fn new(index: usize, hand: Vec<Card>) -> Self {
ProcessingHand {index: index, hand: hand}
}
/// Gets the current card being processed.
/// # Returns
/// The `Card` that is at the index being analized.
fn card(&self) -> Card {
self.hand[self.index]
}
}
/// Represents a hand of basic cards that cannot change
/// themselves or other cards in the hand.
pub(crate) struct ScoringHand {
/// The cards in the hand
pub(crate) cards: Vec<Card>,
/// The cards that are removed from penalties of other cards.
pub(crate) immunity: CardCollection,
} impl ScoringHand {
/// Finds the score of a hand of basic cards.
/// # Returns
/// An `i16` representing the score of the hand.
fn score(self) -> i16 {
let mut total: i16 = self.cards.iter().map(|card| card.strength).sum();
for card in self.cards.iter() {
if let Some(bonus) = card.bonus {
total += bonus(&self);
}
if let Some(penalty) = card.penalty {
total -= penalty(&self, &self.immunity);
}
}
total
}
/// A helper function for `score` that checks if the hand contains a card.
/// # Arguments
/// * `name` - The name of the card to look for.
/// # Returns
/// A `bool` weather or not the card is in the hand.
pub(crate) fn contains_name(&self, name: Name) -> bool {
self.cards.iter().any(|card| card.name == name)
}
/// A helper function for `score` that finds the
/// number of cards of a specific suit in the hand.
/// # Arguments
/// * `suit` - The suit to count.
/// # Returns
/// An `i16` the total number of cards of a specific suit.
pub(crate) fn number_of_suit(&self, suit: Suit) -> i16 {
self.cards.iter().filter(|card| card.suit == suit).count() as i16
}
}