strategy that cheats, first pass

This commit is contained in:
Jeff Wu 2016-03-13 01:05:05 -08:00
parent a16f490c04
commit 2f6dc571c2
4 changed files with 102 additions and 20 deletions

View File

@ -30,7 +30,7 @@ pub fn get_count_for_value(value: &Value) -> usize {
pub type Player = u32; pub type Player = u32;
#[derive(Debug)] #[derive(Debug,Clone,PartialEq)]
pub struct Card { pub struct Card {
pub color: Color, pub color: Color,
pub value: Value, pub value: Value,
@ -227,9 +227,9 @@ pub struct GameOptions {
#[derive(Debug)] #[derive(Debug)]
pub struct PlayerState { pub struct PlayerState {
// the player's actual hand // the player's actual hand
hand: Cards, pub hand: Cards,
// represents what is common knowledge about the player's hand // represents what is common knowledge about the player's hand
info: CardsInfo, pub info: CardsInfo,
} }
impl fmt::Display for PlayerState { impl fmt::Display for PlayerState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -305,7 +305,7 @@ fn new_deck() -> Cards {
} }
}; };
shuffle(&mut deck); shuffle(&mut deck);
debug!("Created deck: {:?}", deck); trace!("Created deck: {:?}", deck);
deck deck
} }
@ -542,7 +542,7 @@ impl GameState {
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(player, state); other_player_states.insert(*other_player, state);
} }
} }
GameStateView { GameStateView {
@ -558,20 +558,20 @@ impl GameState {
let ref mut state = self.player_states.get_mut(&self.board.player).unwrap(); let ref mut state = self.player_states.get_mut(&self.board.player).unwrap();
let (card, _) = state.take(index); let (card, _) = state.take(index);
if let Some(new_card) = self.board.deck.pop() { if let Some(new_card) = self.board.deck.pop() {
info!("Drew new card, {}", new_card); debug!("Drew new card, {}", new_card);
state.place(new_card); state.place(new_card);
} }
card card
} }
pub fn process_choice(&mut self, choice: &TurnChoice) { pub fn process_choice(&mut self, choice: &TurnChoice) {
info!("Player {}'s move", self.board.player); debug!("Player {}'s move", self.board.player);
match choice { match choice {
&TurnChoice::Hint(ref hint) => { &TurnChoice::Hint(ref hint) => {
assert!(self.board.hints_remaining > 0, assert!(self.board.hints_remaining > 0,
"Tried to hint with no hints remaining"); "Tried to hint with no hints remaining");
self.board.hints_remaining -= 1; self.board.hints_remaining -= 1;
info!("Hint to player {}, about {}", hint.player, hint.hinted); debug!("Hint to player {}, about {}", hint.player, hint.hinted);
assert!(self.board.player != hint.player, assert!(self.board.player != hint.player,
format!("Player {} gave a hint to himself", hint.player)); format!("Player {} gave a hint to himself", hint.player));
@ -581,7 +581,7 @@ impl GameState {
} }
&TurnChoice::Discard(index) => { &TurnChoice::Discard(index) => {
let card = self.take_from_hand(index); let card = self.take_from_hand(index);
info!("Discard card in position {}, which is {}", index, card); debug!("Discard card in position {}, which is {}", index, card);
self.board.discard.place(card); self.board.discard.place(card);
self.board.try_add_hint(); self.board.try_add_hint();
@ -589,7 +589,7 @@ impl GameState {
&TurnChoice::Play(index) => { &TurnChoice::Play(index) => {
let card = self.take_from_hand(index); let card = self.take_from_hand(index);
info!( debug!(
"Playing card at position {}, which is {}", "Playing card at position {}, which is {}",
index, card index, card
); );
@ -599,15 +599,15 @@ impl GameState {
if self.board.is_playable(&card) { if self.board.is_playable(&card) {
let ref mut firework = self.board.fireworks.get_mut(&card.color).unwrap(); let ref mut firework = self.board.fireworks.get_mut(&card.color).unwrap();
firework_made = card.value == FINAL_VALUE; firework_made = card.value == FINAL_VALUE;
info!("Successfully played {}!", card); debug!("Successfully played {}!", card);
if firework_made { if firework_made {
info!("Firework complete for {}!", card.color); debug!("Firework complete for {}!", card.color);
} }
firework.place(card); firework.place(card);
} else { } else {
self.board.discard.place(card); self.board.discard.place(card);
self.board.lives_remaining -= 1; self.board.lives_remaining -= 1;
info!( debug!(
"Removing a life! Lives remaining: {}", "Removing a life! Lives remaining: {}",
self.board.lives_remaining self.board.lives_remaining
); );

View File

@ -6,6 +6,7 @@ mod game;
mod simulator; mod simulator;
mod strategies { mod strategies {
pub mod examples; pub mod examples;
pub mod cheating;
} }
mod info; mod info;
@ -27,7 +28,8 @@ impl log::Log for SimpleLogger {
fn main() { fn main() {
log::set_logger(|max_log_level| { log::set_logger(|max_log_level| {
max_log_level.set(log::LogLevelFilter::Trace); //max_log_level.set(log::LogLevelFilter::Trace);
max_log_level.set(log::LogLevelFilter::Info);
Box::new(SimpleLogger) Box::new(SimpleLogger)
}).unwrap(); }).unwrap();
@ -37,7 +39,7 @@ fn main() {
num_hints: 8, num_hints: 8,
num_lives: 3, num_lives: 3,
}; };
let n = 1; let n = 1000;
// simulator::simulate(&opts, &strategies::examples::AlwaysDiscard, n); // simulator::simulate(&opts, &strategies::examples::AlwaysDiscard, n);
// simulator::simulate_symmetric(&opts, strategies::examples::AlwaysPlayConfig, n); // simulator::simulate_symmetric(&opts, strategies::examples::AlwaysPlayConfig, n);
// simulator::simulate( // simulator::simulate(
@ -49,12 +51,17 @@ fn main() {
// Box::new(strategies::examples::AlwaysPlayConfig), // Box::new(strategies::examples::AlwaysPlayConfig),
// ], // ],
// n); // n);
// simulator::simulate_symmetric(
// &opts,
// strategies::examples::RandomStrategyConfig {
// hint_probability: 0.4,
// play_probability: 0.2,
// },
// n
// );
simulator::simulate_symmetric( simulator::simulate_symmetric(
&opts, &opts,
strategies::examples::RandomStrategyConfig { strategies::cheating::CheatingStrategyConfig::new(),
hint_probability: 0.4,
play_probability: 0.2,
},
n n
); );
} }

View File

@ -56,7 +56,7 @@ pub fn simulate<'a>(opts: &GameOptions, strat_configs: &Vec<Box<StrategyConfig +
let mut total_score = 0; let mut total_score = 0;
for _ in 0..n_trials { for _ in 0..n_trials {
let score = simulate_once(&opts, strat_configs); let score = simulate_once(&opts, strat_configs);
info!("Scored: {:?}", score); debug!("Scored: {:?}", score);
total_score += score; total_score += score;
} }
let average: f32 = (total_score as f32) / (n_trials as f32); let average: f32 = (total_score as f32) / (n_trials as f32);

View File

@ -0,0 +1,75 @@
use std::rc::Rc;
use std::cell::{RefCell};
use std::collections::HashMap;
use simulator::*;
use game::*;
// strategy that cheats by using Cell
// Plays according to the following rules:
// - if any card is playable,
// play the card with the lowest
// - if a card is
#[allow(dead_code)]
#[derive(Clone)]
pub struct CheatingStrategyConfig {
player_states_cheat: Rc<RefCell<HashMap<Player, Cards>>>,
}
impl CheatingStrategyConfig {
pub fn new() -> CheatingStrategyConfig {
CheatingStrategyConfig {
player_states_cheat: Rc::new(RefCell::new(HashMap::new())),
}
}
}
impl <'a> StrategyConfig for CheatingStrategyConfig {
fn initialize(&self, _: &Player, _: &GameStateView) -> Box<Strategy> {
Box::new(CheatingStrategy {
player_states_cheat: self.player_states_cheat.clone(),
})
}
}
pub struct CheatingStrategy {
player_states_cheat: Rc<RefCell<HashMap<Player, Cards>>>,
}
impl Strategy for CheatingStrategy {
fn decide(&mut self, me: &Player, view: &GameStateView) -> TurnChoice {
let next = view.board.player_to_left(&me);
self.player_states_cheat.borrow_mut().insert(
next, view.other_player_states.get(&next).unwrap().hand.clone()
);
if view.board.turn == 1 {
TurnChoice::Hint(Hint {
player: next,
hinted: Hinted::Value(1)
})
} else {
let states = self.player_states_cheat.borrow();
let my_cards = states.get(me).unwrap();
let mut playable_cards = my_cards.iter().filter(|card| {
view.board.is_playable(card)
}).peekable();
if playable_cards.peek() == None {
TurnChoice::Discard(0)
} else {
let mut play_card = playable_cards.next().unwrap();
let mut next_card_opt = playable_cards.next();
while let Some(next_card) = next_card_opt {
if next_card.value < play_card.value {
play_card = next_card;
}
next_card_opt = playable_cards.next();
}
let index = my_cards.iter().position(|card| {
card == play_card
}).unwrap();
TurnChoice::Play(index)
}
}
}
fn update(&mut self, _: &Turn, _: &GameStateView) {
}
}