seed deck in simulator, use iterators more
This commit is contained in:
parent
b19e6ff615
commit
678a8f26a7
5 changed files with 103 additions and 135 deletions
118
src/game.rs
118
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<Color, Firework> = 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::<HashMap<_, _>>();
|
||||
|
||||
let total_cards = deck.len() as u32;
|
||||
|
||||
BoardState {
|
||||
|
@ -283,16 +264,12 @@ impl BoardState {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_players(&self) -> Vec<Player> {
|
||||
(0..self.num_players).collect::<Vec<_>>()
|
||||
pub fn get_players(&self) -> Range<Player> {
|
||||
(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<SimpleCardInfo> = Vec::new();
|
||||
for card_info in borrowed_view.info.iter() {
|
||||
info.push((*card_info).clone());
|
||||
}
|
||||
let mut other_player_states : HashMap<Player, PlayerState> = 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::<Vec<_>>();
|
||||
|
||||
let other_player_states = borrowed_view.other_player_states.iter()
|
||||
.map(|(&other_player, &player_state)| {
|
||||
(other_player, player_state.clone())
|
||||
}).collect::<HashMap<_, _>>();
|
||||
|
||||
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<Player, PlayerState> = HashMap::new();
|
||||
for i in 0..opts.num_players {
|
||||
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::<Vec<_>>();
|
||||
player_states.insert(
|
||||
i, PlayerState::new(hand),
|
||||
);
|
||||
}
|
||||
(player, PlayerState::new(hand))
|
||||
}).collect::<HashMap<_, _>>();
|
||||
|
||||
GameState {
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
|
13
src/info.rs
13
src/info.rs
|
@ -142,11 +142,8 @@ pub trait Info<T> where T: Hash + Eq + Clone + Copy {
|
|||
}
|
||||
|
||||
fn initialize() -> HashSet<T> {
|
||||
let mut possible_map : HashSet<T> = 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::<HashSet<_>>()
|
||||
}
|
||||
|
||||
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) {
|
||||
if info {
|
||||
self.mark_true(value);
|
||||
} else {
|
||||
self.mark_false(value);
|
||||
}
|
||||
if info { self.mark_true(value); } else { self.mark_false(value); }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<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(
|
||||
opts: &GameOptions,
|
||||
game_strategy: Box<GameStrategy>,
|
||||
|
@ -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<Player, Box<PlayerStrategy>> = 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::<HashMap<Player, Box<PlayerStrategy>>>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,9 +44,9 @@ impl CheatingStrategy {
|
|||
}
|
||||
impl GameStrategy for CheatingStrategy {
|
||||
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(
|
||||
*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::<Vec<_>>();
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -220,11 +220,12 @@ impl InformationStrategy {
|
|||
}
|
||||
impl GameStrategy for InformationStrategy {
|
||||
fn initialize(&self, player: Player, view: &BorrowedGameView) -> Box<PlayerStrategy> {
|
||||
let mut public_info = HashMap::new();
|
||||
for player in view.board.get_players() {
|
||||
let public_info =
|
||||
view.board.get_players().map(|player| {
|
||||
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 {
|
||||
me: player,
|
||||
public_info: public_info,
|
||||
|
@ -316,12 +317,14 @@ impl InformationPlayerStrategy {
|
|||
fn answer_questions(
|
||||
questions: &Vec<Box<Question>>, 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);
|
||||
|
|
Loading…
Reference in a new issue