From f2de390e0ed9d3485def5e16eb17ca0ed70ec618 Mon Sep 17 00:00:00 2001 From: Jeff Wu Date: Sun, 3 Apr 2016 22:29:57 -0700 Subject: [PATCH] moving stuff around - add hand info - don't manage info in game views - prevent deck size cheat - rearrange stuff --- src/cards.rs | 175 ---------------- src/game.rs | 377 +++++++++++++++++++++------------- src/{info.rs => helpers.rs} | 68 +++++- src/main.rs | 3 +- src/strategies/cheating.rs | 38 ++-- src/strategies/examples.rs | 1 - src/strategies/information.rs | 60 +++--- 7 files changed, 340 insertions(+), 382 deletions(-) delete mode 100644 src/cards.rs rename src/{info.rs => helpers.rs} (85%) diff --git a/src/cards.rs b/src/cards.rs deleted file mode 100644 index 75e2423..0000000 --- a/src/cards.rs +++ /dev/null @@ -1,175 +0,0 @@ -use std::collections::HashMap; -use std::fmt; - -pub type Color = char; -pub const COLORS: [Color; 5] = ['r', 'y', 'g', 'b', 'w']; - -pub type Value = u32; -// list of values, assumed to be small to large -pub const VALUES : [Value; 5] = [1, 2, 3, 4, 5]; -pub const FINAL_VALUE : Value = 5; - -pub fn get_count_for_value(value: Value) -> u32 { - match value { - 1 => 3, - 2 | 3 | 4 => 2, - 5 => 1, - _ => { panic!(format!("Unexpected value: {}", value)); } - } -} - -#[derive(Debug,Clone,PartialEq,Eq,Hash,Ord,PartialOrd)] -pub struct Card { - pub color: Color, - pub value: Value, -} -impl Card { - pub fn new(color: Color, value: Value) -> Card { - Card { color: color, value: value } - } -} -impl fmt::Display for Card { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}{}", self.color, self.value) - } -} - -pub type Cards = Vec; - -#[derive(Debug,Clone)] -pub struct CardCounts { - counts: HashMap, -} -impl CardCounts { - pub fn new() -> CardCounts { - let mut counts = HashMap::new(); - for &color in COLORS.iter() { - for &value in VALUES.iter() { - counts.insert(Card::new(color, value), 0); - } - } - CardCounts { - counts: counts, - } - } - - pub fn get_count(&self, card: &Card) -> u32 { - *self.counts.get(card).unwrap() - } - - pub fn remaining(&self, card: &Card) -> u32 { - let count = self.get_count(card); - get_count_for_value(card.value) - count - } - - pub fn increment(&mut self, card: &Card) { - let count = self.counts.get_mut(card).unwrap(); - *count += 1; - } -} -impl fmt::Display for CardCounts { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for &color in COLORS.iter() { - try!(f.write_str(&format!( - "{}: ", color, - ))); - for &value in VALUES.iter() { - let count = self.get_count(&Card::new(color, value)); - let total = get_count_for_value(value); - try!(f.write_str(&format!( - "{}/{} {}s", count, total, value - ))); - if value != FINAL_VALUE { - try!(f.write_str(", ")); - } - } - try!(f.write_str("\n")); - } - Ok(()) - } -} - -#[derive(Debug,Clone)] -pub struct Discard { - pub cards: Cards, - counts: CardCounts, -} -impl Discard { - pub fn new() -> Discard { - Discard { - cards: Cards::new(), - counts: CardCounts::new(), - } - } - - pub fn has_all(&self, card: &Card) -> bool { - self.counts.remaining(card) == 0 - } - - pub fn remaining(&self, card: &Card) -> u32 { - self.counts.remaining(card) - } - - pub fn place(&mut self, card: Card) { - self.counts.increment(&card); - self.cards.push(card); - } -} -impl fmt::Display for Discard { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // try!(f.write_str(&format!( - // "{}", self.cards, - // ))); - write!(f, "{}", self.counts) - } -} - -pub type Score = u32; -pub const PERFECT_SCORE: Score = 25; - -#[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 needed_value(&self) -> Option { - 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.needed_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) - } - } -} diff --git a/src/game.rs b/src/game.rs index 04a407d..7fcc5d5 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,14 +1,184 @@ use std::collections::HashMap; use std::fmt; -use std::iter; -use std::slice::IterMut; use std::ops::Range; -pub use info::*; -pub use cards::*; - pub type Player = u32; +pub type Color = char; +pub const NUM_COLORS: usize = 5; +pub const COLORS: [Color; NUM_COLORS] = ['r', 'y', 'g', 'b', 'w']; + +pub type Value = u32; +// list of values, assumed to be small to large +pub const NUM_VALUES: usize = 5; +pub const VALUES : [Value; NUM_VALUES] = [1, 2, 3, 4, 5]; +pub const FINAL_VALUE : Value = 5; + +pub fn get_count_for_value(value: Value) -> u32 { + match value { + 1 => 3, + 2 | 3 | 4 => 2, + 5 => 1, + _ => { panic!(format!("Unexpected value: {}", value)); } + } +} + +#[derive(Debug,Clone,PartialEq,Eq,Hash,Ord,PartialOrd)] +pub struct Card { + pub color: Color, + pub value: Value, +} +impl Card { + pub fn new(color: Color, value: Value) -> Card { + Card { color: color, value: value } + } +} +impl fmt::Display for Card { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}{}", self.color, self.value) + } +} + +#[derive(Debug,Clone)] +pub struct CardCounts { + counts: HashMap, +} +impl CardCounts { + pub fn new() -> CardCounts { + let mut counts = HashMap::new(); + for &color in COLORS.iter() { + for &value in VALUES.iter() { + counts.insert(Card::new(color, value), 0); + } + } + CardCounts { + counts: counts, + } + } + + pub fn get_count(&self, card: &Card) -> u32 { + *self.counts.get(card).unwrap() + } + + pub fn remaining(&self, card: &Card) -> u32 { + let count = self.get_count(card); + get_count_for_value(card.value) - count + } + + pub fn increment(&mut self, card: &Card) { + let count = self.counts.get_mut(card).unwrap(); + *count += 1; + } +} +impl fmt::Display for CardCounts { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for &color in COLORS.iter() { + try!(f.write_str(&format!( + "{}: ", color, + ))); + for &value in VALUES.iter() { + let count = self.get_count(&Card::new(color, value)); + let total = get_count_for_value(value); + try!(f.write_str(&format!( + "{}/{} {}s", count, total, value + ))); + if value != FINAL_VALUE { + try!(f.write_str(", ")); + } + } + try!(f.write_str("\n")); + } + Ok(()) + } +} + +pub type Cards = Vec; + +#[derive(Debug,Clone)] +pub struct Discard { + pub cards: Cards, + counts: CardCounts, +} +impl Discard { + pub fn new() -> Discard { + Discard { + cards: Cards::new(), + counts: CardCounts::new(), + } + } + + pub fn has_all(&self, card: &Card) -> bool { + self.counts.remaining(card) == 0 + } + + pub fn remaining(&self, card: &Card) -> u32 { + self.counts.remaining(card) + } + + pub fn place(&mut self, card: Card) { + self.counts.increment(&card); + self.cards.push(card); + } +} +impl fmt::Display for Discard { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // try!(f.write_str(&format!( + // "{}", self.cards, + // ))); + write!(f, "{}", self.counts) + } +} + +pub type Score = u32; +pub const PERFECT_SCORE: Score = (NUM_COLORS * NUM_VALUES) as 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 needed_value(&self) -> Option { + 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.needed_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) + } + } +} + #[derive(Debug,Clone,Hash,PartialEq,Eq)] pub enum Hinted { Color(Color), @@ -65,80 +235,11 @@ pub struct GameOptions { pub allow_empty_hints: bool, } -// The state of a given player: all other players may see this -#[derive(Debug,Clone)] -pub struct PlayerState { - // the player's actual hand - pub hand: Cards, - // represents what is common knowledge about the player's hand - pub info: Vec, -} -impl fmt::Display for PlayerState { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(f.write_str("hand: ")); - - let mut i = 0; - for card in &self.hand { - let info : &SimpleCardInfo = &self.info[i]; - try!(f.write_str(&format!("{} =? {: <15} ", card, info))); - i += 1; - } - Ok(()) - } -} -impl PlayerState { - pub fn new(hand: Cards) -> PlayerState { - let infos = (0..hand.len()).map(|_| { - SimpleCardInfo::new() - }).collect::>(); - PlayerState { - hand: hand, - info: infos, - } - } - - pub fn take(&mut self, index: usize) -> (Card, SimpleCardInfo) { - let card = self.hand.remove(index); - let info = self.info.remove(index); - (card, info) - } - - pub fn place(&mut self, card: Card) { - self.hand.push(card); - self.info.push(SimpleCardInfo::new()); - } - - fn hand_info_iter_mut<'a>(&'a mut self) -> - iter::Zip, IterMut<'a, SimpleCardInfo>> - { - self.hand.iter_mut().zip(self.info.iter_mut()) - } - - pub fn reveal(&mut self, hinted: &Hinted) -> Vec { - match hinted { - &Hinted::Color(color) => { - self.hand_info_iter_mut().map(|(card, info)| { - let matches = card.color == color; - info.mark_color(color, matches); - matches - }).collect::>() - } - &Hinted::Value(value) => { - self.hand_info_iter_mut().map(|(card, info)| { - let matches = card.value == value; - info.mark_value(value, matches); - matches - }).collect::>() - } - } - } -} - // State of everything except the player's hands // Is all completely common knowledge #[derive(Debug,Clone)] pub struct BoardState { - deck: Cards, + pub deck_size: u32, pub total_cards: u32, pub discard: Discard, pub fireworks: HashMap, @@ -161,16 +262,14 @@ pub struct BoardState { pub deckless_turns_remaining: u32, } impl BoardState { - pub fn new(opts: &GameOptions, deck: Cards) -> BoardState { + pub fn new(opts: &GameOptions, deck_size: u32) -> BoardState { let fireworks = COLORS.iter().map(|&color| { (color, Firework::new(color)) }).collect::>(); - let total_cards = deck.len() as u32; - BoardState { - deck: deck, - total_cards: total_cards, + deck_size: deck_size, + total_cards: deck_size, fireworks: fireworks, discard: Discard::new(), num_players: opts.num_players, @@ -272,10 +371,6 @@ impl BoardState { self.fireworks.iter().map(|(_, firework)| firework.score()).fold(0, |a, b| a + b) } - pub fn deck_size(&self) -> u32 { - self.deck.len() as u32 - } - pub fn discard_size(&self) -> u32 { self.discard.cards.len() as u32 } @@ -303,11 +398,10 @@ impl fmt::Display for BoardState { ))); } - let deck_size = self.deck_size(); try!(f.write_str(&format!( - "{} cards remaining in deck\n", deck_size + "{} cards remaining in deck\n", self.deck_size ))); - if deck_size == 0 { + if self.deck_size == 0 { try!(f.write_str(&format!( "Deck is empty. {} turns remaining in game\n", self.deckless_turns_remaining ))); @@ -332,18 +426,14 @@ impl fmt::Display for BoardState { // complete game view of a given player pub trait GameView { fn me(&self) -> Player; - fn my_info(&self) -> &Vec; - fn get_state(&self, player: &Player) -> &PlayerState; + fn get_hand(&self, &Player) -> &Cards; fn get_board(&self) -> &BoardState; - fn get_hand(&self, player: &Player) -> &Cards { - assert!(self.me() != *player, "Cannot query about your own cards!"); - &self.get_state(player).hand - } + fn my_hand_size(&self) -> usize; fn hand_size(&self, player: &Player) -> usize { if self.me() == *player { - self.my_info().len() + self.my_hand_size() } else { self.get_hand(player).len() } @@ -379,10 +469,9 @@ pub trait GameView { pub struct BorrowedGameView<'a> { // the player whose view it is pub player: Player, - // what is known about their own hand (and thus common knowledge) - pub info: &'a Vec, + pub hand_size: usize, // the cards of the other players, as well as the information they have - pub other_player_states: HashMap, + pub other_hands: HashMap, // board state pub board: &'a BoardState, } @@ -390,12 +479,12 @@ impl <'a> GameView for BorrowedGameView<'a> { fn me(&self) -> Player { self.player } - fn my_info(&self) -> &Vec { - self.info + fn my_hand_size(&self) -> usize { + self.hand_size } - fn get_state(&self, player: &Player) -> &PlayerState { + fn get_hand(&self, player: &Player) -> &Cards { assert!(self.me() != *player, "Cannot query about your own state!"); - self.other_player_states.get(player).unwrap() + self.other_hands.get(player).unwrap() } fn get_board(&self) -> &BoardState { self.board @@ -407,27 +496,23 @@ impl <'a> GameView for BorrowedGameView<'a> { pub struct OwnedGameView { // the player whose view it is pub player: Player, - // what is known about their own hand (and thus common knowledge) - pub info: Vec, + pub hand_size: usize, // the cards of the other players, as well as the information they have - pub other_player_states: HashMap, + pub other_hands: HashMap, // board state pub board: BoardState, } impl OwnedGameView { pub fn clone_from(borrowed_view: &BorrowedGameView) -> OwnedGameView { - let info = borrowed_view.info.iter() - .map(|card_info| card_info.clone()).collect::>(); - - let other_player_states = borrowed_view.other_player_states.iter() + let other_hands = borrowed_view.other_hands.iter() .map(|(&other_player, &player_state)| { (other_player, player_state.clone()) }).collect::>(); OwnedGameView { player: borrowed_view.player.clone(), - info: info, - other_player_states: other_player_states, + hand_size: borrowed_view.hand_size, + other_hands: other_hands, board: (*borrowed_view.board).clone(), } } @@ -436,24 +521,24 @@ impl GameView for OwnedGameView { fn me(&self) -> Player { self.player } - fn my_info(&self) -> &Vec { - &self.info + fn my_hand_size(&self) -> usize { + self.hand_size } - fn get_state(&self, player: &Player) -> &PlayerState { + fn get_hand(&self, player: &Player) -> &Cards { assert!(self.me() != *player, "Cannot query about your own state!"); - self.other_player_states.get(player).unwrap() + self.other_hands.get(player).unwrap() } fn get_board(&self) -> &BoardState { &self.board } } - // complete game state (known to nobody!) #[derive(Debug)] pub struct GameState { - pub player_states: HashMap, + pub hands: HashMap, pub board: BoardState, + pub deck: Cards, } impl fmt::Display for GameState { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -462,8 +547,12 @@ impl fmt::Display for GameState { try!(f.write_str("Hands:\n")); try!(f.write_str("======\n")); for player in self.board.get_players() { - let state = &self.player_states.get(&player).unwrap(); - try!(f.write_str(&format!("player {} {}\n", player, state))); + let hand = &self.hands.get(&player).unwrap(); + try!(f.write_str(&format!("player {}:", player))); + for card in hand.iter() { + try!(f.write_str(&format!(" {}", card))); + } + try!(f.write_str(&"\n")); } try!(f.write_str("======\n")); try!(f.write_str("Board:\n")); @@ -474,21 +563,23 @@ impl fmt::Display for GameState { } impl GameState { - pub fn new(opts: &GameOptions, deck: Cards) -> GameState { - let mut board = BoardState::new(opts, deck); + pub fn new(opts: &GameOptions, mut deck: Cards) -> GameState { + let mut board = BoardState::new(opts, deck.len() as u32); - let player_states = + let hands = (0..opts.num_players).map(|player| { let hand = (0..opts.hand_size).map(|_| { // we can assume the deck is big enough to draw initial hands - board.deck.pop().unwrap() + board.deck_size -= 1; + deck.pop().unwrap() }).collect::>(); - (player, PlayerState::new(hand)) + (player, hand) }).collect::>(); GameState { - player_states: player_states, + hands: hands, board: board, + deck: deck, } } @@ -506,33 +597,33 @@ impl GameState { // get the game state view of a particular player pub fn get_view(&self, player: Player) -> BorrowedGameView { - let mut other_player_states = HashMap::new(); - for (&other_player, state) in &self.player_states { + let mut other_hands = HashMap::new(); + for (&other_player, hand) in &self.hands { if player != other_player { - other_player_states.insert(other_player, state); + other_hands.insert(other_player, hand); } } BorrowedGameView { player: player, - info: &self.player_states.get(&player).unwrap().info, - other_player_states: other_player_states, + hand_size: self.hands.get(&player).unwrap().len(), + other_hands: other_hands, board: &self.board, } } // takes a card from the player's hand, and replaces it if possible fn take_from_hand(&mut self, index: usize) -> Card { - let ref mut state = self.player_states.get_mut(&self.board.player).unwrap(); - let (card, _) = state.take(index); - card + let ref mut hand = self.hands.get_mut(&self.board.player).unwrap(); + hand.remove(index) } fn replenish_hand(&mut self) { - let ref mut state = self.player_states.get_mut(&self.board.player).unwrap(); - if (state.hand.len() as u32) < self.board.hand_size { - if let Some(new_card) = self.board.deck.pop() { + let ref mut hand = self.hands.get_mut(&self.board.player).unwrap(); + if (hand.len() as u32) < self.board.hand_size { + if let Some(new_card) = self.deck.pop() { + self.board.deck_size -= 1; debug!("Drew new card, {}", new_card); - state.place(new_card); + hand.push(new_card); } } } @@ -549,11 +640,19 @@ impl GameState { 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 results = state.reveal(&hint.hinted); + let hand = self.hands.get(&hint.player).unwrap(); + let results = match hint.hinted { + Hinted::Color(color) => { + hand.iter().map(|card| { card.color == color }).collect::>() + } + Hinted::Value(value) => { + hand.iter().map(|card| { card.value == value }).collect::>() + } + }; if (!self.board.allow_empty_hints) && (results.iter().all(|matched| !matched)) { panic!("Tried hinting an empty hint"); } + TurnResult::Hint(results) } TurnChoice::Discard(index) => { @@ -603,7 +702,7 @@ impl GameState { self.replenish_hand(); - if self.board.deck.len() == 0 { + if self.board.deck_size == 0 { self.board.deckless_turns_remaining -= 1; } self.board.turn += 1; diff --git a/src/info.rs b/src/helpers.rs similarity index 85% rename from src/info.rs rename to src/helpers.rs index a8289f6..4a89f9c 100644 --- a/src/info.rs +++ b/src/helpers.rs @@ -1,14 +1,17 @@ use std::cmp::Eq; use std::collections::{HashMap, HashSet}; use std::fmt; +use std::ops::{Index,IndexMut}; use std::hash::Hash; use std::convert::From; +use std::slice; -use cards::*; -use game::BoardState; +use game::*; // trait representing information about a card pub trait CardInfo { + fn new() -> Self; + // whether the card is possible fn is_possible(&self, card: &Card) -> bool; @@ -190,15 +193,14 @@ pub struct SimpleCardInfo { pub color_info: ColorInfo, pub value_info: ValueInfo, } -impl SimpleCardInfo { - pub fn new() -> SimpleCardInfo { +impl CardInfo for SimpleCardInfo { + fn new() -> SimpleCardInfo { SimpleCardInfo { color_info: ColorInfo::new(), value_info: ValueInfo::new(), } } -} -impl CardInfo for SimpleCardInfo { + fn get_possibilities(&self) -> Vec { let mut v = Vec::new(); for &color in self.color_info.get_possibilities().iter() { @@ -249,10 +251,6 @@ pub struct CardPossibilityTable { possible: HashMap, } impl CardPossibilityTable { - pub fn new() -> CardPossibilityTable { - Self::from(&CardCounts::new()) - } - // mark a possible card as false pub fn mark_false(&mut self, card: &Card) { self.possible.remove(card); @@ -327,6 +325,10 @@ impl <'a> From<&'a CardCounts> for CardPossibilityTable { } } impl CardInfo for CardPossibilityTable { + fn new() -> CardPossibilityTable { + Self::from(&CardCounts::new()) + } + fn is_possible(&self, card: &Card) -> bool { self.possible.contains_key(card) } @@ -358,3 +360,49 @@ impl fmt::Display for CardPossibilityTable { Ok(()) } } + +#[derive(Clone)] +pub struct HandInfo where T: CardInfo { + pub hand_info: Vec +} +impl HandInfo where T: CardInfo { + pub fn new(hand_size: u32) -> Self { + let hand_info = (0..hand_size).map(|_| T::new()).collect::>(); + HandInfo { + hand_info: hand_info, + } + } + + // update for hint to me + pub fn update_for_hint(&mut self, hinted: &Hinted, matches: &Vec) { + match hinted { + &Hinted::Color(color) => { + for (card_info, &matched) in self.hand_info.iter_mut().zip(matches.iter()) { + card_info.mark_color(color, matched); + } + } + &Hinted::Value(value) => { + for (card_info, &matched) in self.hand_info.iter_mut().zip(matches.iter()) { + card_info.mark_value(value, matched); + } + } + } + } + + pub fn remove(&mut self, index: usize) -> T { self.hand_info.remove(index) } + pub fn push(&mut self, card_info: T) { self.hand_info.push(card_info) } + pub fn iter_mut(&mut self) -> slice::IterMut { self.hand_info.iter_mut() } + pub fn iter(&self) -> slice::Iter { self.hand_info.iter() } + pub fn len(&self) -> usize { self.hand_info.len() } +} +impl Index for HandInfo where T: CardInfo { + type Output = T; + fn index(&self, index: usize) -> &T { + &self.hand_info[index] + } +} +impl IndexMut for HandInfo where T: CardInfo { + fn index_mut(&mut self, index: usize) -> &mut T { + &mut self.hand_info[index] + } +} diff --git a/src/main.rs b/src/main.rs index c2daf1e..167969f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,8 +4,7 @@ extern crate log; extern crate rand; extern crate crossbeam; -mod cards; -mod info; +mod helpers; mod game; mod simulator; mod strategies { diff --git a/src/strategies/cheating.rs b/src/strategies/cheating.rs index f7e362e..b7010bb 100644 --- a/src/strategies/cheating.rs +++ b/src/strategies/cheating.rs @@ -17,7 +17,6 @@ use game::*; // - if a hint exists, hint // - discard the first card -#[allow(dead_code)] pub struct CheatingStrategyConfig; impl CheatingStrategyConfig { @@ -32,40 +31,41 @@ impl GameStrategyConfig for CheatingStrategyConfig { } pub struct CheatingStrategy { - player_states_cheat: Rc>>, + player_hands_cheat: Rc>>, } impl CheatingStrategy { pub fn new() -> CheatingStrategy { CheatingStrategy { - player_states_cheat: Rc::new(RefCell::new(HashMap::new())), + player_hands_cheat: Rc::new(RefCell::new(HashMap::new())), } } } impl GameStrategy for CheatingStrategy { fn initialize(&self, player: Player, view: &BorrowedGameView) -> Box { - for (&player, state) in &view.other_player_states { - self.player_states_cheat.borrow_mut().insert( - player, state.hand.clone() + for (&player, &hand) in &view.other_hands { + self.player_hands_cheat.borrow_mut().insert( + player, hand.clone() ); } Box::new(CheatingPlayerStrategy { - player_states_cheat: self.player_states_cheat.clone(), + player_hands_cheat: self.player_hands_cheat.clone(), me: player, }) } } pub struct CheatingPlayerStrategy { - player_states_cheat: Rc>>, + player_hands_cheat: Rc>>, me: Player, } impl CheatingPlayerStrategy { // last player might've drawn a new card, let him know! fn inform_last_player_cards(&self, view: &BorrowedGameView) { let next = view.board.player_to_right(&self.me); - self.player_states_cheat.borrow_mut().insert( - next, view.other_player_states.get(&next).unwrap().hand.clone() + let their_hand = *view.other_hands.get(&next).unwrap(); + self.player_hands_cheat.borrow_mut().insert( + next, their_hand.clone() ); } @@ -98,15 +98,15 @@ impl CheatingPlayerStrategy { // how badly do we need to play a particular card fn get_play_score(&self, view: &BorrowedGameView, card: &Card) -> i32 { - let states = self.player_states_cheat.borrow(); - let my_hand = states.get(&self.me).unwrap(); + let hands = self.player_hands_cheat.borrow(); + let my_hand = hands.get(&self.me).unwrap(); let my_hand_value = self.hand_play_value(view, my_hand); for player in view.board.get_players() { if player != self.me { if view.has_card(&player, card) { - let their_hand_value = self.hand_play_value(view, states.get(&player).unwrap()); + let their_hand_value = self.hand_play_value(view, hands.get(&player).unwrap()); // they can play this card, and have less urgent plays than i do if their_hand_value < my_hand_value { return 10 - (card.value as i32) @@ -139,9 +139,9 @@ impl PlayerStrategy for CheatingPlayerStrategy { fn decide(&mut self, view: &BorrowedGameView) -> TurnChoice { self.inform_last_player_cards(view); - let states = self.player_states_cheat.borrow(); - let my_cards = states.get(&self.me).unwrap(); - let playable_cards = my_cards.iter().enumerate().filter(|&(_, card)| { + let hands = self.player_hands_cheat.borrow(); + let my_hand = hands.get(&self.me).unwrap(); + let playable_cards = my_hand.iter().enumerate().filter(|&(_, card)| { view.board.is_playable(card) }).collect::>(); @@ -171,7 +171,7 @@ impl PlayerStrategy for CheatingPlayerStrategy { - (view.board.num_players * view.board.hand_size); if view.board.discard_size() <= discard_threshold { // if anything is totally useless, discard it - if let Some(i) = self.find_useless_card(view, my_cards) { + if let Some(i) = self.find_useless_card(view, my_hand) { return TurnChoice::Discard(i); } } @@ -185,7 +185,7 @@ impl PlayerStrategy for CheatingPlayerStrategy { } // if anything is totally useless, discard it - if let Some(i) = self.find_useless_card(view, my_cards) { + if let Some(i) = self.find_useless_card(view, my_hand) { return TurnChoice::Discard(i); } @@ -195,7 +195,7 @@ impl PlayerStrategy for CheatingPlayerStrategy { // The higher, the better to discard let mut index = 0; let mut compval = (false, false, 0); - for (i, card) in my_cards.iter().enumerate() { + for (i, card) in my_hand.iter().enumerate() { let my_compval = ( view.can_see(card), view.board.is_dispensable(card), diff --git a/src/strategies/examples.rs b/src/strategies/examples.rs index ff1c3df..7d3b827 100644 --- a/src/strategies/examples.rs +++ b/src/strategies/examples.rs @@ -3,7 +3,6 @@ use game::*; use rand::{self, Rng}; // dummy, terrible strategy, as an example -#[allow(dead_code)] #[derive(Clone)] pub struct RandomStrategyConfig { pub hint_probability: f64, diff --git a/src/strategies/information.rs b/src/strategies/information.rs index fa34005..6980636 100644 --- a/src/strategies/information.rs +++ b/src/strategies/information.rs @@ -3,6 +3,7 @@ use std::cmp::Ordering; use simulator::*; use game::*; +use helpers::*; // TODO: use random extra information - i.e. when casting up and down, // we sometimes have 2 choices of value to choose @@ -73,7 +74,7 @@ trait Question { fn answer(&self, &Cards, &OwnedGameView) -> u32; // process the answer to this question, updating card info fn acknowledge_answer( - &self, value: u32, &mut Vec, &OwnedGameView + &self, value: u32, &mut HandInfo, &OwnedGameView ); fn answer_info(&self, hand: &Cards, view: &OwnedGameView) -> ModulusInformation { @@ -86,7 +87,7 @@ trait Question { fn acknowledge_answer_info( &self, answer: ModulusInformation, - hand_info: &mut Vec, + hand_info: &mut HandInfo, view: &OwnedGameView ) { assert!(self.info_amount() == answer.modulus); @@ -105,7 +106,7 @@ impl Question for IsPlayable { fn acknowledge_answer( &self, answer: u32, - hand_info: &mut Vec, + hand_info: &mut HandInfo, view: &OwnedGameView, ) { let ref mut card_table = hand_info[self.index]; @@ -187,7 +188,7 @@ impl Question for CardPossibilityPartition { fn acknowledge_answer( &self, answer: u32, - hand_info: &mut Vec, + hand_info: &mut HandInfo, _: &OwnedGameView, ) { let ref mut card_table = hand_info[self.index]; @@ -200,7 +201,6 @@ impl Question for CardPossibilityPartition { } } -#[allow(dead_code)] pub struct InformationStrategyConfig; impl InformationStrategyConfig { @@ -225,7 +225,7 @@ impl GameStrategy for InformationStrategy { fn initialize(&self, player: Player, view: &BorrowedGameView) -> Box { let public_info = view.board.get_players().map(|player| { - let hand_info = (0..view.board.hand_size).map(|_| { CardPossibilityTable::new() }).collect::>(); + let hand_info = HandInfo::new(view.board.hand_size); (player, hand_info) }).collect::>(); @@ -240,16 +240,17 @@ impl GameStrategy for InformationStrategy { pub struct InformationPlayerStrategy { me: Player, - public_info: HashMap>, + public_info: HashMap>, public_counts: CardCounts, // what any newly drawn card should be last_view: OwnedGameView, // the view on the previous turn } + impl InformationPlayerStrategy { fn get_questions( total_info: u32, view: &OwnedGameView, - hand_info: &Vec, + hand_info: &HandInfo, ) -> Vec> { let mut questions = Vec::new(); let mut info_remaining = total_info; @@ -443,7 +444,7 @@ impl InformationPlayerStrategy { fn get_play_score(&self, view: &OwnedGameView, card: &Card) -> f32 { let mut num_with = 1; - if view.board.deck_size() > 0 { + if view.board.deck_size > 0 { for player in view.board.get_players() { if player != self.me { if view.has_card(&player, card) { @@ -455,7 +456,7 @@ impl InformationPlayerStrategy { (10.0 - card.value as f32) / (num_with as f32) } - fn find_useless_cards(&self, view: &OwnedGameView, hand: &Vec) -> Vec { + fn find_useless_cards(&self, view: &OwnedGameView, hand: &HandInfo) -> Vec { let mut useless: HashSet = HashSet::new(); let mut seen: HashMap = HashMap::new(); @@ -479,47 +480,34 @@ impl InformationPlayerStrategy { return useless_vec; } - fn take_public_info(&mut self, player: &Player) -> Vec { + fn take_public_info(&mut self, player: &Player) -> HandInfo { self.public_info.remove(player).unwrap() } - fn return_public_info(&mut self, player: &Player, card_info: Vec) { + fn return_public_info(&mut self, player: &Player, card_info: HandInfo) { self.public_info.insert(*player, card_info); } - fn get_my_public_info(&self) -> &Vec { + fn get_my_public_info(&self) -> &HandInfo { self.get_player_public_info(&self.me) } - // fn get_my_public_info_mut(&mut self) -> &mut Vec { + // fn get_my_public_info_mut(&mut self) -> &mut HandInfo { // let me = self.me.clone(); // self.get_player_public_info_mut(&me) // } - fn get_player_public_info(&self, player: &Player) -> &Vec { + fn get_player_public_info(&self, player: &Player) -> &HandInfo { self.public_info.get(player).unwrap() } - fn get_player_public_info_mut(&mut self, player: &Player) -> &mut Vec { + fn get_player_public_info_mut(&mut self, player: &Player) -> &mut HandInfo { self.public_info.get_mut(player).unwrap() } fn update_public_info_for_hint(&mut self, hint: &Hint, matches: &Vec) { let mut info = self.get_player_public_info_mut(&hint.player); - let zip_iter = info.iter_mut().zip(matches); - match hint.hinted { - Hinted::Color(color) => { - for (card_info, matched) in zip_iter { - card_info.mark_color(color, *matched); - } - } - Hinted::Value(value) => { - for (card_info, matched) in zip_iter { - card_info.mark_value(value, *matched); - } - } - - } + info.update_for_hint(&hint.hinted, matches); } fn update_public_info_for_discard_or_play( @@ -547,7 +535,7 @@ impl InformationPlayerStrategy { // in particular, we will decrement the newly drawn card for other_player in view.board.get_players() { let info = self.get_player_public_info_mut(&other_player); - for card_table in info { + for card_table in info.iter_mut() { card_table.decrement_weight_if_possible(card); } } @@ -555,11 +543,11 @@ impl InformationPlayerStrategy { self.public_counts.increment(card); } - fn get_private_info(&self, view: &OwnedGameView) -> Vec { + fn get_private_info(&self, view: &OwnedGameView) -> HandInfo { let mut info = self.get_my_public_info().clone(); for card_table in info.iter_mut() { - for (_, state) in &view.other_player_states { - for card in &state.hand { + for (_, hand) in &view.other_hands { + for card in hand { card_table.decrement_weight_if_possible(card); } } @@ -585,7 +573,7 @@ impl InformationPlayerStrategy { return score; } - fn get_index_for_hint(&self, info: &Vec, view: &OwnedGameView) -> usize { + fn get_index_for_hint(&self, info: &HandInfo, view: &OwnedGameView) -> usize { let mut scores = info.iter().enumerate().map(|(i, card_table)| { let score = self.get_hint_index_score(card_table, view); (-score, i) @@ -739,8 +727,8 @@ impl InformationPlayerStrategy { self.update_from_hint_sum(mod_info); } - } + impl PlayerStrategy for InformationPlayerStrategy { fn decide(&mut self, _: &BorrowedGameView) -> TurnChoice { // we already stored the view