seed deck in simulator, use iterators more

This commit is contained in:
Jeff Wu 2016-04-02 15:14:05 -07:00
parent b19e6ff615
commit 678a8f26a7
5 changed files with 103 additions and 135 deletions

View file

@ -1,8 +1,8 @@
use rand::{self, Rng, SeedableRng};
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::iter; use std::iter;
use std::slice::IterMut; use std::slice::IterMut;
use std::ops::Range;
pub use info::*; pub use info::*;
pub use cards::*; 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 // State of everything except the player's hands
// Is all completely common knowledge // Is all completely common knowledge
#[derive(Debug,Clone)] #[derive(Debug,Clone)]
@ -179,12 +161,11 @@ pub struct BoardState {
pub deckless_turns_remaining: u32, pub deckless_turns_remaining: u32,
} }
impl BoardState { impl BoardState {
pub fn new(opts: &GameOptions, seed: u32) -> BoardState { pub fn new(opts: &GameOptions, deck: Cards) -> BoardState {
let mut fireworks : HashMap<Color, Firework> = HashMap::new(); let fireworks = COLORS.iter().map(|&color| {
for &color in COLORS.iter() { (color, Firework::new(color))
fireworks.insert(color, Firework::new(color)); }).collect::<HashMap<_, _>>();
}
let deck = new_deck(seed);
let total_cards = deck.len() as u32; let total_cards = deck.len() as u32;
BoardState { BoardState {
@ -283,16 +264,12 @@ impl BoardState {
} }
} }
pub fn get_players(&self) -> Vec<Player> { pub fn get_players(&self) -> Range<Player> {
(0..self.num_players).collect::<Vec<_>>() (0..self.num_players)
} }
pub fn score(&self) -> Score { pub fn score(&self) -> Score {
let mut score = 0; self.fireworks.iter().map(|(_, firework)| firework.score()).fold(0, |a, b| a + b)
for (_, firework) in &self.fireworks {
score += firework.score();
}
score as u32
} }
pub fn deck_size(&self) -> u32 { pub fn deck_size(&self) -> u32 {
@ -373,37 +350,27 @@ pub trait GameView {
} }
fn has_card(&self, player: &Player, card: &Card) -> bool { fn has_card(&self, player: &Player, card: &Card) -> bool {
for other_card in self.get_hand(player) { self.get_hand(player).iter().position(|other_card| {
if *card == *other_card { card == other_card
return true; }).is_some()
}
}
false
} }
fn can_see(&self, card: &Card) -> bool { fn can_see(&self, card: &Card) -> bool {
for other_player in self.get_board().get_players() { self.get_board().get_players().filter(|&player| {
if self.me() == other_player { player != self.me()
continue }).any(|player| {
} self.has_card(&player, card)
if self.has_card(&other_player, card) { })
return true;
}
}
false
} }
fn someone_else_can_play(&self) -> bool { fn someone_else_can_play(&self) -> bool {
for player in self.get_board().get_players() { self.get_board().get_players().filter(|&player| {
if player != self.me() { player != self.me()
for card in self.get_hand(&player) { }).any(|player| {
if self.get_board().is_playable(card) { self.get_hand(&player).iter().any(|card| {
return true; self.get_board().is_playable(card)
} })
} })
}
}
false
} }
} }
@ -449,14 +416,13 @@ pub struct OwnedGameView {
} }
impl OwnedGameView { impl OwnedGameView {
pub fn clone_from(borrowed_view: &BorrowedGameView) -> OwnedGameView { pub fn clone_from(borrowed_view: &BorrowedGameView) -> OwnedGameView {
let mut info : Vec<SimpleCardInfo> = Vec::new(); let info = borrowed_view.info.iter()
for card_info in borrowed_view.info.iter() { .map(|card_info| card_info.clone()).collect::<Vec<_>>();
info.push((*card_info).clone());
} let other_player_states = borrowed_view.other_player_states.iter()
let mut other_player_states : HashMap<Player, PlayerState> = HashMap::new(); .map(|(&other_player, &player_state)| {
for (other_player, player_state) in &borrowed_view.other_player_states { (other_player, player_state.clone())
other_player_states.insert(*other_player, (*player_state).clone()); }).collect::<HashMap<_, _>>();
}
OwnedGameView { OwnedGameView {
player: borrowed_view.player.clone(), player: borrowed_view.player.clone(),
@ -508,19 +474,17 @@ impl fmt::Display for GameState {
} }
impl GameState { impl GameState {
pub fn new(opts: &GameOptions, seed: u32) -> GameState { pub fn new(opts: &GameOptions, deck: Cards) -> GameState {
let mut board = BoardState::new(opts, seed); let mut board = BoardState::new(opts, deck);
let mut player_states : HashMap<Player, PlayerState> = HashMap::new(); let player_states =
for i in 0..opts.num_players { (0..opts.num_players).map(|player| {
let hand = (0..opts.hand_size).map(|_| { let hand = (0..opts.hand_size).map(|_| {
// we can assume the deck is big enough to draw initial hands // we can assume the deck is big enough to draw initial hands
board.deck.pop().unwrap() board.deck.pop().unwrap()
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
player_states.insert( (player, PlayerState::new(hand))
i, PlayerState::new(hand), }).collect::<HashMap<_, _>>();
);
}
GameState { GameState {
player_states: player_states, player_states: player_states,
@ -528,7 +492,7 @@ impl GameState {
} }
} }
pub fn get_players(&self) -> Vec<Player> { pub fn get_players(&self) -> Range<Player> {
self.board.get_players() self.board.get_players()
} }
@ -543,9 +507,9 @@ impl GameState {
// get the game state view of a particular player // get the game state view of a particular player
pub fn get_view(&self, player: Player) -> BorrowedGameView { pub fn get_view(&self, player: Player) -> BorrowedGameView {
let mut other_player_states = HashMap::new(); let mut other_player_states = HashMap::new();
for (other_player, state) in &self.player_states { for (&other_player, state) in &self.player_states {
if player != *other_player { if player != other_player {
other_player_states.insert(*other_player, state); other_player_states.insert(other_player, state);
} }
} }
BorrowedGameView { BorrowedGameView {

View file

@ -142,11 +142,8 @@ pub trait Info<T> where T: Hash + Eq + Clone + Copy {
} }
fn initialize() -> HashSet<T> { fn initialize() -> HashSet<T> {
let mut possible_map : HashSet<T> = HashSet::new(); Self::get_all_possibilities().iter()
for value in Self::get_all_possibilities().iter() { .map(|val| val.clone()).collect::<HashSet<_>>()
possible_map.insert(value.clone());
}
possible_map
} }
fn mark_true(&mut self, value: T) { fn mark_true(&mut self, value: T) {
@ -160,11 +157,7 @@ pub trait Info<T> where T: Hash + Eq + Clone + Copy {
} }
fn mark(&mut self, value: T, info: bool) { fn mark(&mut self, value: T, info: bool) {
if info { if info { self.mark_true(value); } else { self.mark_false(value); }
self.mark_true(value);
} else {
self.mark_false(value);
}
} }
} }

View file

@ -1,4 +1,4 @@
use rand::{self, Rng}; use rand::{self, Rng, SeedableRng};
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use crossbeam; use crossbeam;
@ -29,6 +29,24 @@ pub trait GameStrategyConfig {
fn initialize(&self, &GameOptions) -> Box<GameStrategy>; fn initialize(&self, &GameOptions) -> Box<GameStrategy>;
} }
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( pub fn simulate_once(
opts: &GameOptions, opts: &GameOptions,
game_strategy: Box<GameStrategy>, game_strategy: Box<GameStrategy>,
@ -36,16 +54,13 @@ pub fn simulate_once(
) -> GameState { ) -> GameState {
let seed = seed_opt.unwrap_or(rand::thread_rng().next_u32()); 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<Player, Box<PlayerStrategy>> = HashMap::new(); let mut strategies = game.get_players().map(|player| {
for player in game.get_players() { (player, game_strategy.initialize(player.clone(), &game.get_view(player)))
strategies.insert( }).collect::<HashMap<Player, Box<PlayerStrategy>>>();
player,
game_strategy.initialize(player.clone(), &game.get_view(player)),
);
}
while !game.is_over() { while !game.is_over() {
let player = game.board.player; let player = game.board.player;
@ -110,8 +125,8 @@ impl Histogram {
(self.sum as f32) / (self.total_count as f32) (self.sum as f32) / (self.total_count as f32)
} }
pub fn merge(&mut self, other: Histogram) { pub fn merge(&mut self, other: Histogram) {
for (val, count) in other.hist.iter() { for (val, count) in other.hist.into_iter() {
self.insert_many(*val, *count); self.insert_many(val, count);
} }
} }
} }

View file

@ -44,9 +44,9 @@ impl CheatingStrategy {
} }
impl GameStrategy for CheatingStrategy { impl GameStrategy for CheatingStrategy {
fn initialize(&self, player: Player, view: &BorrowedGameView) -> Box<PlayerStrategy> { fn initialize(&self, player: Player, view: &BorrowedGameView) -> Box<PlayerStrategy> {
for (player, state) in &view.other_player_states { for (&player, state) in &view.other_player_states {
self.player_states_cheat.borrow_mut().insert( self.player_states_cheat.borrow_mut().insert(
*player, state.hand.clone() player, state.hand.clone()
); );
} }
Box::new(CheatingPlayerStrategy { Box::new(CheatingPlayerStrategy {
@ -141,28 +141,23 @@ impl PlayerStrategy for CheatingPlayerStrategy {
let states = self.player_states_cheat.borrow(); let states = self.player_states_cheat.borrow();
let my_cards = states.get(&self.me).unwrap(); 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) view.board.is_playable(card)
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
if playable_cards.len() > 0 { if playable_cards.len() > 0 {
// play the best playable card // play the best playable card
// the higher the play_score, the better to play // the higher the play_score, the better to play
let mut play_card = None; let mut index = 0;
let mut play_score = -1; 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); let score = self.get_play_score(view, card);
if score > play_score { if score > play_score {
play_card = Some(card); index = i;
play_score = score; play_score = score;
} }
} }
let index = my_cards.iter().position(|card| {
card == play_card.unwrap()
}).unwrap();
return TurnChoice::Play(index) return TurnChoice::Play(index)
} }

View file

@ -220,11 +220,12 @@ impl InformationStrategy {
} }
impl GameStrategy for InformationStrategy { impl GameStrategy for InformationStrategy {
fn initialize(&self, player: Player, view: &BorrowedGameView) -> Box<PlayerStrategy> { fn initialize(&self, player: Player, view: &BorrowedGameView) -> Box<PlayerStrategy> {
let mut public_info = HashMap::new(); let public_info =
for player in view.board.get_players() { view.board.get_players().map(|player| {
let hand_info = (0..view.board.hand_size).map(|_| { CardPossibilityTable::new() }).collect::<Vec<_>>(); let hand_info = (0..view.board.hand_size).map(|_| { CardPossibilityTable::new() }).collect::<Vec<_>>();
public_info.insert(player, hand_info); (player, hand_info)
} }).collect::<HashMap<_,_>>();
Box::new(InformationPlayerStrategy { Box::new(InformationPlayerStrategy {
me: player, me: player,
public_info: public_info, public_info: public_info,
@ -316,12 +317,14 @@ impl InformationPlayerStrategy {
fn answer_questions( fn answer_questions(
questions: &Vec<Box<Question>>, hand: &Cards, view: &OwnedGameView questions: &Vec<Box<Question>>, hand: &Cards, view: &OwnedGameView
) -> ModulusInformation { ) -> ModulusInformation {
let mut info = ModulusInformation::none(); questions.iter()
for question in questions { .fold(
let answer_info = question.answer_info(hand, view); ModulusInformation::none(),
info.combine(answer_info); |mut answer_info, question| {
} let new_answer_info = question.answer_info(hand, view);
info answer_info.combine(new_answer_info);
answer_info
})
} }
fn get_hint_info_for_player( fn get_hint_info_for_player(
@ -338,19 +341,18 @@ impl InformationPlayerStrategy {
} }
fn get_hint_sum_info(&self, total_info: u32, view: &OwnedGameView) -> ModulusInformation { fn get_hint_sum_info(&self, total_info: u32, view: &OwnedGameView) -> ModulusInformation {
let mut sum = ModulusInformation::new(total_info, 0); view.get_board().get_players().filter(|&player| {
for player in view.get_board().get_players() { player != self.me
if 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); let answer = self.get_hint_info_for_player(&player, total_info, view);
sum.add(&answer); sum_info.add(&answer);
} sum_info
} })
trace!("Summed answer {:?}\n", sum);
sum
} }
fn infer_own_from_hint_sum(&mut self, hint: ModulusInformation) { fn infer_own_from_hint_sum(&mut self, mut hint: ModulusInformation) {
let mut hint = hint;
let questions = { let questions = {
let view = &self.last_view; let view = &self.last_view;
let hand_info = self.get_my_public_info(); let hand_info = self.get_my_public_info();
@ -375,14 +377,13 @@ impl InformationPlayerStrategy {
self.return_public_info(&me, hand_info); 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 hinter = self.last_view.board.player;
let players = { let players = {
let view = &self.last_view; let view = &self.last_view;
view.board.get_players() view.board.get_players()
}; };
trace!("{}: inferring for myself, starting with {:?}", self.me, hint); trace!("{}: inferring for myself, starting with {:?}", self.me, hint);
let mut hint = hint;
for player in players { for player in players {
if (player != hinter) && (player != self.me) { if (player != hinter) && (player != self.me) {
{ {
@ -725,8 +726,8 @@ impl PlayerStrategy for InformationPlayerStrategy {
// we already stored the view // we already stored the view
let view = &self.last_view; let view = &self.last_view;
for player in view.board.get_players().iter() { for player in view.board.get_players() {
let hand_info = self.get_player_public_info(player); let hand_info = self.get_player_public_info(&player);
debug!("Current state of hand_info for {}:", player); debug!("Current state of hand_info for {}:", player);
for (i, card_table) in hand_info.iter().enumerate() { for (i, card_table) in hand_info.iter().enumerate() {
debug!(" Card {}: {}", i, card_table); debug!(" Card {}: {}", i, card_table);