Skip to content

Commit 846f79d

Browse files
author
Matt Goldberg
committed
perf: iterate over CardPlay without allocation
1 parent c95e25a commit 846f79d

File tree

4 files changed

+61
-17
lines changed

4 files changed

+61
-17
lines changed

strategies/src/input_strategy.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,12 +227,11 @@ fn play_action_from_captures(caps: &Captures, actions: &[Action]) -> Result<Acti
227227
.filter(|cp| cp.size() == cards.len())
228228
// rank matches and all suits are accounted for?
229229
.filter(|cp| {
230-
let cp_cards = cp.to_vec();
231230
let suits: Vec<Suit> = cards.iter().filter_map(|c| c.1).collect();
232231
cp.rank() == rank
233232
&& suits
234233
.iter()
235-
.all(|suit| cp_cards.iter().any(|c| c.suit() == *suit))
234+
.all(|suit| cp.cards().any(|c| c.suit() == *suit))
236235
})
237236
.next()
238237
.ok_or_else(|| format!("Unable to find a permitted action matching the input string"))?;

types/src/action.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ impl Display for Action {
1818
Action::SendCard { card, .. } => format!("Send {card}"),
1919
Action::Pass => "Pass".to_string(),
2020
Action::PlayCards { card_play } => {
21-
format!("Play {}", card_play.to_vec().iter().join(","))
21+
let cards = card_play.cards().map(|card| format!("{card}")).join(",");
22+
format!("Play {cards}")
2223
}
2324
};
2425
write!(f, "{}", string)

types/src/card_play.rs

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{cmp::Ordering, fmt::Display};
1+
use std::{cmp::Ordering, fmt::Display, iter::FusedIterator};
22

33
use deckofcards::Rank;
44
use itertools::Itertools;
@@ -18,10 +18,7 @@ impl Display for CardPlay {
1818
write!(
1919
f,
2020
"({})",
21-
self.to_vec()
22-
.iter()
23-
.map(|card| format!("{}", card))
24-
.join(", ")
21+
self.cards().map(|card| format!("{}", card)).join(", ")
2522
)
2623
}
2724
}
@@ -60,15 +57,17 @@ impl CardPlay {
6057
),
6158
}
6259
}
63-
pub fn to_vec(self: &CardPlay) -> Vec<Card> {
64-
match self {
65-
CardPlay::Single(card) => vec![*card],
66-
CardPlay::Pair(card1, card2) => vec![*card1, *card2],
67-
CardPlay::Triple(card1, card2, card3) => vec![*card1, *card2, *card3],
68-
CardPlay::Quad(card1, card2, card3, card4) => vec![*card1, *card2, *card3, *card4],
60+
pub fn cards(&self) -> CardPlayCards<'_> {
61+
CardPlayCards {
62+
card_play: self,
63+
idx: 0,
6964
}
7065
}
7166

67+
pub fn to_vec(&self) -> Vec<Card> {
68+
self.cards().collect()
69+
}
70+
7271
pub fn size(&self) -> usize {
7372
match self {
7473
CardPlay::Single(_) => 1,
@@ -96,3 +95,48 @@ impl CardPlay {
9695
}
9796
}
9897
}
98+
99+
pub struct CardPlayCards<'a> {
100+
card_play: &'a CardPlay,
101+
idx: usize,
102+
}
103+
104+
impl<'a> Iterator for CardPlayCards<'a> {
105+
type Item = Card;
106+
107+
fn next(&mut self) -> Option<Self::Item> {
108+
let card = match (self.card_play, self.idx) {
109+
(CardPlay::Single(card), 0) => Some(*card),
110+
(CardPlay::Pair(card1, card2), idx) => match idx {
111+
0 => Some(*card1),
112+
1 => Some(*card2),
113+
_ => None,
114+
},
115+
(CardPlay::Triple(card1, card2, card3), idx) => match idx {
116+
0 => Some(*card1),
117+
1 => Some(*card2),
118+
2 => Some(*card3),
119+
_ => None,
120+
},
121+
(CardPlay::Quad(card1, card2, card3, card4), idx) => match idx {
122+
0 => Some(*card1),
123+
1 => Some(*card2),
124+
2 => Some(*card3),
125+
3 => Some(*card4),
126+
_ => None,
127+
},
128+
_ => None,
129+
}?;
130+
self.idx += 1;
131+
Some(card)
132+
}
133+
134+
fn size_hint(&self) -> (usize, Option<usize>) {
135+
let remaining = self.card_play.size().saturating_sub(self.idx);
136+
(remaining, Some(remaining))
137+
}
138+
}
139+
140+
impl<'a> ExactSizeIterator for CardPlayCards<'a> {}
141+
142+
impl<'a> FusedIterator for CardPlayCards<'a> {}

types/src/game_state.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ impl GameState {
118118
let (_, starting_card) = self.starting_player_and_card();
119119
actions.retain(|action| match action {
120120
Action::PlayCards { card_play } => {
121-
card_play.to_vec().iter().any(|&card| card == starting_card)
121+
card_play.cards().any(|card| card == starting_card)
122122
}
123123
_ => false,
124124
});
@@ -140,8 +140,8 @@ impl GameState {
140140
}
141141
Action::Pass => {}
142142
Action::PlayCards { card_play } => {
143-
for card in &card_play.to_vec() {
144-
let removed = player.state.current_hand.remove_card(card);
143+
for card in card_play.cards() {
144+
let removed = player.state.current_hand.remove_card(&card);
145145
assert!(
146146
removed,
147147
"Attempted to play a card {:?} that wasn't in the hand!",

0 commit comments

Comments
 (0)