fn random(&self) -> Option<&Card> {
self.cards.choose(&mut rand::thread_rng())
}
+ /// Which suits are in this Hand?
+ fn suits(&self) -> Vec<Suit> {
+ self.cards
+ .iter()
+ .map(|c| c.suit().expect("I shouldn't have jokers in my hand"))
+ .collect()
+ }
+ /// Make a new Hand that contains only cards of the requested suit
+ fn filter_by_suit(&self, suit: Suit) -> Self {
+ self.filter_by_suits(&[suit])
+ }
+ /// Make a new Hand that contains only cards of the requested suits
+ fn filter_by_suits(&self, suits: &[Suit]) -> Self {
+ Self {
+ cards: self
+ .cards
+ .iter()
+ .filter(|c| suits.contains(&c.suit().expect("I shouldn't have jokers in my hand")))
+ .copied()
+ .collect(),
+ }
+ }
}
#[derive(Copy, Clone)]
pub fn current_player_hand(&self) -> &Hand {
&self.hands[self.turn.0]
}
+ #[must_use]
+ pub fn next_player_hand(&self) -> &Hand {
+ &self.hands[self.turn.next(self.hands.len()).0]
+ }
+ #[must_use]
fn player_hand_mut(&mut self, pi: PlayerIndex) -> &mut Hand {
&mut self.hands[pi.0]
}
+ #[must_use]
fn current_player_hand_mut(&mut self) -> &mut Hand {
self.player_hand_mut(self.turn)
}
}
}
-pub fn random_player(draw_chance: f64) -> impl FnMut(&Game) -> Play {
- move |game: &Game| -> Play {
+#[must_use]
+pub fn random_player(draw_chance: f64) -> Player {
+ Player(Box::new(move |game: &Game| -> Play {
match game.phase {
Phase::Play => Play::Play(
*game
}
}
}
- }
+ }))
+}
+
+/// When available, make plays that grant momentum.
+#[must_use]
+pub fn momentum_player(mut fallback: Player) -> Player {
+ Player(Box::new(move |game: &Game| -> Play {
+ if game.phase == Phase::Play {
+ if let Some(suit) = game.discard.top().and_then(Card::suit) {
+ if let Some(card) = game.current_player_hand().filter_by_suit(suit).random() {
+ return Play::Play(*card);
+ }
+ }
+ }
+ fallback.0(game)
+ }))
+}
+
+/// Try to coordinate to give the next player a momentum opportunity.
+#[must_use]
+pub fn coordinating_player(mut fallback: Player) -> Player {
+ Player(Box::new(move |game: &Game| -> Play {
+ if let Some(card) = game
+ .current_player_hand()
+ .filter_by_suits(&game.next_player_hand().suits())
+ .random()
+ {
+ return Play::Play(*card);
+ }
+ fallback.0(game)
+ }))
}
/// # Errors
#[test]
fn test_game() {
for num_players in 1..10 {
- let players: Vec<_> = std::iter::from_fn(|| Some(Player::new(random_player(0.5))))
- .take(num_players)
- .collect();
+ let players: Vec<_> = std::iter::from_fn(|| {
+ Some(momentum_player(coordinating_player(random_player(0.5))))
+ })
+ .take(num_players)
+ .collect();
let mut game = Game::default();
for _ in 0..num_players {
game.add_player();