diff --git a/src/game.rs b/src/game.rs index 9e50609..04a407d 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,8 +1,8 @@ -use rand::{self, Rng, SeedableRng}; use std::collections::HashMap; use std::fmt; use std::iter; use std::slice::IterMut; +use std::ops::Range; pub use info::*; pub use cards::*; @@ -134,24 +134,6 @@ impl PlayerState { } } -fn new_deck(seed: u32) -> Cards { - let mut deck: Cards = Cards::new(); - - for &color in COLORS.iter() { - for &value in VALUES.iter() { - let count = get_count_for_value(value); - for _ in 0..count { - deck.push(Card::new(color, value)); - } - } - }; - - rand::ChaChaRng::from_seed(&[seed]).shuffle(&mut deck[..]); - - trace!("Created deck: {:?}", deck); - deck -} - // State of everything except the player's hands // Is all completely common knowledge #[derive(Debug,Clone)] @@ -179,12 +161,11 @@ pub struct BoardState { pub deckless_turns_remaining: u32, } impl BoardState { - pub fn new(opts: &GameOptions, seed: u32) -> BoardState { - let mut fireworks : HashMap = HashMap::new(); - for &color in COLORS.iter() { - fireworks.insert(color, Firework::new(color)); - } - let deck = new_deck(seed); + pub fn new(opts: &GameOptions, deck: Cards) -> BoardState { + let fireworks = COLORS.iter().map(|&color| { + (color, Firework::new(color)) + }).collect::>(); + let total_cards = deck.len() as u32; BoardState { @@ -283,16 +264,12 @@ impl BoardState { } } - pub fn get_players(&self) -> Vec { - (0..self.num_players).collect::>() + pub fn get_players(&self) -> Range { + (0..self.num_players) } pub fn score(&self) -> Score { - let mut score = 0; - for (_, firework) in &self.fireworks { - score += firework.score(); - } - score as u32 + self.fireworks.iter().map(|(_, firework)| firework.score()).fold(0, |a, b| a + b) } pub fn deck_size(&self) -> u32 { @@ -373,37 +350,27 @@ pub trait GameView { } fn has_card(&self, player: &Player, card: &Card) -> bool { - for other_card in self.get_hand(player) { - if *card == *other_card { - return true; - } - } - false + self.get_hand(player).iter().position(|other_card| { + card == other_card + }).is_some() } fn can_see(&self, card: &Card) -> bool { - for other_player in self.get_board().get_players() { - if self.me() == other_player { - continue - } - if self.has_card(&other_player, card) { - return true; - } - } - false + self.get_board().get_players().filter(|&player| { + player != self.me() + }).any(|player| { + self.has_card(&player, card) + }) } fn someone_else_can_play(&self) -> bool { - for player in self.get_board().get_players() { - if player != self.me() { - for card in self.get_hand(&player) { - if self.get_board().is_playable(card) { - return true; - } - } - } - } - false + self.get_board().get_players().filter(|&player| { + player != self.me() + }).any(|player| { + self.get_hand(&player).iter().any(|card| { + self.get_board().is_playable(card) + }) + }) } } @@ -449,14 +416,13 @@ pub struct OwnedGameView { } impl OwnedGameView { pub fn clone_from(borrowed_view: &BorrowedGameView) -> OwnedGameView { - let mut info : Vec = Vec::new(); - for card_info in borrowed_view.info.iter() { - info.push((*card_info).clone()); - } - let mut other_player_states : HashMap = HashMap::new(); - for (other_player, player_state) in &borrowed_view.other_player_states { - other_player_states.insert(*other_player, (*player_state).clone()); - } + let info = borrowed_view.info.iter() + .map(|card_info| card_info.clone()).collect::>(); + + let other_player_states = borrowed_view.other_player_states.iter() + .map(|(&other_player, &player_state)| { + (other_player, player_state.clone()) + }).collect::>(); OwnedGameView { player: borrowed_view.player.clone(), @@ -508,19 +474,17 @@ impl fmt::Display for GameState { } impl GameState { - pub fn new(opts: &GameOptions, seed: u32) -> GameState { - let mut board = BoardState::new(opts, seed); + pub fn new(opts: &GameOptions, deck: Cards) -> GameState { + let mut board = BoardState::new(opts, deck); - let mut player_states : HashMap = HashMap::new(); - for i in 0..opts.num_players { - let hand = (0..opts.hand_size).map(|_| { + let player_states = + (0..opts.num_players).map(|player| { + let hand = (0..opts.hand_size).map(|_| { // we can assume the deck is big enough to draw initial hands board.deck.pop().unwrap() }).collect::>(); - player_states.insert( - i, PlayerState::new(hand), - ); - } + (player, PlayerState::new(hand)) + }).collect::>(); GameState { player_states: player_states, @@ -528,7 +492,7 @@ impl GameState { } } - pub fn get_players(&self) -> Vec { + pub fn get_players(&self) -> Range { self.board.get_players() } @@ -543,9 +507,9 @@ impl GameState { // get the game state view of a particular player pub fn get_view(&self, player: Player) -> BorrowedGameView { let mut other_player_states = HashMap::new(); - for (other_player, state) in &self.player_states { - if player != *other_player { - other_player_states.insert(*other_player, state); + for (&other_player, state) in &self.player_states { + if player != other_player { + other_player_states.insert(other_player, state); } } BorrowedGameView { diff --git a/src/info.rs b/src/info.rs index 6675bbd..a8289f6 100644 --- a/src/info.rs +++ b/src/info.rs @@ -142,11 +142,8 @@ pub trait Info where T: Hash + Eq + Clone + Copy { } fn initialize() -> HashSet { - let mut possible_map : HashSet = HashSet::new(); - for value in Self::get_all_possibilities().iter() { - possible_map.insert(value.clone()); - } - possible_map + Self::get_all_possibilities().iter() + .map(|val| val.clone()).collect::>() } fn mark_true(&mut self, value: T) { @@ -160,11 +157,7 @@ pub trait Info where T: Hash + Eq + Clone + Copy { } fn mark(&mut self, value: T, info: bool) { - if info { - self.mark_true(value); - } else { - self.mark_false(value); - } + if info { self.mark_true(value); } else { self.mark_false(value); } } } diff --git a/src/simulator.rs b/src/simulator.rs index 5206eaf..9387194 100644 --- a/src/simulator.rs +++ b/src/simulator.rs @@ -1,4 +1,4 @@ -use rand::{self, Rng}; +use rand::{self, Rng, SeedableRng}; use std::collections::HashMap; use std::fmt; use crossbeam; @@ -29,6 +29,24 @@ pub trait GameStrategyConfig { fn initialize(&self, &GameOptions) -> Box; } +fn new_deck(seed: u32) -> Cards { + let mut deck: Cards = Cards::new(); + + for &color in COLORS.iter() { + for &value in VALUES.iter() { + let count = get_count_for_value(value); + for _ in 0..count { + deck.push(Card::new(color, value)); + } + } + }; + + rand::ChaChaRng::from_seed(&[seed]).shuffle(&mut deck[..]); + + trace!("Created deck: {:?}", deck); + deck +} + pub fn simulate_once( opts: &GameOptions, game_strategy: Box, @@ -36,16 +54,13 @@ pub fn simulate_once( ) -> GameState { let seed = seed_opt.unwrap_or(rand::thread_rng().next_u32()); + let deck = new_deck(seed); - let mut game = GameState::new(opts, seed); + let mut game = GameState::new(opts, deck); - let mut strategies : HashMap> = HashMap::new(); - for player in game.get_players() { - strategies.insert( - player, - game_strategy.initialize(player.clone(), &game.get_view(player)), - ); - } + let mut strategies = game.get_players().map(|player| { + (player, game_strategy.initialize(player.clone(), &game.get_view(player))) + }).collect::>>(); while !game.is_over() { let player = game.board.player; @@ -110,8 +125,8 @@ impl Histogram { (self.sum as f32) / (self.total_count as f32) } pub fn merge(&mut self, other: Histogram) { - for (val, count) in other.hist.iter() { - self.insert_many(*val, *count); + for (val, count) in other.hist.into_iter() { + self.insert_many(val, count); } } } diff --git a/src/strategies/cheating.rs b/src/strategies/cheating.rs index aec01d3..f7e362e 100644 --- a/src/strategies/cheating.rs +++ b/src/strategies/cheating.rs @@ -44,9 +44,9 @@ impl CheatingStrategy { } impl GameStrategy for CheatingStrategy { fn initialize(&self, player: Player, view: &BorrowedGameView) -> Box { - for (player, state) in &view.other_player_states { + for (&player, state) in &view.other_player_states { self.player_states_cheat.borrow_mut().insert( - *player, state.hand.clone() + player, state.hand.clone() ); } Box::new(CheatingPlayerStrategy { @@ -141,28 +141,23 @@ impl PlayerStrategy for CheatingPlayerStrategy { let states = self.player_states_cheat.borrow(); let my_cards = states.get(&self.me).unwrap(); - let playable_cards = my_cards.iter().filter(|card| { + let playable_cards = my_cards.iter().enumerate().filter(|&(_, card)| { view.board.is_playable(card) }).collect::>(); if playable_cards.len() > 0 { // play the best playable card // the higher the play_score, the better to play - let mut play_card = None; + let mut index = 0; let mut play_score = -1; - for card in playable_cards { + for &(i, card) in playable_cards.iter() { let score = self.get_play_score(view, card); if score > play_score { - play_card = Some(card); + index = i; play_score = score; } } - - let index = my_cards.iter().position(|card| { - card == play_card.unwrap() - }).unwrap(); - return TurnChoice::Play(index) } diff --git a/src/strategies/information.rs b/src/strategies/information.rs index 7831c00..a936773 100644 --- a/src/strategies/information.rs +++ b/src/strategies/information.rs @@ -220,11 +220,12 @@ impl InformationStrategy { } impl GameStrategy for InformationStrategy { fn initialize(&self, player: Player, view: &BorrowedGameView) -> Box { - let mut public_info = HashMap::new(); - for player in view.board.get_players() { - let hand_info = (0..view.board.hand_size).map(|_| { CardPossibilityTable::new() }).collect::>(); - public_info.insert(player, hand_info); - } + let public_info = + view.board.get_players().map(|player| { + let hand_info = (0..view.board.hand_size).map(|_| { CardPossibilityTable::new() }).collect::>(); + (player, hand_info) + }).collect::>(); + Box::new(InformationPlayerStrategy { me: player, public_info: public_info, @@ -316,12 +317,14 @@ impl InformationPlayerStrategy { fn answer_questions( questions: &Vec>, hand: &Cards, view: &OwnedGameView ) -> ModulusInformation { - let mut info = ModulusInformation::none(); - for question in questions { - let answer_info = question.answer_info(hand, view); - info.combine(answer_info); - } - info + questions.iter() + .fold( + ModulusInformation::none(), + |mut answer_info, question| { + let new_answer_info = question.answer_info(hand, view); + answer_info.combine(new_answer_info); + answer_info + }) } fn get_hint_info_for_player( @@ -338,19 +341,18 @@ impl InformationPlayerStrategy { } fn get_hint_sum_info(&self, total_info: u32, view: &OwnedGameView) -> ModulusInformation { - let mut sum = ModulusInformation::new(total_info, 0); - for player in view.get_board().get_players() { - if player != self.me { + view.get_board().get_players().filter(|&player| { + player != self.me + }).fold( + ModulusInformation::new(total_info, 0), + |mut sum_info, player| { let answer = self.get_hint_info_for_player(&player, total_info, view); - sum.add(&answer); - } - } - trace!("Summed answer {:?}\n", sum); - sum + sum_info.add(&answer); + sum_info + }) } - fn infer_own_from_hint_sum(&mut self, hint: ModulusInformation) { - let mut hint = hint; + fn infer_own_from_hint_sum(&mut self, mut hint: ModulusInformation) { let questions = { let view = &self.last_view; let hand_info = self.get_my_public_info(); @@ -375,14 +377,13 @@ impl InformationPlayerStrategy { self.return_public_info(&me, hand_info); } - fn update_from_hint_sum(&mut self, hint: ModulusInformation) { + fn update_from_hint_sum(&mut self, mut hint: ModulusInformation) { let hinter = self.last_view.board.player; let players = { let view = &self.last_view; view.board.get_players() }; trace!("{}: inferring for myself, starting with {:?}", self.me, hint); - let mut hint = hint; for player in players { if (player != hinter) && (player != self.me) { { @@ -725,8 +726,8 @@ impl PlayerStrategy for InformationPlayerStrategy { // we already stored the view let view = &self.last_view; - for player in view.board.get_players().iter() { - let hand_info = self.get_player_public_info(player); + for player in view.board.get_players() { + let hand_info = self.get_player_public_info(&player); debug!("Current state of hand_info for {}:", player); for (i, card_table) in hand_info.iter().enumerate() { debug!(" Card {}: {}", i, card_table);