improvements to cheating strategy

This commit is contained in:
Jeff Wu 2016-03-13 23:05:01 -07:00
parent 0b9734c20b
commit 44248c8d3e
3 changed files with 56 additions and 22 deletions

View file

@ -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;
}

View file

@ -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<Box<StrategyConfig + 'a>>,
@ -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::<Score, usize>::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 {

View file

@ -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<usize> {
let mut set: HashSet<Card> = 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) {
if let Some(i) = self.find_useless_card(view, my_cards) {
return TurnChoice::Discard(i);
}
}
}
// it's unintuitive that hinting is better than
// discarding dead cards, but turns out true
// 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
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);
}
}
// All cards are plausibly useful.
// Play the best discardable card, according to the ordering induced by comparing
// (is in another hand, is dispensable, value)