diff --git a/Cargo.lock b/Cargo.lock index e063b68..7f6b6db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,61 +1,72 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + [[package]] name = "crossbeam" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348228ce9f93d20ffc30c18e575f82fa41b9c8bf064806c65d41eba4771595a0" [[package]] name = "float-ord" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e" [[package]] name = "fnv" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" [[package]] name = "getopts" -version = "0.2.14" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] [[package]] name = "libc" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4870ef6725dde13394134e587e4ab4eca13cb92e916209a31c851b49131d3c75" [[package]] name = "log" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038b5d13189a14e5b6ac384fdb7c691a45ef0885f6d2dddbf422e6c3506b8234" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "rand" version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "rust_hanabi" version = "0.1.0" dependencies = [ - "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam", + "float-ord", + "fnv", + "getopts", + "log", + "rand", ] -[metadata] -"checksum crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "348228ce9f93d20ffc30c18e575f82fa41b9c8bf064806c65d41eba4771595a0" -"checksum float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e" -"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" -"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" -"checksum libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4870ef6725dde13394134e587e4ab4eca13cb92e916209a31c851b49131d3c75" -"checksum log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "038b5d13189a14e5b6ac384fdb7c691a45ef0885f6d2dddbf422e6c3506b8234" -"checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5" +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" diff --git a/src/game.rs b/src/game.rs index e973a3c..1b21f11 100644 --- a/src/game.rs +++ b/src/game.rs @@ -19,7 +19,7 @@ pub fn get_count_for_value(value: Value) -> u32 { 1 => 3, 2 | 3 | 4 => 2, 5 => 1, - _ => { panic!(format!("Unexpected value: {}", value)); } + _ => { panic!("Unexpected value: {}", value); } } } @@ -30,7 +30,7 @@ pub struct Card { } impl Card { pub fn new(color: Color, value: Value) -> Card { - Card { color: color, value: value } + Card { color, value } } } impl fmt::Display for Card { @@ -57,7 +57,7 @@ impl CardCounts { } } CardCounts { - counts: counts, + counts, } } @@ -78,20 +78,20 @@ impl CardCounts { impl fmt::Display for CardCounts { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for &color in COLORS.iter() { - try!(f.write_str(&format!( + 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!( + f.write_str(&format!( "{}/{} {}s", count, total, value - ))); + ))?; if value != FINAL_VALUE { - try!(f.write_str(", ")); + f.write_str(", ")?; } } - try!(f.write_str("\n")); + f.write_str("\n")?; } Ok(()) } @@ -127,9 +127,9 @@ impl Discard { } impl fmt::Display for Discard { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // try!(f.write_str(&format!( + // f.write_str(&format!( // "{}", self.cards, - // ))); + // ))?; write!(f, "{}", self.counts) } } @@ -145,7 +145,7 @@ pub struct Firework { impl Firework { pub fn new(color: Color) -> Firework { Firework { - color: color, + color, top: 0, } } @@ -192,8 +192,8 @@ pub enum Hinted { impl fmt::Display for Hinted { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &Hinted::Color(color) => { write!(f, "{}", color) } - &Hinted::Value(value) => { write!(f, "{}", value) } + Hinted::Color(color) => { write!(f, "{}", color) } + Hinted::Value(value) => { write!(f, "{}", value) } } } } @@ -274,9 +274,9 @@ impl BoardState { }).collect::>(); BoardState { - deck_size: deck_size, + deck_size, total_cards: deck_size, - fireworks: fireworks, + fireworks, discard: Discard::new(), num_players: opts.num_players, hand_size: opts.hand_size, @@ -332,7 +332,7 @@ impl BoardState { return value - 1; } } - return FINAL_VALUE; + FINAL_VALUE } // is never going to play, based on discard + fireworks @@ -357,24 +357,20 @@ impl BoardState { true } else { let needed = firework.needed_value().unwrap(); - if card.value < needed { + if card.value < needed || card.value > self.highest_attainable(card.color) { true } else { - if card.value > self.highest_attainable(card.color) { - true - } else { - self.discard.remaining(&card) != 1 - } + self.discard.remaining(card) != 1 } } } pub fn get_players(&self) -> Range { - (0..self.num_players) + 0..self.num_players } pub fn score(&self) -> Score { - self.fireworks.iter().map(|(_, firework)| firework.score()).fold(0, |a, b| a + b) + self.fireworks.iter().map(|(_, firework)| firework.score()).sum() } pub fn discard_size(&self) -> u32 { @@ -395,35 +391,35 @@ impl BoardState { impl fmt::Display for BoardState { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.is_over() { - try!(f.write_str(&format!( + f.write_str(&format!( "Turn {} (GAME ENDED):\n", self.turn - ))); + ))?; } else { - try!(f.write_str(&format!( + f.write_str(&format!( "Turn {} (Player {}'s turn):\n", self.turn, self.player - ))); + ))?; } - try!(f.write_str(&format!( + f.write_str(&format!( "{} cards remaining in deck\n", self.deck_size - ))); + ))?; if self.deck_size == 0 { - try!(f.write_str(&format!( + f.write_str(&format!( "Deck is empty. {} turns remaining in game\n", self.deckless_turns_remaining - ))); + ))?; } - try!(f.write_str(&format!( + f.write_str(&format!( "{}/{} hints remaining\n", self.hints_remaining, self.hints_total - ))); - try!(f.write_str(&format!( + ))?; + f.write_str(&format!( "{}/{} lives remaining\n", self.lives_remaining, self.lives_total - ))); - try!(f.write_str("Fireworks:\n")); + ))?; + f.write_str("Fireworks:\n")?; for &color in COLORS.iter() { - try!(f.write_str(&format!(" {}\n", self.get_firework(color)))); + f.write_str(&format!(" {}\n", self.get_firework(color)))?; } - try!(f.write_str("Discard:\n")); - try!(f.write_str(&format!("{}\n", self.discard))); + f.write_str("Discard:\n")?; + f.write_str(&format!("{}\n", self.discard))?; Ok(()) } @@ -432,7 +428,7 @@ impl fmt::Display for BoardState { // complete game view of a given player pub trait GameView { fn me(&self) -> Player; - fn get_hand(&self, &Player) -> &Cards; + fn get_hand(&self, player: &Player) -> &Cards; fn get_board(&self) -> &BoardState; fn my_hand_size(&self) -> usize; @@ -459,13 +455,13 @@ pub trait GameView { fn can_see(&self, card: &Card) -> bool { self.get_other_players().iter().any(|player| { - self.has_card(&player, card) + self.has_card(player, card) }) } fn someone_else_can_play(&self) -> bool { self.get_other_players().iter().any(|player| { - self.get_hand(&player).iter().any(|card| { + self.get_hand(player).iter().any(|card| { self.get_board().is_playable(card) }) }) @@ -518,9 +514,9 @@ impl OwnedGameView { }).collect::>(); OwnedGameView { - player: borrowed_view.player.clone(), + player: borrowed_view.player, hand_size: borrowed_view.hand_size, - other_hands: other_hands, + other_hands, board: (*borrowed_view.board).clone(), } } @@ -550,22 +546,22 @@ pub struct GameState { } impl fmt::Display for GameState { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(f.write_str("\n")); - try!(f.write_str("======\n")); - try!(f.write_str("Hands:\n")); - try!(f.write_str("======\n")); + f.write_str("\n")?; + f.write_str("======\n")?; + f.write_str("Hands:\n")?; + f.write_str("======\n")?; for player in self.board.get_players() { let hand = &self.hands.get(&player).unwrap(); - try!(f.write_str(&format!("player {}:", player))); + f.write_str(&format!("player {}:", player))?; for card in hand.iter() { - try!(f.write_str(&format!(" {}", card))); + f.write_str(&format!(" {}", card))?; } - try!(f.write_str(&"\n")); + f.write_str("\n")?; } - try!(f.write_str("======\n")); - try!(f.write_str("Board:\n")); - try!(f.write_str("======\n")); - try!(f.write_str(&format!("{}", self.board))); + f.write_str("======\n")?; + f.write_str("Board:\n")?; + f.write_str("======\n")?; + f.write_str(&format!("{}", self.board))?; Ok(()) } } @@ -585,9 +581,9 @@ impl GameState { }).collect::>(); GameState { - hands: hands, - board: board, - deck: deck, + hands, + board, + deck, } } @@ -612,9 +608,9 @@ impl GameState { } } BorrowedGameView { - player: player, + player, hand_size: self.hands.get(&player).unwrap().len(), - other_hands: other_hands, + other_hands, board: &self.board, } } @@ -646,7 +642,7 @@ impl GameState { debug!("Hint to player {}, about {}", hint.player, hint.hinted); assert!(self.board.player != hint.player, - format!("Player {} gave a hint to himself", hint.player)); + "Player {} gave a hint to himself", hint.player); let hand = self.hands.get(&hint.player).unwrap(); let results = match hint.hinted { @@ -703,9 +699,9 @@ impl GameState { } }; let turn_record = TurnRecord { - player: self.board.player.clone(), + player: self.board.player, result: turn_result, - choice: choice, + choice, }; self.board.turn_history.push(turn_record.clone()); diff --git a/src/helpers.rs b/src/helpers.rs index 43aa3b7..1306e78 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -33,7 +33,7 @@ pub trait CardInfo { // get probability weight for the card #[allow(unused_variables)] fn get_weight(&self, card: &Card) -> f32 { - 1 as f32 + 1. } fn get_weighted_possibilities(&self) -> Vec<(Card, f32)> { @@ -46,11 +46,11 @@ pub trait CardInfo { fn total_weight(&self) -> f32 { self.get_possibilities().iter() - .map(|card| self.get_weight(&card)) + .map(|card| self.get_weight(card)) .fold(0.0, |a, b| a+b) } - fn weighted_score(&self, score_fn: &Fn(&Card) -> T) -> f32 + fn weighted_score(&self, score_fn: &dyn Fn(&Card) -> T) -> f32 where f32: From { let mut total_score = 0.; @@ -68,7 +68,7 @@ pub trait CardInfo { self.weighted_score(&|card| card.value as f32 ) } - fn probability_of_predicate(&self, predicate: &Fn(&Card) -> bool) -> f32 { + fn probability_of_predicate(&self, predicate: &dyn Fn(&Card) -> bool) -> f32 { let f = |card: &Card| { if predicate(card) { 1.0 } else { 0.0 } }; @@ -126,7 +126,7 @@ pub trait CardInfo { // Represents hinted information about possible values of type T -pub trait Info where T: Hash + Eq + Clone + Copy { +pub trait Info where T: Hash + Eq + Clone { // get all a-priori possibilities fn get_all_possibilities() -> Vec; @@ -137,7 +137,7 @@ pub trait Info where T: Hash + Eq + Clone + Copy { // get what is now possible fn get_possibilities(&self) -> Vec { - self.get_possibility_set().iter().map(|t| t.clone()).collect::>() + self.get_possibility_set().iter().cloned().collect::>() } fn is_possible(&self, value: T) -> bool { @@ -146,13 +146,13 @@ pub trait Info where T: Hash + Eq + Clone + Copy { fn initialize() -> HashSet { Self::get_all_possibilities().iter() - .map(|val| val.clone()).collect::>() + .cloned().collect::>() } fn mark_true(&mut self, value: T) { let possible = self.get_mut_possibility_set(); possible.clear(); - possible.insert(value.clone()); + possible.insert(value); } fn mark_false(&mut self, value: T) { @@ -328,7 +328,7 @@ impl <'a> From<&'a CardCounts> for CardPossibilityTable { } } CardPossibilityTable { - possible: possible, + possible, } } } @@ -341,7 +341,7 @@ impl CardInfo for CardPossibilityTable { self.possible.contains_key(card) } fn get_possibilities(&self) -> Vec { - let mut cards = self.possible.keys().map(|card| {card.clone() }).collect::>(); + let mut cards = self.possible.keys().cloned().collect::>(); cards.sort(); cards } @@ -363,7 +363,7 @@ impl CardInfo for CardPossibilityTable { impl fmt::Display for CardPossibilityTable { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for (card, weight) in &self.possible { - try!(f.write_str(&format!("{} {}, ", weight, card))); + f.write_str(&format!("{} {}, ", weight, card))?; } Ok(()) } @@ -377,21 +377,21 @@ 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, + hand_info, } } // update for hint to me - pub fn update_for_hint(&mut self, hinted: &Hinted, matches: &Vec) { + pub fn update_for_hint(&mut self, hinted: &Hinted, matches: &[bool]) { match hinted { - &Hinted::Color(color) => { + Hinted::Color(color) => { for (card_info, &matched) in self.hand_info.iter_mut().zip(matches.iter()) { - card_info.mark_color(color, matched); + card_info.mark_color(*color, matched); } } - &Hinted::Value(value) => { + Hinted::Value(value) => { for (card_info, &matched) in self.hand_info.iter_mut().zip(matches.iter()) { - card_info.mark_value(value, matched); + card_info.mark_value(*value, matched); } } } diff --git a/src/main.rs b/src/main.rs index 1568470..aa74cdb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -75,7 +75,7 @@ fn main() { Ok(m) => { m } Err(f) => { print_usage(&program, opts); - panic!(f.to_string()) + panic!("{}", f) } }; if matches.opt_present("h") { @@ -131,27 +131,27 @@ fn sim_games(n_players: u32, strategy_str: &str, seed: Option, n_trials: u3 let game_opts = game::GameOptions { num_players: n_players, - hand_size: hand_size, + hand_size, num_hints: 8, num_lives: 3, // hanabi rules are a bit ambiguous about whether you can give hints that match 0 cards allow_empty_hints: false, }; - let strategy_config : Box = match strategy_str { + let strategy_config : Box = match strategy_str { "random" => { Box::new(strategies::examples::RandomStrategyConfig { hint_probability: 0.4, play_probability: 0.2, - }) as Box + }) as Box }, "cheat" => { Box::new(strategies::cheating::CheatingStrategyConfig::new()) - as Box + as Box }, "info" => { Box::new(strategies::information::InformationStrategyConfig::new()) - as Box + as Box }, _ => { panic!("Unexpected strategy argument {}", strategy_str); @@ -176,7 +176,7 @@ fn get_results_table() -> String { let dashes = String::from("---------"); let dashes_long = String::from("------------------"); type TwoLines = (String, String); - fn make_twolines(player_nums: &Vec, head: TwoLines, make_block: &dyn Fn(u32) -> TwoLines) -> TwoLines { + fn make_twolines(player_nums: &[u32], head: TwoLines, make_block: &dyn Fn(u32) -> TwoLines) -> TwoLines { let mut blocks = player_nums.iter().cloned().map(make_block).collect::>(); blocks.insert(0, head); fn combine(items: Vec) -> String { @@ -189,7 +189,7 @@ fn get_results_table() -> String { body.into_iter().fold(String::default(), |output, (a, b)| (output + &a + "\n" + &b + "\n")) } let header = make_twolines(&player_nums, - (space.clone(), dashes.clone()), + (space.clone(), dashes), &|n_players| (format_players(n_players), dashes_long.clone())); let mut body = strategies.iter().map(|strategy| { make_twolines(&player_nums, (format_name(strategy), space.clone()), &|n_players| { diff --git a/src/simulator.rs b/src/simulator.rs index cf96183..0c51065 100644 --- a/src/simulator.rs +++ b/src/simulator.rs @@ -24,7 +24,7 @@ fn new_deck(seed: u32) -> Cards { pub fn simulate_once( opts: &GameOptions, - game_strategy: Box, + game_strategy: Box, seed: u32, ) -> GameState { let deck = new_deck(seed); @@ -33,7 +33,7 @@ pub fn simulate_once( let mut strategies = game.get_players().map(|player| { (player, game_strategy.initialize(player, &game.get_view(player))) - }).collect::>>(); + }).collect::>>(); while !game.is_over() { let player = game.board.player; @@ -46,14 +46,14 @@ pub fn simulate_once( let choice = { - let mut strategy = strategies.get_mut(&player).unwrap(); + let strategy = strategies.get_mut(&player).unwrap(); strategy.decide(&game.get_view(player)) }; let turn = game.process_choice(choice); for player in game.get_players() { - let mut strategy = strategies.get_mut(&player).unwrap(); + let strategy = strategies.get_mut(&player).unwrap(); strategy.update(&turn, &game.get_view(player)); } @@ -89,7 +89,7 @@ impl Histogram { self.insert_many(val, 1); } pub fn get_count(&self, val: &Score) -> u32 { - *self.hist.get(&val).unwrap_or(&0) + *self.hist.get(val).unwrap_or(&0) } pub fn percentage_with(&self, val: &Score) -> f32 { self.get_count(val) as f32 / self.total_count as f32 @@ -119,9 +119,9 @@ impl fmt::Display for Histogram { let mut keys = self.hist.keys().collect::>(); keys.sort(); for val in keys { - try!(f.write_str(&format!( + f.write_str(&format!( "\n{}: {}", val, self.get_count(val), - ))); + ))?; } Ok(()) } @@ -164,7 +164,7 @@ pub fn simulate( ); } } - let game = simulate_once(&opts, strat_config_ref.initialize(&opts), seed); + let game = simulate_once(opts, strat_config_ref.initialize(opts), seed); let score = game.score(); lives_histogram.insert(game.board.lives_remaining); score_histogram.insert(score); diff --git a/src/strategies/cheating.rs b/src/strategies/cheating.rs index c71bfd5..9ca8c8b 100644 --- a/src/strategies/cheating.rs +++ b/src/strategies/cheating.rs @@ -25,7 +25,7 @@ impl CheatingStrategyConfig { } } impl GameStrategyConfig for CheatingStrategyConfig { - fn initialize(&self, _: &GameOptions) -> Box { + fn initialize(&self, _: &GameOptions) -> Box { Box::new(CheatingStrategy::new()) } } @@ -42,7 +42,7 @@ impl CheatingStrategy { } } impl GameStrategy for CheatingStrategy { - fn initialize(&self, player: Player, view: &BorrowedGameView) -> Box { + fn initialize(&self, player: Player, view: &BorrowedGameView) -> Box { for (&player, &hand) in &view.other_hands { self.player_hands_cheat.borrow_mut().insert( player, hand.clone() @@ -93,7 +93,7 @@ impl CheatingPlayerStrategy { // given a hand of cards, represents how badly it will need to play things fn hand_play_value(&self, view: &BorrowedGameView, hand: &Cards) -> u32 { - hand.iter().map(|card| self.card_play_value(view, card)).fold(0, |a,b| a+b) + hand.iter().map(|card| self.card_play_value(view, card)).sum() } // how badly do we need to play a particular card @@ -104,13 +104,11 @@ impl CheatingPlayerStrategy { 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, 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) - } + if player != self.me && view.has_card(&player, card) { + 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) } } } @@ -132,7 +130,7 @@ impl CheatingPlayerStrategy { } set.insert(card.clone()); } - return None + None } } impl PlayerStrategy for CheatingPlayerStrategy { @@ -145,7 +143,7 @@ impl PlayerStrategy for CheatingPlayerStrategy { view.board.is_playable(card) }).collect::>(); - if playable_cards.len() > 0 { + if !playable_cards.is_empty() { // play the best playable card // the higher the play_score, the better to play let mut index = 0; @@ -178,10 +176,8 @@ impl PlayerStrategy for CheatingPlayerStrategy { // hinting is better than discarding dead cards // (probably because it stalls the deck-drawing). - if view.board.hints_remaining > 0 { - if view.someone_else_can_play() { - return self.throwaway_hint(view); - } + if view.board.hints_remaining > 0 && view.someone_else_can_play() { + return self.throwaway_hint(view); } // if anything is totally useless, discard it diff --git a/src/strategies/examples.rs b/src/strategies/examples.rs index 60c7aad..a524b75 100644 --- a/src/strategies/examples.rs +++ b/src/strategies/examples.rs @@ -10,7 +10,7 @@ pub struct RandomStrategyConfig { } impl GameStrategyConfig for RandomStrategyConfig { - fn initialize(&self, _: &GameOptions) -> Box { + fn initialize(&self, _: &GameOptions) -> Box { Box::new(RandomStrategy { hint_probability: self.hint_probability, play_probability: self.play_probability, @@ -23,7 +23,7 @@ pub struct RandomStrategy { play_probability: f64, } impl GameStrategy for RandomStrategy { - fn initialize(&self, player: Player, _: &BorrowedGameView) -> Box { + fn initialize(&self, player: Player, _: &BorrowedGameView) -> Box { Box::new(RandomStrategyPlayer { hint_probability: self.hint_probability, play_probability: self.play_probability, @@ -44,7 +44,7 @@ impl PlayerStrategy for RandomStrategyPlayer { if p < self.hint_probability { if view.board.hints_remaining > 0 { let hint_player = view.board.player_to_left(&self.me); - let hint_card = rand::thread_rng().choose(&view.get_hand(&hint_player)).unwrap(); + let hint_card = rand::thread_rng().choose(view.get_hand(&hint_player)).unwrap(); let hinted = { if rand::random() { // hint a color @@ -55,7 +55,7 @@ impl PlayerStrategy for RandomStrategyPlayer { }; TurnChoice::Hint(Hint { player: hint_player, - hinted: hinted, + hinted, }) } else { TurnChoice::Discard(0) diff --git a/src/strategies/hat_helpers.rs b/src/strategies/hat_helpers.rs index 7550a5b..4f2c921 100644 --- a/src/strategies/hat_helpers.rs +++ b/src/strategies/hat_helpers.rs @@ -10,8 +10,8 @@ impl ModulusInformation { pub fn new(modulus: u32, value: u32) -> Self { assert!(value < modulus); ModulusInformation { - modulus: modulus, - value: value, + modulus, + value, } } @@ -21,7 +21,7 @@ impl ModulusInformation { pub fn combine(&mut self, other: Self, max_modulus: u32) { assert!(other.modulus <= self.info_remaining(max_modulus)); - self.value = self.value + self.modulus * other.value; + self.value += self.modulus * other.value; self.modulus = std::cmp::min(max_modulus, self.modulus * other.modulus); assert!(self.value < self.modulus); } @@ -45,7 +45,7 @@ impl ModulusInformation { let original_modulus = self.modulus; let original_value = self.value; let value = self.value % modulus; - self.value = self.value / modulus; + self.value /= modulus; // `self.modulus` is the largest number such that // `value + (self.modulus - 1) * modulus < original_modulus`. // TODO: find an explanation of why this makes everything work out @@ -80,10 +80,10 @@ pub trait Question { // how much info does this question ask for? fn info_amount(&self) -> u32; // get the answer to this question, given cards - fn answer(&self, &Cards, &BoardState) -> u32; + fn answer(&self, hand: &Cards, board: &BoardState) -> u32; // process the answer to this question, updating card info fn acknowledge_answer( - &self, value: u32, &mut HandInfo, &BoardState + &self, value: u32, hand_info: &mut HandInfo, board: &BoardState ); fn answer_info(&self, hand: &Cards, board: &BoardState) -> ModulusInformation { @@ -105,11 +105,11 @@ pub trait Question { } pub trait PublicInformation: Clone { - fn get_player_info(&self, &Player) -> HandInfo; - fn set_player_info(&mut self, &Player, HandInfo); + fn get_player_info(&self, player: &Player) -> HandInfo; + fn set_player_info(&mut self, player: &Player, hand_info: HandInfo); - fn new(&BoardState) -> Self; - fn set_board(&mut self, &BoardState); + fn new(board: &BoardState) -> Self; + fn set_board(&mut self, board: &BoardState); /// If we store more state than just `HandInfo`s, update it after `set_player_info` has been called. fn update_other_info(&mut self) { @@ -126,10 +126,10 @@ pub trait PublicInformation: Clone { /// /// Note that `self` does not reflect the answers to previous questions; it reflects the state /// before the entire "hat value" calculation. - fn ask_question(&self, &Player, &HandInfo, total_info: u32) -> Option>; + fn ask_question(&self, player: &Player, hand_info: &HandInfo, total_info: u32) -> Option>; fn ask_question_wrapper(&self, player: &Player, hand_info: &HandInfo, total_info: u32) - -> Option> + -> Option> { assert!(total_info > 0); if total_info == 1 { @@ -191,7 +191,7 @@ pub trait PublicInformation: Clone { let (infos, new_player_hands): (Vec<_>, Vec<_>) = view.get_other_players().iter().map(|player| { let mut hand_info = self.get_player_info(player); let info = self.get_hat_info_for_player(player, &mut hand_info, total_info, view); - (info, (player.clone(), hand_info)) + (info, (*player, hand_info)) }).unzip(); self.set_player_infos(new_player_hands); infos.into_iter().fold( @@ -213,7 +213,7 @@ pub trait PublicInformation: Clone { }).map(|player| { let mut hand_info = self.get_player_info(&player); let player_info = self.get_hat_info_for_player(&player, &mut hand_info, info.modulus, view); - (player_info, (player.clone(), hand_info)) + (player_info, (player, hand_info)) }).unzip(); for other_info in other_infos { info.subtract(&other_info); diff --git a/src/strategies/information.rs b/src/strategies/information.rs index e28951d..53b47bf 100644 --- a/src/strategies/information.rs +++ b/src/strategies/information.rs @@ -58,7 +58,7 @@ fn q_is_dead(index: usize) -> CardHasProperty { /// It's named that way because the `info_amount` grows additively with the `info_amount`s of /// the questions in `l`. struct AdditiveComboQuestion { - questions: Vec>, + questions: Vec>, } impl Question for AdditiveComboQuestion { fn info_amount(&self) -> u32 { @@ -113,7 +113,7 @@ impl CardPossibilityPartition { let mut partition = FnvHashMap::default(); let mut n_partitions = 0; - let has_dead = card_table.probability_is_dead(&board) != 0.0; + let has_dead = card_table.probability_is_dead(board) != 0.0; // TODO: group things of different colors and values? let mut effective_max = max_n_partitions; @@ -152,9 +152,9 @@ impl CardPossibilityPartition { // debug!("{}", s); CardPossibilityPartition { - index: index, - n_partitions: n_partitions, - partition: partition, + index, + n_partitions, + partition, } } } @@ -162,7 +162,7 @@ impl Question for CardPossibilityPartition { fn info_amount(&self) -> u32 { self.n_partitions } fn answer(&self, hand: &Cards, _: &BoardState) -> u32 { let ref card = hand[self.index]; - *self.partition.get(&card).unwrap() + *self.partition.get(card).unwrap() } fn acknowledge_answer( &self, @@ -220,7 +220,7 @@ impl MyPublicInformation { }) }); - return if !may_be_all_one_color && !may_be_all_one_number { 4 } else { 3 } + if !may_be_all_one_color && !may_be_all_one_number { 4 } else { 3 } } fn get_hint_index_score(&self, card_table: &CardPossibilityTable) -> i32 { @@ -238,7 +238,7 @@ impl MyPublicInformation { if !card_table.value_determined() { score += 1; } - return score; + score } fn get_index_for_hint(&self, player: &Player) -> usize { @@ -355,12 +355,12 @@ impl MyPublicInformation { hint_option_set.into_iter().collect::>().into_iter().map(|hinted| { Hint { player: hint_player, - hinted: hinted, + hinted, } }).collect() } - fn decode_hint_choice(&self, hint: &Hint, result: &Vec) -> ModulusInformation { + fn decode_hint_choice(&self, hint: &Hint, result: &[bool]) -> ModulusInformation { let hinter = self.board.player; let info_per_player: Vec<_> = self.get_other_players_starting_after(hinter).into_iter().map( @@ -372,7 +372,7 @@ impl MyPublicInformation { let player_amt = (n + hint.player - hinter - 1) % n; - let amt_from_prev_players = info_per_player.iter().take(player_amt as usize).fold(0, |a, b| a + b); + let amt_from_prev_players = info_per_player.iter().take(player_amt as usize).sum::(); let hint_info_we_can_give_to_this_player = info_per_player[player_amt as usize]; let card_index = self.get_index_for_hint(&hint.player); @@ -405,12 +405,12 @@ impl MyPublicInformation { ModulusInformation::new(total_info, hint_value) } - fn update_from_hint_choice(&mut self, hint: &Hint, matches: &Vec, view: &OwnedGameView) { + fn update_from_hint_choice(&mut self, hint: &Hint, matches: &[bool], view: &OwnedGameView) { let info = self.decode_hint_choice(hint, matches); self.update_from_hat_sum(info, view); } - fn update_from_hint_matches(&mut self, hint: &Hint, matches: &Vec) { + fn update_from_hint_matches(&mut self, hint: &Hint, matches: &[bool]) { let info = self.get_player_info_mut(&hint.player); info.update_for_hint(&hint.hinted, matches); } @@ -424,10 +424,10 @@ impl MyPublicInformation { fn someone_else_needs_hint(&self, view: &OwnedGameView) -> bool { // Does another player have a playable card, but doesn't know it? view.get_other_players().iter().any(|player| { - let has_playable_card = view.get_hand(&player).iter().any(|card| { + let has_playable_card = view.get_hand(player).iter().any(|card| { view.get_board().is_playable(card) }); - has_playable_card && !self.knows_playable_card(&player) + has_playable_card && !self.knows_playable_card(player) }) } @@ -466,7 +466,7 @@ impl MyPublicInformation { info.remove(index); // push *before* incrementing public counts - if info.len() < new_view.hand_size(&player) { + if info.len() < new_view.hand_size(player) { info.push(new_card_table); } } @@ -491,7 +491,7 @@ impl PublicInformation for MyPublicInformation { (player, hand_info) }).collect::>(); MyPublicInformation { - hand_info: hand_info, + hand_info, card_counts: CardCounts::new(), board: board.clone(), } @@ -518,7 +518,7 @@ impl PublicInformation for MyPublicInformation { _me: &Player, hand_info: &HandInfo, total_info: u32, - ) -> Option> { + ) -> Option> { // Changing anything inside this function will not break the information transfer // mechanisms! @@ -532,8 +532,7 @@ impl PublicInformation for MyPublicInformation { // We don't need to find out anything about cards that are determined or dead. let augmented_hand_info = augmented_hand_info_raw.into_iter().filter(|&(i, _, p_dead)| { - if p_dead == 1.0 { false } - else if hand_info[i].is_determined() { false } + if p_dead == 1.0 || hand_info[i].is_determined() { false } else { true } }).collect::>(); @@ -565,11 +564,11 @@ impl PublicInformation for MyPublicInformation { // only matters if we find a playable/dead card, and conditional on that, it's better // to find out about as many non-playable/non-dead cards as possible. to_ask.sort_by_key(|&(ask_dead, _, p_yes)| {(ask_dead, FloatOrd(p_yes))}); - let questions = to_ask.into_iter().map(|(ask_dead, i, _)| -> Box { + let questions = to_ask.into_iter().map(|(ask_dead, i, _)| -> Box { if ask_dead { Box::new(q_is_dead(i)) } else { Box::new(q_is_playable(i)) } }).collect::>(); - if questions.len() > 0 { + if !questions.is_empty() { return Some(Box::new(AdditiveComboQuestion { questions })) } } @@ -607,7 +606,7 @@ impl InformationStrategyConfig { } } impl GameStrategyConfig for InformationStrategyConfig { - fn initialize(&self, _: &GameOptions) -> Box { + fn initialize(&self, _: &GameOptions) -> Box { Box::new(InformationStrategy::new()) } } @@ -620,7 +619,7 @@ impl InformationStrategy { } } impl GameStrategy for InformationStrategy { - fn initialize(&self, player: Player, view: &BorrowedGameView) -> Box { + fn initialize(&self, player: Player, view: &BorrowedGameView) -> Box { Box::new(InformationPlayerStrategy { me: player, public_info: MyPublicInformation::new(view.board), @@ -650,10 +649,8 @@ impl InformationPlayerStrategy { let mut num_with = 1; if view.board.deck_size > 0 { for player in view.board.get_players() { - if player != self.me { - if view.has_card(&player, card) { - num_with += 1; - } + if player != self.me && view.has_card(&player, card) { + num_with += 1; } } } @@ -667,21 +664,19 @@ impl InformationPlayerStrategy { for (i, card_table) in hand.iter().enumerate() { if card_table.probability_is_dead(board) == 1.0 { useless.insert(i); - } else { - if let Some(card) = card_table.get_card() { - if seen.contains_key(&card) { - // found a duplicate card - useless.insert(i); - useless.insert(*seen.get(&card).unwrap()); - } else { - seen.insert(card, i); - } + } else if let Some(card) = card_table.get_card() { + if seen.contains_key(&card) { + // found a duplicate card + useless.insert(i); + useless.insert(*seen.get(&card).unwrap()); + } else { + seen.insert(card, i); } } } let mut useless_vec : Vec = useless.into_iter().collect(); useless_vec.sort(); - return useless_vec; + useless_vec } // how good is it to give this hint to this player? @@ -692,8 +687,8 @@ impl InformationPlayerStrategy { let hint_player = &hint.player; let hinted = &hint.hinted; - let hand = view.get_hand(&hint_player); - let mut hand_info = self.public_info.get_player_info(&hint_player); + let hand = view.get_hand(hint_player); + let mut hand_info = self.public_info.get_player_info(hint_player); let mut goodness = 1.0; for (i, card_table) in hand_info.iter_mut().enumerate() { @@ -716,9 +711,7 @@ impl InformationPlayerStrategy { let new_weight = card_table.total_weight(); assert!(new_weight <= old_weight); let bonus = { - if card_table.is_determined() { - 2 - } else if card_table.probability_is_dead(&view.board) == 1.0 { + if card_table.is_determined() || card_table.probability_is_dead(&view.board) == 1.0 { 2 } else { 1 @@ -744,12 +737,10 @@ impl InformationPlayerStrategy { h2.0.partial_cmp(&h1.0).unwrap_or(Ordering::Equal) }); - if hint_options.len() == 0 { + if hint_options.is_empty() { // NOTE: Technically possible, but never happens - } else { - if hint_options.len() > 1 { - debug!("Choosing amongst hint options: {:?}", hint_options); - } + } else if hint_options.len() > 1 { + debug!("Choosing amongst hint options: {:?}", hint_options); } hint_options.remove(0).1 } @@ -809,7 +800,7 @@ impl InformationPlayerStrategy { (i, card_table, p) }).collect::>(); - if risky_playable_cards.len() > 0 { + if !risky_playable_cards.is_empty() { risky_playable_cards.sort_by(|c1, c2| { c2.2.partial_cmp(&c1.2).unwrap_or(Ordering::Equal) }); @@ -827,7 +818,7 @@ impl InformationPlayerStrategy { // NOTE When changing this, make sure to keep the "discard" branch of update() up to date! let will_hint = if view.board.hints_remaining > 0 && public_info.someone_else_needs_hint(view) { true } - else if view.board.discard_size() <= discard_threshold && useless_indices.len() > 0 { false } + else if view.board.discard_size() <= discard_threshold && !useless_indices.is_empty() { false } // hinting is better than discarding dead cards // (probably because it stalls the deck-drawing). else if view.board.hints_remaining > 0 && view.someone_else_can_play() { true } @@ -849,7 +840,7 @@ impl InformationPlayerStrategy { if public_useless_indices.len() > 1 { let info = public_info.get_hat_sum(public_useless_indices.len() as u32, view); return TurnChoice::Discard(public_useless_indices[info.value as usize]); - } else if useless_indices.len() > 0 { + } else if !useless_indices.is_empty() { // TODO: have opponents infer that i knew a card was useless // TODO: after that, potentially prefer useless indices that arent public return TurnChoice::Discard(useless_indices[0]); diff --git a/src/strategy.rs b/src/strategy.rs index 8ef667f..c3823ee 100644 --- a/src/strategy.rs +++ b/src/strategy.rs @@ -6,21 +6,21 @@ use game::*; pub trait PlayerStrategy { // A function to decide what to do on the player's turn. // Given a BorrowedGameView, outputs their choice. - fn decide(&mut self, &BorrowedGameView) -> TurnChoice; + fn decide(&mut self, view: &BorrowedGameView) -> TurnChoice; // A function to update internal state after other players' turns. // Given what happened last turn, and the new state. - fn update(&mut self, &TurnRecord, &BorrowedGameView); + fn update(&mut self, turn_record: &TurnRecord, view: &BorrowedGameView); } // Represents the overall strategy for a game // Shouldn't do much, except store configuration parameters and // possibility initialize some shared randomness between players pub trait GameStrategy { - fn initialize(&self, Player, &BorrowedGameView) -> Box; + fn initialize(&self, player: Player, view: &BorrowedGameView) -> Box; } // Represents configuration for a strategy. // Acts as a factory for game strategies, so we can play many rounds pub trait GameStrategyConfig { - fn initialize(&self, &GameOptions) -> Box; + fn initialize(&self, opts: &GameOptions) -> Box; }