add types for information
This commit is contained in:
parent
55e9dc2fe3
commit
a44b017eae
84
src/game.rs
84
src/game.rs
@ -1,20 +1,24 @@
|
|||||||
|
|
||||||
use rand::{self, Rng};
|
use rand::{self, Rng};
|
||||||
|
use std::convert::From;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use info::*;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Type definitions
|
* Type definitions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub type Color = &'static str;
|
pub type Color = &'static str;
|
||||||
const COLORS: [Color; 5] = ["blue", "red", "yellow", "white", "green"];
|
pub const COLORS: [Color; 5] = ["blue", "red", "yellow", "white", "green"];
|
||||||
|
|
||||||
pub type Value = u32;
|
pub type Value = u32;
|
||||||
// list of (value, count) pairs
|
// list of (value, count) pairs
|
||||||
const VALUE_COUNTS : [(Value, u32); 5] = [(1, 3), (2, 2), (3, 2), (4, 2), (5, 1)];
|
pub const VALUES : [Value; 5] = [1, 2, 3, 4, 5];
|
||||||
const FINAL_VALUE : Value = 5;
|
pub const VALUE_COUNTS : [(Value, u32); 5] = [(1, 3), (2, 2), (3, 2), (4, 2), (5, 1)];
|
||||||
|
pub const FINAL_VALUE : Value = 5;
|
||||||
|
|
||||||
pub struct Card {
|
pub struct Card {
|
||||||
pub color: Color,
|
pub color: Color,
|
||||||
@ -27,22 +31,22 @@ impl fmt::Debug for Card {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Pile(Vec<Card>);
|
// basically a stack of cards, or card info
|
||||||
// basically a stack of cards
|
pub struct Pile<T>(Vec<T>);
|
||||||
impl Pile {
|
impl <T> Pile<T> {
|
||||||
pub fn new() -> Pile {
|
pub fn new() -> Pile<T> {
|
||||||
Pile(Vec::new())
|
Pile(Vec::<T>::new())
|
||||||
}
|
}
|
||||||
pub fn draw(&mut self) -> Option<Card> {
|
pub fn draw(&mut self) -> Option<T> {
|
||||||
self.0.pop()
|
self.0.pop()
|
||||||
}
|
}
|
||||||
pub fn place(&mut self, card: Card) {
|
pub fn place(&mut self, item: T) {
|
||||||
self.0.push(card);
|
self.0.push(item);
|
||||||
}
|
}
|
||||||
pub fn take(&mut self, index: usize) -> Card {
|
pub fn take(&mut self, index: usize) -> T {
|
||||||
self.0.remove(index)
|
self.0.remove(index)
|
||||||
}
|
}
|
||||||
pub fn top(&self) -> Option<&Card> {
|
pub fn top(&self) -> Option<&T> {
|
||||||
self.0.last()
|
self.0.last()
|
||||||
}
|
}
|
||||||
pub fn shuffle(&mut self) {
|
pub fn shuffle(&mut self) {
|
||||||
@ -52,6 +56,15 @@ impl Pile {
|
|||||||
self.0.len()
|
self.0.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl <T> From<Vec<T>> for Pile<T> {
|
||||||
|
fn from(items: Vec<T>) -> Pile<T> {
|
||||||
|
Pile(items)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Cards = Pile<Card>;
|
||||||
|
|
||||||
|
pub type CardsInfo = Pile<CardInfo>;
|
||||||
|
|
||||||
pub type Player = u32;
|
pub type Player = u32;
|
||||||
|
|
||||||
@ -89,18 +102,18 @@ pub struct GameOptions {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PlayerState {
|
pub struct PlayerState {
|
||||||
// the player's actual hand
|
// the player's actual hand
|
||||||
pub hand: Pile,
|
pub hand: Cards,
|
||||||
// represents what is common knowledge about the player's hand
|
// represents what is common knowledge about the player's hand
|
||||||
// pub known: ,
|
pub info: CardsInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
// State of everything except the player's hands
|
// State of everything except the player's hands
|
||||||
// Is all completely common knowledge
|
// Is all completely common knowledge
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BoardState {
|
pub struct BoardState {
|
||||||
deck: Pile,
|
deck: Cards,
|
||||||
pub discard: Pile,
|
pub discard: Cards,
|
||||||
pub fireworks: HashMap<Color, Pile>,
|
pub fireworks: HashMap<Color, Cards>,
|
||||||
|
|
||||||
pub num_players: u32,
|
pub num_players: u32,
|
||||||
|
|
||||||
@ -123,9 +136,9 @@ pub struct BoardState {
|
|||||||
pub struct GameStateView<'a> {
|
pub struct GameStateView<'a> {
|
||||||
// the player whose view it is
|
// the player whose view it is
|
||||||
pub player: Player,
|
pub player: Player,
|
||||||
// what is known about their own hand
|
// what is known about their own hand (and thus common knowledge)
|
||||||
// pub known:
|
pub info: &'a CardsInfo,
|
||||||
// the cards of the other players
|
// the cards of the other players, as well as the information they have
|
||||||
pub other_player_states: HashMap<Player, &'a PlayerState>,
|
pub other_player_states: HashMap<Player, &'a PlayerState>,
|
||||||
// board state
|
// board state
|
||||||
pub board: &'a BoardState,
|
pub board: &'a BoardState,
|
||||||
@ -150,18 +163,22 @@ impl GameState {
|
|||||||
// we can assume the deck is big enough to draw initial hands
|
// we can assume the deck is big enough to draw initial hands
|
||||||
deck.draw().unwrap()
|
deck.draw().unwrap()
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
|
let infos = (0..opts.hand_size).map(|_| {
|
||||||
|
CardInfo::new()
|
||||||
|
}).collect::<Vec<_>>();
|
||||||
let state = PlayerState {
|
let state = PlayerState {
|
||||||
hand: Pile(raw_hand),
|
hand: Cards::from(raw_hand),
|
||||||
|
info: CardsInfo::from(infos),
|
||||||
};
|
};
|
||||||
player_states.insert(i, state);
|
player_states.insert(i, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut fireworks : HashMap<Color, Pile> = HashMap::new();
|
let mut fireworks : HashMap<Color, Cards> = HashMap::new();
|
||||||
for color in COLORS.iter() {
|
for color in COLORS.iter() {
|
||||||
let mut pile = Pile::new();
|
let mut firework = Cards::new();
|
||||||
let card = Card { value: 0, color: color };
|
let card = Card { value: 0, color: color };
|
||||||
pile.place(card);
|
firework.place(card);
|
||||||
fireworks.insert(color, pile);
|
fireworks.insert(color, firework);
|
||||||
}
|
}
|
||||||
|
|
||||||
GameState {
|
GameState {
|
||||||
@ -169,7 +186,7 @@ impl GameState {
|
|||||||
board: BoardState {
|
board: BoardState {
|
||||||
deck: deck,
|
deck: deck,
|
||||||
fireworks: fireworks,
|
fireworks: fireworks,
|
||||||
discard: Pile::new(),
|
discard: Cards::new(),
|
||||||
num_players: opts.num_players,
|
num_players: opts.num_players,
|
||||||
player: 0,
|
player: 0,
|
||||||
turn: 1,
|
turn: 1,
|
||||||
@ -183,8 +200,8 @@ impl GameState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_deck() -> Pile {
|
fn make_deck() -> Cards {
|
||||||
let mut deck: Pile = Pile(Vec::new());
|
let mut deck: Cards = Cards::from(Vec::new());
|
||||||
|
|
||||||
for color in COLORS.iter() {
|
for color in COLORS.iter() {
|
||||||
for &(value, count) in VALUE_COUNTS.iter() {
|
for &(value, count) in VALUE_COUNTS.iter() {
|
||||||
@ -227,6 +244,7 @@ impl GameState {
|
|||||||
}
|
}
|
||||||
GameStateView {
|
GameStateView {
|
||||||
player: player,
|
player: player,
|
||||||
|
info: &self.player_states.get(&player).unwrap().info,
|
||||||
other_player_states: other_player_states,
|
other_player_states: other_player_states,
|
||||||
board: &self.board,
|
board: &self.board,
|
||||||
}
|
}
|
||||||
@ -234,10 +252,12 @@ impl GameState {
|
|||||||
|
|
||||||
// takes a card from the player's hand, and replaces it if possible
|
// takes a card from the player's hand, and replaces it if possible
|
||||||
fn take_from_hand(&mut self, index: usize) -> Card {
|
fn take_from_hand(&mut self, index: usize) -> Card {
|
||||||
let ref mut hand = self.player_states.get_mut(&self.board.player).unwrap().hand;
|
let ref mut state = self.player_states.get_mut(&self.board.player).unwrap();
|
||||||
let card = hand.take(index);
|
let card = state.hand.take(index);
|
||||||
|
state.info.take(index);
|
||||||
if let Some(new_card) = self.board.deck.draw() {
|
if let Some(new_card) = self.board.deck.draw() {
|
||||||
hand.place(new_card);
|
state.hand.place(new_card);
|
||||||
|
state.info.place(CardInfo::new());
|
||||||
}
|
}
|
||||||
card
|
card
|
||||||
}
|
}
|
||||||
|
105
src/info.rs
Normal file
105
src/info.rs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::cmp::Eq;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
use game::*;
|
||||||
|
|
||||||
|
// Represents a bit of information about T
|
||||||
|
trait Info<T> where T: Hash + Eq + Clone {
|
||||||
|
// get all a-priori possibilities
|
||||||
|
fn get_possibilities() -> Vec<T>;
|
||||||
|
|
||||||
|
// 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 initialize() -> HashMap<T, bool> {
|
||||||
|
let mut possible_map : HashMap<T, bool> = HashMap::new();
|
||||||
|
for value in Self::get_possibilities().iter() {
|
||||||
|
possible_map.insert(value.clone(), true);
|
||||||
|
}
|
||||||
|
possible_map
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge(&mut self, other: &Self) {
|
||||||
|
for (value, possible) in self.get_mut_possibility_map().iter_mut() {
|
||||||
|
*possible = *possible && *other.get_possibility_map().get(value).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_false(&mut self, value: &T) {
|
||||||
|
self.get_mut_possibility_map().insert(value.clone(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ColorInfo(HashMap<Color, bool>);
|
||||||
|
impl ColorInfo {
|
||||||
|
pub fn new() -> ColorInfo {
|
||||||
|
ColorInfo(ColorInfo::initialize())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Info<Color> for ColorInfo {
|
||||||
|
fn get_possibilities() -> Vec<Color> {
|
||||||
|
let mut possible : Vec<Color> = Vec::new();
|
||||||
|
for color in COLORS.iter() {
|
||||||
|
possible.push(*color);
|
||||||
|
}
|
||||||
|
possible
|
||||||
|
}
|
||||||
|
fn get_possibility_map(&self) -> &HashMap<Color, bool> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
fn get_mut_possibility_map(&mut self) -> &mut HashMap<Color, bool> {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ValueInfo(HashMap<Value, bool>);
|
||||||
|
impl ValueInfo {
|
||||||
|
pub fn new() -> ValueInfo {
|
||||||
|
ValueInfo(ValueInfo::initialize())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Info<Value> for ValueInfo {
|
||||||
|
fn get_possibilities() -> Vec<Value> {
|
||||||
|
let mut possible : Vec<Value> = Vec::new();
|
||||||
|
for value in VALUES.iter() {
|
||||||
|
possible.push(*value);
|
||||||
|
}
|
||||||
|
possible
|
||||||
|
}
|
||||||
|
fn get_possibility_map(&self) -> &HashMap<Value, bool> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
fn get_mut_possibility_map(&mut self) -> &mut HashMap<Value, bool> {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CardInfo {
|
||||||
|
pub color_info: ColorInfo,
|
||||||
|
pub value_info: ValueInfo,
|
||||||
|
}
|
||||||
|
impl CardInfo {
|
||||||
|
pub fn new() -> CardInfo {
|
||||||
|
CardInfo {
|
||||||
|
color_info: ColorInfo::new(),
|
||||||
|
value_info: ValueInfo::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,12 +4,15 @@ extern crate log;
|
|||||||
|
|
||||||
mod game;
|
mod game;
|
||||||
mod strategies;
|
mod strategies;
|
||||||
|
mod info;
|
||||||
|
|
||||||
|
|
||||||
struct SimpleLogger;
|
struct SimpleLogger;
|
||||||
impl log::Log for SimpleLogger {
|
impl log::Log for SimpleLogger {
|
||||||
fn enabled(&self, metadata: &log::LogMetadata) -> bool {
|
fn enabled(&self, metadata: &log::LogMetadata) -> bool {
|
||||||
metadata.level() <= log::LogLevel::Debug
|
// metadata.level() <= log::LogLevel::Warn
|
||||||
|
metadata.level() <= log::LogLevel::Info
|
||||||
|
// metadata.level() <= log::LogLevel::Debug
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log(&self, record: &log::LogRecord) {
|
fn log(&self, record: &log::LogRecord) {
|
||||||
|
@ -60,6 +60,7 @@ pub fn simulate<S: Strategy>(opts: &GameOptions, strategy: &S, n_trials: u32) ->
|
|||||||
average
|
average
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dummy, terrible strategy
|
||||||
pub struct AlwaysPlay;
|
pub struct AlwaysPlay;
|
||||||
impl Strategy for AlwaysPlay {
|
impl Strategy for AlwaysPlay {
|
||||||
type InternalState = ();
|
type InternalState = ();
|
||||||
|
Loading…
Reference in New Issue
Block a user