allow for probabilities in cardinfo
- helper functions for using probabilistic card info - move firework to cards, re-export everything in game.rs
This commit is contained in:
parent
9c580ecb88
commit
4fa72e030f
4 changed files with 147 additions and 90 deletions
48
src/cards.rs
48
src/cards.rs
|
@ -131,3 +131,51 @@ impl fmt::Display for Discard {
|
|||
}
|
||||
}
|
||||
|
||||
pub type Score = u32;
|
||||
|
||||
#[derive(Debug,Clone)]
|
||||
pub struct Firework {
|
||||
pub color: Color,
|
||||
pub top: Value,
|
||||
}
|
||||
impl Firework {
|
||||
pub fn new(color: Color) -> Firework {
|
||||
Firework {
|
||||
color: color,
|
||||
top: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn desired_value(&self) -> Option<Value> {
|
||||
if self.complete() { None } else { Some(self.top + 1) }
|
||||
}
|
||||
|
||||
pub fn score(&self) -> Score {
|
||||
self.top
|
||||
}
|
||||
|
||||
pub fn complete(&self) -> bool {
|
||||
self.top == FINAL_VALUE
|
||||
}
|
||||
|
||||
pub fn place(&mut self, card: &Card) {
|
||||
assert!(
|
||||
card.color == self.color,
|
||||
"Attempted to place card on firework of wrong color!"
|
||||
);
|
||||
assert!(
|
||||
Some(card.value) == self.desired_value(),
|
||||
"Attempted to place card of wrong value on firework!"
|
||||
);
|
||||
self.top = card.value;
|
||||
}
|
||||
}
|
||||
impl fmt::Display for Firework {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.complete() {
|
||||
write!(f, "{} firework complete!", self.color)
|
||||
} else {
|
||||
write!(f, "{} firework at {}", self.color, self.top)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
84
src/game.rs
84
src/game.rs
|
@ -2,12 +2,11 @@ use rand::{self, Rng, SeedableRng};
|
|||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
||||
use info::*;
|
||||
use cards::*;
|
||||
pub use info::*;
|
||||
pub use cards::*;
|
||||
|
||||
pub type Player = u32;
|
||||
|
||||
|
||||
#[derive(Debug,Clone)]
|
||||
pub enum Hinted {
|
||||
Color(Color),
|
||||
|
@ -292,6 +291,35 @@ impl BoardState {
|
|||
}
|
||||
}
|
||||
|
||||
fn probability_of_predicate<T>(
|
||||
&self,
|
||||
card_info: &T,
|
||||
predicate: &Fn(&Self, &Card) -> bool
|
||||
) -> f32 where T: CardInfo {
|
||||
let mut total_weight = 0;
|
||||
let mut playable_weight = 0;
|
||||
for card in card_info.get_possibilities() {
|
||||
let weight = card_info.get_weight(&card);
|
||||
if predicate(&self, &card) {
|
||||
playable_weight += weight;
|
||||
}
|
||||
total_weight += weight;
|
||||
}
|
||||
(playable_weight as f32) / (total_weight as f32)
|
||||
}
|
||||
|
||||
pub fn probability_is_playable<T>(&self, card_info: &T) -> f32 where T: CardInfo {
|
||||
self.probability_of_predicate(card_info, &Self::is_playable)
|
||||
}
|
||||
|
||||
pub fn probability_is_dead<T>(&self, card_info: &T) -> f32 where T: CardInfo {
|
||||
self.probability_of_predicate(card_info, &Self::is_dead)
|
||||
}
|
||||
|
||||
pub fn probability_is_dispensable<T>(&self, card_info: &T) -> f32 where T: CardInfo {
|
||||
self.probability_of_predicate(card_info, &Self::is_dispensable)
|
||||
}
|
||||
|
||||
pub fn get_players(&self) -> Vec<Player> {
|
||||
(0..self.num_players).collect::<Vec<_>>()
|
||||
}
|
||||
|
@ -422,8 +450,6 @@ impl fmt::Display for GameState {
|
|||
}
|
||||
}
|
||||
|
||||
pub type Score = u32;
|
||||
|
||||
impl GameState {
|
||||
pub fn new(opts: &GameOptions, seed: u32) -> GameState {
|
||||
let mut board = BoardState::new(opts, seed);
|
||||
|
@ -569,51 +595,3 @@ impl GameState {
|
|||
turn
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone)]
|
||||
pub struct Firework {
|
||||
pub color: Color,
|
||||
pub top: Value,
|
||||
}
|
||||
impl Firework {
|
||||
pub fn new(color: Color) -> Firework {
|
||||
Firework {
|
||||
color: color,
|
||||
top: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn desired_value(&self) -> Option<Value> {
|
||||
if self.complete() { None } else { Some(self.top + 1) }
|
||||
}
|
||||
|
||||
fn score(&self) -> Score {
|
||||
self.top
|
||||
}
|
||||
|
||||
fn complete(&self) -> bool {
|
||||
self.top == FINAL_VALUE
|
||||
}
|
||||
|
||||
fn place(&mut self, card: &Card) {
|
||||
assert!(
|
||||
card.color == self.color,
|
||||
"Attempted to place card on firework of wrong color!"
|
||||
);
|
||||
assert!(
|
||||
Some(card.value) == self.desired_value(),
|
||||
"Attempted to place card of wrong value on firework!"
|
||||
);
|
||||
self.top = card.value;
|
||||
}
|
||||
}
|
||||
impl fmt::Display for Firework {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.complete() {
|
||||
write!(f, "{} firework complete!", self.color)
|
||||
} else {
|
||||
write!(f, "{} firework at {}", self.color, self.top)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
104
src/info.rs
104
src/info.rs
|
@ -5,6 +5,7 @@ use std::hash::Hash;
|
|||
|
||||
use cards::*;
|
||||
|
||||
// trait representing information about a card
|
||||
pub trait CardInfo {
|
||||
// get all a-priori possibilities
|
||||
fn get_all_possibilities(&self) -> Vec<Card> {
|
||||
|
@ -16,8 +17,37 @@ pub trait CardInfo {
|
|||
}
|
||||
v
|
||||
}
|
||||
// whether the card is possible
|
||||
fn is_possible(&self, card: &Card) -> bool;
|
||||
|
||||
// TODO: have a borrow_possibilities to allow for more efficiency?
|
||||
|
||||
// mark all current possibilities for the card
|
||||
fn get_possibilities(&self) -> Vec<Card>;
|
||||
fn get_possibilities(&self) -> Vec<Card> {
|
||||
let mut v = Vec::new();
|
||||
for &color in COLORS.iter() {
|
||||
for &value in VALUES.iter() {
|
||||
let card = Card::new(color, value);
|
||||
if self.is_possible(&card) {
|
||||
v.push(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
v
|
||||
}
|
||||
// get probability weight for the card
|
||||
#[allow(unused_variables)]
|
||||
fn get_weight(&self, card: &Card) -> u32 {
|
||||
1
|
||||
}
|
||||
fn get_weighted_possibilities(&self) -> Vec<(Card, u32)> {
|
||||
let mut v = Vec::new();
|
||||
for card in self.get_possibilities() {
|
||||
let weight = self.get_weight(&card);
|
||||
v.push((card, weight));
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
// mark a whole color as false
|
||||
fn mark_color_false(&mut self, color: &Color);
|
||||
|
@ -64,47 +94,34 @@ pub trait Info<T> where T: Hash + Eq + Clone {
|
|||
|
||||
// get map from values to whether it's possible
|
||||
// true means maybe, false means no
|
||||
fn get_possibility_map(&self) -> &HashMap<T, bool>;
|
||||
fn get_mut_possibility_map(&mut self) -> &mut HashMap<T, bool>;
|
||||
fn get_possibility_set(&self) -> &HashSet<T>;
|
||||
fn get_mut_possibility_set(&mut self) -> &mut HashSet<T>;
|
||||
|
||||
// get what is now possible
|
||||
fn get_possibilities(&self) -> Vec<T> {
|
||||
let mut v = Vec::new();
|
||||
let map = self.get_possibility_map();
|
||||
for (value, is_possible) in map {
|
||||
if *is_possible {
|
||||
v.push(value.clone());
|
||||
}
|
||||
}
|
||||
v
|
||||
self.get_possibility_set().iter().map(|t| t.clone()).collect::<Vec<T>>()
|
||||
}
|
||||
|
||||
fn is_possible(&self, value: &T) -> bool {
|
||||
// self.get_possibility_map().contains_key(value)
|
||||
*self.get_possibility_map().get(value).unwrap()
|
||||
self.get_possibility_set().contains(value)
|
||||
}
|
||||
|
||||
fn initialize() -> HashMap<T, bool> {
|
||||
let mut possible_map : HashMap<T, bool> = HashMap::new();
|
||||
fn initialize() -> HashSet<T> {
|
||||
let mut possible_map : HashSet<T> = HashSet::new();
|
||||
for value in Self::get_all_possibilities().iter() {
|
||||
possible_map.insert(value.clone(), true);
|
||||
possible_map.insert(value.clone());
|
||||
}
|
||||
possible_map
|
||||
}
|
||||
|
||||
fn mark_true(&mut self, value: &T) {
|
||||
// mark everything else as definitively impossible
|
||||
for (other_value, possible) in self.get_mut_possibility_map().iter_mut() {
|
||||
if other_value != value {
|
||||
*possible = false;
|
||||
} else {
|
||||
assert_eq!(*possible, true);
|
||||
}
|
||||
}
|
||||
let possible = self.get_mut_possibility_set();
|
||||
possible.clear();
|
||||
possible.insert(value.clone());
|
||||
}
|
||||
|
||||
fn mark_false(&mut self, value: &T) {
|
||||
self.get_mut_possibility_map().insert(value.clone(), false);
|
||||
self.get_mut_possibility_set().remove(value);
|
||||
}
|
||||
|
||||
fn mark(&mut self, value: &T, info: bool) {
|
||||
|
@ -117,25 +134,25 @@ pub trait Info<T> where T: Hash + Eq + Clone {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ColorInfo(HashMap<Color, bool>);
|
||||
pub struct ColorInfo(HashSet<Color>);
|
||||
impl ColorInfo {
|
||||
pub fn new() -> ColorInfo { ColorInfo(ColorInfo::initialize()) }
|
||||
}
|
||||
impl Info<Color> for ColorInfo {
|
||||
fn get_all_possibilities() -> Vec<Color> { COLORS.to_vec() }
|
||||
fn get_possibility_map(&self) -> &HashMap<Color, bool> { &self.0 }
|
||||
fn get_mut_possibility_map(&mut self) -> &mut HashMap<Color, bool> { &mut self.0 }
|
||||
fn get_possibility_set(&self) -> &HashSet<Color> { &self.0 }
|
||||
fn get_mut_possibility_set(&mut self) -> &mut HashSet<Color> { &mut self.0 }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ValueInfo(HashMap<Value, bool>);
|
||||
pub struct ValueInfo(HashSet<Value>);
|
||||
impl ValueInfo {
|
||||
pub fn new() -> ValueInfo { ValueInfo(ValueInfo::initialize()) }
|
||||
}
|
||||
impl Info<Value> for ValueInfo {
|
||||
fn get_all_possibilities() -> Vec<Value> { VALUES.to_vec() }
|
||||
fn get_possibility_map(&self) -> &HashMap<Value, bool> { &self.0 }
|
||||
fn get_mut_possibility_map(&mut self) -> &mut HashMap<Value, bool> { &mut self.0 }
|
||||
fn get_possibility_set(&self) -> &HashSet<Value> { &self.0 }
|
||||
fn get_mut_possibility_set(&mut self) -> &mut HashSet<Value> { &mut self.0 }
|
||||
}
|
||||
|
||||
// represents information only of the form:
|
||||
|
@ -163,6 +180,11 @@ impl CardInfo for SimpleCardInfo {
|
|||
}
|
||||
v
|
||||
}
|
||||
fn is_possible(&self, card: &Card) -> bool {
|
||||
self.color_info.is_possible(&card.color) &&
|
||||
self.value_info.is_possible(&card.value)
|
||||
|
||||
}
|
||||
fn mark_color_false(&mut self, color: &Color) {
|
||||
self.color_info.mark_false(color);
|
||||
|
||||
|
@ -193,16 +215,20 @@ impl fmt::Display for SimpleCardInfo {
|
|||
|
||||
// Can represent information of the form:
|
||||
// this card is/isn't possible
|
||||
// also, maintains weights for the cards
|
||||
#[derive(Clone)]
|
||||
struct CardPossibilityTable {
|
||||
possible: HashSet<Card>,
|
||||
pub struct CardPossibilityTable {
|
||||
possible: HashMap<Card, u32>,
|
||||
}
|
||||
impl CardPossibilityTable {
|
||||
pub fn new() -> CardPossibilityTable {
|
||||
let mut possible = HashSet::new();
|
||||
let mut possible = HashMap::new();
|
||||
for &color in COLORS.iter() {
|
||||
for &value in VALUES.iter() {
|
||||
possible.insert(Card::new(color, value));
|
||||
possible.insert(
|
||||
Card::new(color, value),
|
||||
get_count_for_value(&value)
|
||||
);
|
||||
}
|
||||
}
|
||||
CardPossibilityTable {
|
||||
|
@ -216,8 +242,11 @@ impl CardPossibilityTable {
|
|||
}
|
||||
}
|
||||
impl CardInfo for CardPossibilityTable {
|
||||
fn is_possible(&self, card: &Card) -> bool {
|
||||
self.possible.contains_key(card)
|
||||
}
|
||||
fn get_possibilities(&self) -> Vec<Card> {
|
||||
let mut cards = self.possible.iter().map(|card| {card.clone() }).collect::<Vec<_>>();
|
||||
let mut cards = self.possible.keys().map(|card| {card.clone() }).collect::<Vec<_>>();
|
||||
cards.sort();
|
||||
cards
|
||||
}
|
||||
|
@ -232,6 +261,9 @@ impl CardInfo for CardPossibilityTable {
|
|||
self.mark_false(&Card::new(color, value.clone()));
|
||||
}
|
||||
}
|
||||
fn get_weight(&self, card: &Card) -> u32 {
|
||||
*self.possible.get(card).unwrap_or(&0)
|
||||
}
|
||||
}
|
||||
impl fmt::Display for CardPossibilityTable {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
|
|
@ -4,7 +4,6 @@ use std::collections::{HashMap, HashSet};
|
|||
|
||||
use simulator::*;
|
||||
use game::*;
|
||||
use cards::*;
|
||||
|
||||
// strategy that explicitly cheats by using Rc/RefCell
|
||||
// serves as a reference point for other strategies
|
||||
|
|
Loading…
Reference in a new issue