diff --git a/src/game.rs b/src/game.rs index 7bff869..ba511c4 100644 --- a/src/game.rs +++ b/src/game.rs @@ -30,7 +30,7 @@ pub fn get_count_for_value(value: &Value) -> usize { pub type Player = u32; -#[derive(Debug,Clone,PartialEq)] +#[derive(Debug,Clone,PartialEq,Eq,Hash)] pub struct Card { pub color: Color, pub value: Value, @@ -520,10 +520,13 @@ pub struct GameStateView<'a> { pub board: &'a BoardState, } impl <'a> GameStateView<'a> { - pub fn has_card(&self, player: &Player, card: &Card) -> bool { + pub fn get_hand(&self, player: &Player) -> &Cards { assert!(self.player != *player, "Cannot query about your own cards!"); - let state = self.other_player_states.get(player).unwrap(); - for other_card in &state.hand { + &self.other_player_states.get(player).unwrap().hand + } + + pub fn has_card(&self, player: &Player, card: &Card) -> bool { + for other_card in self.get_hand(player) { if *card == *other_card { return true; } diff --git a/src/simulator.rs b/src/simulator.rs index 86a31f5..e17dabe 100644 --- a/src/simulator.rs +++ b/src/simulator.rs @@ -59,9 +59,12 @@ pub fn simulate_once<'a>( // TODO: do some stuff debug!("State:\n{}", game); } - game.score() + let score = game.score(); + debug!("SCORED: {:?}", score); + score } +// TODO: multithreaded pub fn simulate<'a>( opts: &GameOptions, strat_configs: &Vec>, @@ -73,6 +76,7 @@ pub fn simulate<'a>( let mut non_perfect_seeds = Vec::new(); let first_seed = first_seed_opt.unwrap_or(rand::thread_rng().next_u32()); + info!("Initial seed: {}\n", first_seed); let mut histogram = HashMap::::new(); for i in 0..n_trials { if (i > 0) && (i % 1000 == 0) { @@ -81,7 +85,6 @@ pub fn simulate<'a>( } let seed = first_seed + i; let score = simulate_once(&opts, strat_configs, Some(seed)); - debug!("Scored: {:?}", score); let count = histogram.get(&score).unwrap_or(&0) + 1; histogram.insert(score, count); if score != 25 { diff --git a/src/strategies/cheating.rs b/src/strategies/cheating.rs index 141ca8c..1857886 100644 --- a/src/strategies/cheating.rs +++ b/src/strategies/cheating.rs @@ -1,6 +1,6 @@ use std::rc::Rc; use std::cell::{RefCell}; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use simulator::*; use game::*; @@ -101,6 +101,35 @@ impl CheatingStrategy { // maybe value 5s more? 5 + (5 - (card.value as i32)) } + + fn find_useless_card(&self, view: &GameStateView, hand: &Cards) -> Option { + let mut set: HashSet = HashSet::new(); + + for (i, card) in hand.iter().enumerate() { + if view.board.is_dead(card) { + return Some(i); + } + if set.contains(card) { + // found a duplicate card + return Some(i); + } + set.insert(card.clone()); + } + return None + } + + fn someone_else_can_play(&self, view: &GameStateView) -> bool { + for player in view.board.get_players() { + if player != self.me { + for card in view.get_hand(&player) { + if view.board.is_playable(card) { + return true; + } + } + } + } + false + } } impl Strategy for CheatingStrategy { fn decide(&mut self, view: &GameStateView) -> TurnChoice { @@ -120,24 +149,23 @@ impl Strategy for CheatingStrategy { // 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 - for (i, card) in my_cards.iter().enumerate() { - if view.board.is_dead(card) { + if let Some(i) = self.find_useless_card(view, my_cards) { return TurnChoice::Discard(i); } } + + // hinting is better than discarding dead cards + // (probably because it stalls the deck-drawing). + if view.board.hints_remaining > 1 { + if self.someone_else_can_play(view) { + return self.throwaway_hint(view); + } + } + // if anything is totally useless, discard it + if let Some(i) = self.find_useless_card(view, my_cards) { + return TurnChoice::Discard(i); + } + // All cards are plausibly useful. // Play the best discardable card, according to the ordering induced by comparing // (is in another hand, is dispensable, value)