move stuff to boardstate

This commit is contained in:
Jeff Wu 2016-03-06 21:44:17 -08:00
parent 49627b91b6
commit b4d949ff2f
3 changed files with 120 additions and 87 deletions

View file

@ -64,9 +64,10 @@ impl <T> From<Vec<T>> for Pile<T> {
} }
impl <T> fmt::Display for Pile<T> where T: fmt::Display { impl <T> fmt::Display for Pile<T> where T: fmt::Display {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "["); // surely doing unwraps is improper..
write!(f, "[").unwrap();
for item in &self.0 { for item in &self.0 {
write!(f, "{}, ", item); write!(f, "{}, ", item).unwrap();
} }
write!(f, "] ") write!(f, "] ")
} }
@ -179,6 +180,21 @@ impl PlayerState {
} }
} }
fn new_deck() -> Cards {
let mut deck: Cards = Cards::from(Vec::new());
for color in COLORS.iter() {
for &(value, count) in VALUE_COUNTS.iter() {
for _ in 0..count {
deck.place(Card {color: color, value: value});
}
}
};
deck.shuffle();
info!("Created deck: {}", deck);
deck
}
// 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)]
@ -201,6 +217,65 @@ pub struct BoardState {
// only relevant when deck runs out // only relevant when deck runs out
deckless_turns_remaining: u32, deckless_turns_remaining: u32,
} }
impl BoardState {
pub fn new(opts: &GameOptions) -> BoardState {
let mut fireworks : HashMap<Color, Cards> = HashMap::new();
for color in COLORS.iter() {
let mut firework = Cards::new();
let card = Card { value: 0, color: color };
firework.place(card);
fireworks.insert(color, firework);
}
BoardState {
deck: new_deck(),
fireworks: fireworks,
discard: Cards::new(),
num_players: opts.num_players,
player: 0,
turn: 1,
hints_total: opts.num_hints,
hints_remaining: opts.num_hints,
lives_total: opts.num_lives,
lives_remaining: opts.num_lives,
// number of turns to play with deck length ran out
deckless_turns_remaining: opts.num_players + 1,
}
}
fn try_add_hint(&mut self) {
if self.hints_remaining < self.hints_total {
self.hints_remaining += 1;
}
}
// returns whether a card would place on a firework
pub fn is_playable(&self, card: &Card) -> bool {
let firework = self.fireworks.get(card.color).unwrap();
let under_card = firework.top().unwrap();
card.value == under_card.value + 1
}
pub fn get_players(&self) -> Vec<Player> {
(0..self.num_players).collect::<Vec<_>>()
}
pub fn score(&self) -> Score {
let mut score = 0;
for (_, firework) in &self.fireworks {
// subtract one to account for the 0 we pushed
score += firework.size() - 1;
}
score as u32
}
pub fn player_to_left(&self, player: &Player) -> Player {
(player + 1) % self.num_players
}
pub fn player_to_right(&self, player: &Player) -> Player {
(player - 1) % self.num_players
}
}
// complete game view of a given player // complete game view of a given player
// state will be borrowed GameState // state will be borrowed GameState
@ -227,63 +302,27 @@ pub type Score = u32;
impl GameState { impl GameState {
pub fn new(opts: &GameOptions) -> GameState { pub fn new(opts: &GameOptions) -> GameState {
let mut deck = GameState::make_deck(); let mut board = BoardState::new(opts);
let mut player_states : HashMap<Player, PlayerState> = HashMap::new(); let mut player_states : HashMap<Player, PlayerState> = HashMap::new();
for i in 0..opts.num_players { for i in 0..opts.num_players {
let raw_hand = (0..opts.hand_size).map(|_| { let raw_hand = (0..opts.hand_size).map(|_| {
// 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() board.deck.draw().unwrap()
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
player_states.insert( player_states.insert(
i, PlayerState::new(Cards::from(raw_hand)), i, PlayerState::new(Cards::from(raw_hand)),
); );
} }
let mut fireworks : HashMap<Color, Cards> = HashMap::new();
for color in COLORS.iter() {
let mut firework = Cards::new();
let card = Card { value: 0, color: color };
firework.place(card);
fireworks.insert(color, firework);
}
GameState { GameState {
player_states: player_states, player_states: player_states,
board: BoardState { board: board,
deck: deck,
fireworks: fireworks,
discard: Cards::new(),
num_players: opts.num_players,
player: 0,
turn: 1,
hints_total: opts.num_hints,
hints_remaining: opts.num_hints,
lives_total: opts.num_lives,
lives_remaining: opts.num_lives,
// number of turns to play with deck length ran out
deckless_turns_remaining: opts.num_players + 1,
}
} }
} }
fn make_deck() -> Cards {
let mut deck: Cards = Cards::from(Vec::new());
for color in COLORS.iter() {
for &(value, count) in VALUE_COUNTS.iter() {
for _ in 0..count {
deck.place(Card {color: color, value: value});
}
}
};
deck.shuffle();
info!("Created deck: {}", deck);
deck
}
pub fn get_players(&self) -> Vec<Player> { pub fn get_players(&self) -> Vec<Player> {
(0..self.board.num_players).collect::<Vec<_>>() self.board.get_players()
} }
pub fn is_over(&self) -> bool { pub fn is_over(&self) -> bool {
@ -293,12 +332,7 @@ impl GameState {
} }
pub fn score(&self) -> Score { pub fn score(&self) -> Score {
let mut score = 0; self.board.score()
for (_, firework) in &self.board.fireworks {
// subtract one to account for the 0 we pushed
score += firework.size() - 1;
}
score as u32
} }
// get the game state view of a particular player // get the game state view of a particular player
@ -322,68 +356,63 @@ impl GameState {
let ref mut state = self.player_states.get_mut(&self.board.player).unwrap(); let ref mut state = self.player_states.get_mut(&self.board.player).unwrap();
let (card, _) = state.take(index); let (card, _) = state.take(index);
if let Some(new_card) = self.board.deck.draw() { if let Some(new_card) = self.board.deck.draw() {
info!("Drew new card, {}", new_card);
state.place(new_card); state.place(new_card);
} }
card card
} }
fn try_add_hint(&mut self) {
if self.board.hints_remaining < self.board.hints_total {
self.board.hints_remaining += 1;
}
}
pub fn process_choice(&mut self, choice: &TurnChoice) { pub fn process_choice(&mut self, choice: &TurnChoice) {
info!("Player {}'s move", self.board.player); info!("Player {}'s move", self.board.player);
match *choice { match choice {
TurnChoice::Hint(ref hint) => { &TurnChoice::Hint(ref hint) => {
assert!(self.board.hints_remaining > 0); assert!(self.board.hints_remaining > 0,
"Tried to hint with no hints remaining");
self.board.hints_remaining -= 1; self.board.hints_remaining -= 1;
info!("Hint to player {}, about {}", hint.player, hint.hinted); info!("Hint to player {}, about {}", hint.player, hint.hinted);
assert!(self.board.player != hint.player,
format!("Player {} gave a hint to himself", hint.player));
let ref mut state = self.player_states.get_mut(&hint.player).unwrap(); let ref mut state = self.player_states.get_mut(&hint.player).unwrap();
state.reveal(&hint.hinted); state.reveal(&hint.hinted);
} }
TurnChoice::Discard(index) => { &TurnChoice::Discard(index) => {
let card = self.take_from_hand(index); let card = self.take_from_hand(index);
info!("Discard {}, which is {}", index, card); info!("Discard card in position {}, which is {}", index, card);
self.board.discard.place(card); self.board.discard.place(card);
self.try_add_hint(); self.board.try_add_hint();
} }
TurnChoice::Play(index) => { &TurnChoice::Play(index) => {
let card = self.take_from_hand(index); let card = self.take_from_hand(index);
info!( info!(
"Playing card at {}, which is {}", "Playing card at position {}, which is {}",
index, card index, card
); );
let mut firework_made = false; let mut firework_made = false;
{ if self.board.is_playable(&card) {
let ref mut firework = self.board.fireworks.get_mut(&card.color).unwrap(); let ref mut firework = self.board.fireworks.get_mut(&card.color).unwrap();
firework_made = card.value == FINAL_VALUE;
let playable = { info!("Successfully played {}!", card);
let under_card = firework.top().unwrap(); if firework_made {
card.value == under_card.value + 1 info!("Firework complete for {}!", card.color);
};
if playable {
firework_made = card.value == FINAL_VALUE;
firework.place(card);
} else {
self.board.discard.place(card);
self.board.lives_remaining -= 1;
info!(
"Removing a life! Lives remaining: {}",
self.board.lives_remaining
);
} }
firework.place(card);
} else {
self.board.discard.place(card);
self.board.lives_remaining -= 1;
info!(
"Removing a life! Lives remaining: {}",
self.board.lives_remaining
);
} }
if firework_made { if firework_made {
self.try_add_hint(); self.board.try_add_hint();
} }
} }
} }
@ -392,7 +421,10 @@ impl GameState {
self.board.deckless_turns_remaining -= 1; self.board.deckless_turns_remaining -= 1;
} }
self.board.turn += 1; self.board.turn += 1;
self.board.player = (self.board.player + 1) % self.board.num_players; self.board.player = {
let cur = self.board.player;
self.board.player_to_left(&cur)
};
assert_eq!((self.board.turn - 1) % self.board.num_players, self.board.player); assert_eq!((self.board.turn - 1) % self.board.num_players, self.board.player);
} }

View file

@ -6,11 +6,13 @@ mod game;
mod strategies; mod strategies;
mod info; mod info;
#[allow(unused_imports)]
use log::LogLevel::{Trace, Debug, Info, Warn, Error};
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 {
true metadata.level() <= Debug
} }
fn log(&self, record: &log::LogRecord) { fn log(&self, record: &log::LogRecord) {
@ -22,10 +24,9 @@ impl log::Log for SimpleLogger {
fn main() { fn main() {
log::set_logger(|max_log_level| { log::set_logger(|max_log_level| {
// Trace, Debug, Info, Warn, ... max_log_level.set(log::LogLevelFilter::Trace);
max_log_level.set(log::LogLevelFilter::Info);
Box::new(SimpleLogger) Box::new(SimpleLogger)
}); }).unwrap();
let opts = game::GameOptions { let opts = game::GameOptions {
num_players: 4, num_players: 4,

View file

@ -99,7 +99,7 @@ impl Strategy for RandomStrategy {
fn initialize(_: &Player, _: &GameStateView) -> () { fn initialize(_: &Player, _: &GameStateView) -> () {
() ()
} }
fn decide(_: &mut (), _: &Player, view: &GameStateView) -> TurnChoice { fn decide(_: &mut (), me: &Player, view: &GameStateView) -> TurnChoice {
let p = rand::random::<f64>(); let p = rand::random::<f64>();
if p < 0.4 { if p < 0.4 {
if view.board.hints_remaining > 0 { if view.board.hints_remaining > 0 {
@ -112,7 +112,7 @@ impl Strategy for RandomStrategy {
} }
}; };
TurnChoice::Hint(Hint { TurnChoice::Hint(Hint {
player: 0, player: view.board.player_to_left(&me),
hinted: hinted, hinted: hinted,
}) })
} else { } else {