improvements to cheating strategy
This commit is contained in:
parent
0b9734c20b
commit
44248c8d3e
11
src/game.rs
11
src/game.rs
@ -30,7 +30,7 @@ pub fn get_count_for_value(value: &Value) -> usize {
|
|||||||
|
|
||||||
pub type Player = u32;
|
pub type Player = u32;
|
||||||
|
|
||||||
#[derive(Debug,Clone,PartialEq)]
|
#[derive(Debug,Clone,PartialEq,Eq,Hash)]
|
||||||
pub struct Card {
|
pub struct Card {
|
||||||
pub color: Color,
|
pub color: Color,
|
||||||
pub value: Value,
|
pub value: Value,
|
||||||
@ -520,10 +520,13 @@ pub struct GameStateView<'a> {
|
|||||||
pub board: &'a BoardState,
|
pub board: &'a BoardState,
|
||||||
}
|
}
|
||||||
impl <'a> GameStateView<'a> {
|
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!");
|
assert!(self.player != *player, "Cannot query about your own cards!");
|
||||||
let state = self.other_player_states.get(player).unwrap();
|
&self.other_player_states.get(player).unwrap().hand
|
||||||
for other_card in &state.hand {
|
}
|
||||||
|
|
||||||
|
pub fn has_card(&self, player: &Player, card: &Card) -> bool {
|
||||||
|
for other_card in self.get_hand(player) {
|
||||||
if *card == *other_card {
|
if *card == *other_card {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -59,9 +59,12 @@ pub fn simulate_once<'a>(
|
|||||||
// TODO: do some stuff
|
// TODO: do some stuff
|
||||||
debug!("State:\n{}", game);
|
debug!("State:\n{}", game);
|
||||||
}
|
}
|
||||||
game.score()
|
let score = game.score();
|
||||||
|
debug!("SCORED: {:?}", score);
|
||||||
|
score
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: multithreaded
|
||||||
pub fn simulate<'a>(
|
pub fn simulate<'a>(
|
||||||
opts: &GameOptions,
|
opts: &GameOptions,
|
||||||
strat_configs: &Vec<Box<StrategyConfig + 'a>>,
|
strat_configs: &Vec<Box<StrategyConfig + 'a>>,
|
||||||
@ -73,6 +76,7 @@ pub fn simulate<'a>(
|
|||||||
let mut non_perfect_seeds = Vec::new();
|
let mut non_perfect_seeds = Vec::new();
|
||||||
|
|
||||||
let first_seed = first_seed_opt.unwrap_or(rand::thread_rng().next_u32());
|
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();
|
let mut histogram = HashMap::<Score, usize>::new();
|
||||||
for i in 0..n_trials {
|
for i in 0..n_trials {
|
||||||
if (i > 0) && (i % 1000 == 0) {
|
if (i > 0) && (i % 1000 == 0) {
|
||||||
@ -81,7 +85,6 @@ pub fn simulate<'a>(
|
|||||||
}
|
}
|
||||||
let seed = first_seed + i;
|
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);
|
|
||||||
let count = histogram.get(&score).unwrap_or(&0) + 1;
|
let count = histogram.get(&score).unwrap_or(&0) + 1;
|
||||||
histogram.insert(score, count);
|
histogram.insert(score, count);
|
||||||
if score != 25 {
|
if score != 25 {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::{RefCell};
|
use std::cell::{RefCell};
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use simulator::*;
|
use simulator::*;
|
||||||
use game::*;
|
use game::*;
|
||||||
@ -101,6 +101,35 @@ impl CheatingStrategy {
|
|||||||
// maybe value 5s more?
|
// maybe value 5s more?
|
||||||
5 + (5 - (card.value as i32))
|
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 {
|
impl Strategy for CheatingStrategy {
|
||||||
fn decide(&mut self, view: &GameStateView) -> TurnChoice {
|
fn decide(&mut self, view: &GameStateView) -> TurnChoice {
|
||||||
@ -120,24 +149,23 @@ impl Strategy for CheatingStrategy {
|
|||||||
// if view.board.deck_size() > 10 {
|
// if view.board.deck_size() > 10 {
|
||||||
if view.board.discard.cards.len() < 5 {
|
if view.board.discard.cards.len() < 5 {
|
||||||
// if anything is totally useless, discard it
|
// if anything is totally useless, discard it
|
||||||
for (i, card) in my_cards.iter().enumerate() {
|
if let Some(i) = self.find_useless_card(view, my_cards) {
|
||||||
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) {
|
|
||||||
return TurnChoice::Discard(i);
|
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.
|
// 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)
|
||||||
|
Loading…
Reference in New Issue
Block a user