moving stuff around
- add hand info - don't manage info in game views - prevent deck size cheat - rearrange stuff
This commit is contained in:
parent
d86136889d
commit
f2de390e0e
7 changed files with 340 additions and 382 deletions
175
src/cards.rs
175
src/cards.rs
|
@ -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<Card>;
|
||||
|
||||
#[derive(Debug,Clone)]
|
||||
pub struct CardCounts {
|
||||
counts: HashMap<Card, u32>,
|
||||
}
|
||||
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<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.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)
|
||||
}
|
||||
}
|
||||
}
|
377
src/game.rs
377
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<Card, u32>,
|
||||
}
|
||||
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<Card>;
|
||||
|
||||
#[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<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.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<SimpleCardInfo>,
|
||||
}
|
||||
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::<Vec<_>>();
|
||||
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, Card>, IterMut<'a, SimpleCardInfo>>
|
||||
{
|
||||
self.hand.iter_mut().zip(self.info.iter_mut())
|
||||
}
|
||||
|
||||
pub fn reveal(&mut self, hinted: &Hinted) -> Vec<bool> {
|
||||
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::<Vec<_>>()
|
||||
}
|
||||
&Hinted::Value(value) => {
|
||||
self.hand_info_iter_mut().map(|(card, info)| {
|
||||
let matches = card.value == value;
|
||||
info.mark_value(value, matches);
|
||||
matches
|
||||
}).collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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<Color, Firework>,
|
||||
|
@ -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::<HashMap<_, _>>();
|
||||
|
||||
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<SimpleCardInfo>;
|
||||
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<SimpleCardInfo>,
|
||||
pub hand_size: usize,
|
||||
// the cards of the other players, as well as the information they have
|
||||
pub other_player_states: HashMap<Player, &'a PlayerState>,
|
||||
pub other_hands: HashMap<Player, &'a Cards>,
|
||||
// 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<SimpleCardInfo> {
|
||||
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<SimpleCardInfo>,
|
||||
pub hand_size: usize,
|
||||
// the cards of the other players, as well as the information they have
|
||||
pub other_player_states: HashMap<Player, PlayerState>,
|
||||
pub other_hands: HashMap<Player, Cards>,
|
||||
// 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::<Vec<_>>();
|
||||
|
||||
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::<HashMap<_, _>>();
|
||||
|
||||
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<SimpleCardInfo> {
|
||||
&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<Player, PlayerState>,
|
||||
pub hands: HashMap<Player, Cards>,
|
||||
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::<Vec<_>>();
|
||||
(player, PlayerState::new(hand))
|
||||
(player, hand)
|
||||
}).collect::<HashMap<_, _>>();
|
||||
|
||||
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::<Vec<_>>()
|
||||
}
|
||||
Hinted::Value(value) => {
|
||||
hand.iter().map(|card| { card.value == value }).collect::<Vec<_>>()
|
||||
}
|
||||
};
|
||||
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;
|
||||
|
|
|
@ -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<Card> {
|
||||
let mut v = Vec::new();
|
||||
for &color in self.color_info.get_possibilities().iter() {
|
||||
|
@ -249,10 +251,6 @@ pub struct CardPossibilityTable {
|
|||
possible: HashMap<Card, u32>,
|
||||
}
|
||||
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<T> where T: CardInfo {
|
||||
pub hand_info: Vec<T>
|
||||
}
|
||||
impl <T> HandInfo<T> where T: CardInfo {
|
||||
pub fn new(hand_size: u32) -> Self {
|
||||
let hand_info = (0..hand_size).map(|_| T::new()).collect::<Vec<_>>();
|
||||
HandInfo {
|
||||
hand_info: hand_info,
|
||||
}
|
||||
}
|
||||
|
||||
// update for hint to me
|
||||
pub fn update_for_hint(&mut self, hinted: &Hinted, matches: &Vec<bool>) {
|
||||
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<T> { self.hand_info.iter_mut() }
|
||||
pub fn iter(&self) -> slice::Iter<T> { self.hand_info.iter() }
|
||||
pub fn len(&self) -> usize { self.hand_info.len() }
|
||||
}
|
||||
impl <T> Index<usize> for HandInfo<T> where T: CardInfo {
|
||||
type Output = T;
|
||||
fn index(&self, index: usize) -> &T {
|
||||
&self.hand_info[index]
|
||||
}
|
||||
}
|
||||
impl <T> IndexMut<usize> for HandInfo<T> where T: CardInfo {
|
||||
fn index_mut(&mut self, index: usize) -> &mut T {
|
||||
&mut self.hand_info[index]
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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<RefCell<HashMap<Player, Cards>>>,
|
||||
player_hands_cheat: Rc<RefCell<HashMap<Player, Cards>>>,
|
||||
}
|
||||
|
||||
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<PlayerStrategy> {
|
||||
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<RefCell<HashMap<Player, Cards>>>,
|
||||
player_hands_cheat: Rc<RefCell<HashMap<Player, Cards>>>,
|
||||
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::<Vec<_>>();
|
||||
|
||||
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<CardPossibilityTable>, &OwnedGameView
|
||||
&self, value: u32, &mut HandInfo<CardPossibilityTable>, &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<CardPossibilityTable>,
|
||||
hand_info: &mut HandInfo<CardPossibilityTable>,
|
||||
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<CardPossibilityTable>,
|
||||
hand_info: &mut HandInfo<CardPossibilityTable>,
|
||||
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<CardPossibilityTable>,
|
||||
hand_info: &mut HandInfo<CardPossibilityTable>,
|
||||
_: &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<PlayerStrategy> {
|
||||
let public_info =
|
||||
view.board.get_players().map(|player| {
|
||||
let hand_info = (0..view.board.hand_size).map(|_| { CardPossibilityTable::new() }).collect::<Vec<_>>();
|
||||
let hand_info = HandInfo::new(view.board.hand_size);
|
||||
(player, hand_info)
|
||||
}).collect::<HashMap<_,_>>();
|
||||
|
||||
|
@ -240,16 +240,17 @@ impl GameStrategy for InformationStrategy {
|
|||
|
||||
pub struct InformationPlayerStrategy {
|
||||
me: Player,
|
||||
public_info: HashMap<Player, Vec<CardPossibilityTable>>,
|
||||
public_info: HashMap<Player, HandInfo<CardPossibilityTable>>,
|
||||
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<CardPossibilityTable>,
|
||||
hand_info: &HandInfo<CardPossibilityTable>,
|
||||
) -> Vec<Box<Question>> {
|
||||
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<CardPossibilityTable>) -> Vec<usize> {
|
||||
fn find_useless_cards(&self, view: &OwnedGameView, hand: &HandInfo<CardPossibilityTable>) -> Vec<usize> {
|
||||
let mut useless: HashSet<usize> = HashSet::new();
|
||||
let mut seen: HashMap<Card, usize> = HashMap::new();
|
||||
|
||||
|
@ -479,47 +480,34 @@ impl InformationPlayerStrategy {
|
|||
return useless_vec;
|
||||
}
|
||||
|
||||
fn take_public_info(&mut self, player: &Player) -> Vec<CardPossibilityTable> {
|
||||
fn take_public_info(&mut self, player: &Player) -> HandInfo<CardPossibilityTable> {
|
||||
self.public_info.remove(player).unwrap()
|
||||
}
|
||||
|
||||
fn return_public_info(&mut self, player: &Player, card_info: Vec<CardPossibilityTable>) {
|
||||
fn return_public_info(&mut self, player: &Player, card_info: HandInfo<CardPossibilityTable>) {
|
||||
self.public_info.insert(*player, card_info);
|
||||
}
|
||||
|
||||
fn get_my_public_info(&self) -> &Vec<CardPossibilityTable> {
|
||||
fn get_my_public_info(&self) -> &HandInfo<CardPossibilityTable> {
|
||||
self.get_player_public_info(&self.me)
|
||||
}
|
||||
|
||||
// fn get_my_public_info_mut(&mut self) -> &mut Vec<CardPossibilityTable> {
|
||||
// fn get_my_public_info_mut(&mut self) -> &mut HandInfo<CardPossibilityTable> {
|
||||
// let me = self.me.clone();
|
||||
// self.get_player_public_info_mut(&me)
|
||||
// }
|
||||
|
||||
fn get_player_public_info(&self, player: &Player) -> &Vec<CardPossibilityTable> {
|
||||
fn get_player_public_info(&self, player: &Player) -> &HandInfo<CardPossibilityTable> {
|
||||
self.public_info.get(player).unwrap()
|
||||
}
|
||||
|
||||
fn get_player_public_info_mut(&mut self, player: &Player) -> &mut Vec<CardPossibilityTable> {
|
||||
fn get_player_public_info_mut(&mut self, player: &Player) -> &mut HandInfo<CardPossibilityTable> {
|
||||
self.public_info.get_mut(player).unwrap()
|
||||
}
|
||||
|
||||
fn update_public_info_for_hint(&mut self, hint: &Hint, matches: &Vec<bool>) {
|
||||
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<CardPossibilityTable> {
|
||||
fn get_private_info(&self, view: &OwnedGameView) -> HandInfo<CardPossibilityTable> {
|
||||
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<CardPossibilityTable>, view: &OwnedGameView) -> usize {
|
||||
fn get_index_for_hint(&self, info: &HandInfo<CardPossibilityTable>, 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
|
||||
|
|
Loading…
Reference in a new issue