replicated 24.88 from paper

This commit is contained in:
Jeff Wu 2016-03-13 22:28:34 -07:00
parent 7f5feacbc7
commit 0b9734c20b
4 changed files with 72 additions and 27 deletions

View file

@ -366,6 +366,10 @@ impl BoardState {
self.fireworks.get(color).unwrap() self.fireworks.get(color).unwrap()
} }
fn get_firework_mut(&mut self, color: &Color) -> &mut Firework {
self.fireworks.get_mut(color).unwrap()
}
// returns whether a card would place on a firework // returns whether a card would place on a firework
pub fn is_playable(&self, card: &Card) -> bool { pub fn is_playable(&self, card: &Card) -> bool {
Some(card.value) == self.get_firework(&card.color).desired_value() Some(card.value) == self.get_firework(&card.color).desired_value()
@ -658,16 +662,20 @@ impl GameState {
index, card index, card
); );
let mut firework_made = false;
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 finished = {
firework_made = card.value == FINAL_VALUE; let firework = self.board.get_firework_mut(&card.color);
debug!("Successfully played {}!", card); debug!("Successfully played {}!", card);
if firework_made { let finished = card.value == FINAL_VALUE;
debug!("Firework complete for {}!", card.color); if finished {
debug!("Firework complete for {}!", card.color);
}
firework.place(card);
finished
};
if finished {
self.board.try_add_hint();
} }
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;
@ -676,10 +684,6 @@ impl GameState {
self.board.lives_remaining self.board.lives_remaining
); );
} }
if firework_made {
self.board.try_add_hint();
}
} }
} }

View file

@ -77,7 +77,7 @@ fn main() {
// TODO: make these configurable // TODO: make these configurable
let opts = game::GameOptions { let opts = game::GameOptions {
num_players: 4, num_players: 5,
hand_size: 4, hand_size: 4,
num_hints: 8, num_hints: 8,
num_lives: 3, num_lives: 3,
@ -93,7 +93,7 @@ fn main() {
if n == 1 { if n == 1 {
simulator::simulate_symmetric_once(&opts, strategy, seed); simulator::simulate_symmetric_once(&opts, strategy, seed);
} else { } else {
simulator::simulate_symmetric(&opts, strategy, n); simulator::simulate_symmetric(&opts, strategy, n, seed);
} }
// simulator::simulate_symmetric_once( // simulator::simulate_symmetric_once(

View file

@ -18,11 +18,7 @@ pub fn simulate_once<'a>(
seed_opt: Option<u32>, seed_opt: Option<u32>,
) -> Score { ) -> Score {
let seed = if let Some(seed) = seed_opt { let seed = seed_opt.unwrap_or(rand::thread_rng().next_u32());
seed
} else {
rand::thread_rng().next_u32()
};
let mut game = GameState::new(opts, seed); let mut game = GameState::new(opts, seed);
@ -66,16 +62,37 @@ pub fn simulate_once<'a>(
game.score() game.score()
} }
pub fn simulate<'a>(opts: &GameOptions, strat_configs: &Vec<Box<StrategyConfig + 'a>>, n_trials: u32) -> f32 { pub fn simulate<'a>(
opts: &GameOptions,
strat_configs: &Vec<Box<StrategyConfig + 'a>>,
n_trials: u32,
first_seed_opt: Option<u32>
) -> f32 {
let mut total_score = 0; let mut total_score = 0;
for seed in 0..n_trials { let mut non_perfect_seeds = Vec::new();
let first_seed = first_seed_opt.unwrap_or(rand::thread_rng().next_u32());
let mut histogram = HashMap::<Score, usize>::new();
for i in 0..n_trials {
if (i > 0) && (i % 1000 == 0) {
let average: f32 = (total_score as f32) / (i as f32);
info!("Trials: {}, Average so far: {}", i, average);
}
let seed = first_seed + i;
let score = simulate_once(&opts, strat_configs, Some(seed)); let score = simulate_once(&opts, strat_configs, Some(seed));
debug!("Scored: {:?}", score); debug!("Scored: {:?}", score);
let count = histogram.get(&score).unwrap_or(&0) + 1;
histogram.insert(score, count);
if score != 25 { if score != 25 {
info!("Seed with non-perfect score: {:?}", seed); non_perfect_seeds.push((score, seed));
} }
total_score += score; total_score += score;
} }
non_perfect_seeds.sort();
info!("Score histogram: {:?}", histogram);
info!("Seeds with non-perfect score: {:?}", non_perfect_seeds);
let average: f32 = (total_score as f32) / (n_trials as f32); let average: f32 = (total_score as f32) / (n_trials as f32);
info!("Average score: {:?}", average); info!("Average score: {:?}", average);
average average
@ -94,10 +111,16 @@ pub fn simulate_symmetric_once<'a, S: StrategyConfig + Clone + 'a>(
simulate_once(opts, &strat_configs, seed_opt) simulate_once(opts, &strat_configs, seed_opt)
} }
pub fn simulate_symmetric<'a, S: StrategyConfig + Clone + 'a>(opts: &GameOptions, strat_config: S, n_trials: u32) -> f32 { pub fn simulate_symmetric<'a, S: StrategyConfig + Clone + 'a>(
opts: &GameOptions,
strat_config: S,
n_trials: u32,
first_seed_opt: Option<u32>,
) -> f32 {
let mut strat_configs = Vec::new(); let mut strat_configs = Vec::new();
for _ in 0..opts.num_players { for _ in 0..opts.num_players {
strat_configs.push(Box::new(strat_config.clone()) as Box<StrategyConfig + 'a>); strat_configs.push(Box::new(strat_config.clone()) as Box<StrategyConfig + 'a>);
} }
simulate(opts, &strat_configs, n_trials) simulate(opts, &strat_configs, n_trials, first_seed_opt)
} }

View file

@ -117,15 +117,27 @@ impl Strategy for CheatingStrategy {
}).peekable(); }).peekable();
if playable_cards.peek() == None { if playable_cards.peek() == None {
// if view.board.deck_size() > 10 {
if view.board.discard.cards.len() < 5 {
// if anything is totally useless, discard it
for (i, card) in my_cards.iter().enumerate() {
if view.board.is_dead(card) {
return TurnChoice::Discard(i);
}
}
}
// it's unintuitive that hinting is better than
// discarding dead cards, but turns out true
if view.board.hints_remaining > 1 {
return self.throwaway_hint(view);
}
// if anything is totally useless, discard it // if anything is totally useless, discard it
for (i, card) in my_cards.iter().enumerate() { for (i, card) in my_cards.iter().enumerate() {
if view.board.is_dead(card) { if view.board.is_dead(card) {
return TurnChoice::Discard(i); return TurnChoice::Discard(i);
} }
} }
if view.board.hints_remaining > 0 {
return self.throwaway_hint(view);
}
// All cards are plausibly useful. // All cards are plausibly useful.
// Play the best discardable card, according to the ordering induced by comparing // Play the best discardable card, according to the ordering induced by comparing
// (is in another hand, is dispensable, value) // (is in another hand, is dispensable, value)
@ -144,6 +156,12 @@ impl Strategy for CheatingStrategy {
} }
} }
if let Some(card) = discard_card { if let Some(card) = discard_card {
if view.board.hints_remaining > 0 {
if !view.can_see(card) {
return self.throwaway_hint(view);
}
}
let index = my_cards.iter().position(|iter_card| { let index = my_cards.iter().position(|iter_card| {
card == iter_card card == iter_card
}).unwrap(); }).unwrap();