Make runs reproducible by replacing HashMaps with FnvHashMaps

This commit is contained in:
Felix Bauckholt 2019-03-07 13:54:30 +01:00
parent e04d242a71
commit ef860fa73b
7 changed files with 43 additions and 36 deletions

7
Cargo.lock generated
View file

@ -3,6 +3,11 @@ name = "crossbeam"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fnv"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "getopts"
version = "0.2.14"
@ -34,6 +39,7 @@ name = "rust_hanabi"
version = "0.1.0"
dependencies = [
"crossbeam 0.2.8 (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)",
@ -41,6 +47,7 @@ dependencies = [
[metadata]
"checksum crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "348228ce9f93d20ffc30c18e575f82fa41b9c8bf064806c65d41eba4771595a0"
"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"

View file

@ -7,4 +7,5 @@ authors = ["Jeff Wu <wuthefwasthat@gmail.com>"]
rand = "*"
log = "*"
getopts = "*"
fnv = "*"
crossbeam = "0.2.5"

View file

@ -1,4 +1,4 @@
use std::collections::HashMap;
use fnv::FnvHashMap;
use std::fmt;
use std::ops::Range;
@ -46,11 +46,11 @@ impl fmt::Debug for Card {
#[derive(Debug,Clone)]
pub struct CardCounts {
counts: HashMap<Card, u32>,
counts: FnvHashMap<Card, u32>,
}
impl CardCounts {
pub fn new() -> CardCounts {
let mut counts = HashMap::new();
let mut counts = FnvHashMap::default();
for &color in COLORS.iter() {
for &value in VALUES.iter() {
counts.insert(Card::new(color, value), 0);
@ -248,7 +248,7 @@ pub struct BoardState {
pub deck_size: u32,
pub total_cards: u32,
pub discard: Discard,
pub fireworks: HashMap<Color, Firework>,
pub fireworks: FnvHashMap<Color, Firework>,
pub num_players: u32,
@ -271,7 +271,7 @@ impl BoardState {
pub fn new(opts: &GameOptions, deck_size: u32) -> BoardState {
let fireworks = COLORS.iter().map(|&color| {
(color, Firework::new(color))
}).collect::<HashMap<_, _>>();
}).collect::<FnvHashMap<_, _>>();
BoardState {
deck_size: deck_size,
@ -479,7 +479,7 @@ pub struct BorrowedGameView<'a> {
pub player: Player,
pub hand_size: usize,
// the cards of the other players, as well as the information they have
pub other_hands: HashMap<Player, &'a Cards>,
pub other_hands: FnvHashMap<Player, &'a Cards>,
// board state
pub board: &'a BoardState,
}
@ -506,7 +506,7 @@ pub struct OwnedGameView {
pub player: Player,
pub hand_size: usize,
// the cards of the other players, as well as the information they have
pub other_hands: HashMap<Player, Cards>,
pub other_hands: FnvHashMap<Player, Cards>,
// board state
pub board: BoardState,
}
@ -515,7 +515,7 @@ impl OwnedGameView {
let other_hands = borrowed_view.other_hands.iter()
.map(|(&other_player, &player_state)| {
(other_player, player_state.clone())
}).collect::<HashMap<_, _>>();
}).collect::<FnvHashMap<_, _>>();
OwnedGameView {
player: borrowed_view.player.clone(),
@ -544,7 +544,7 @@ impl GameView for OwnedGameView {
// complete game state (known to nobody!)
#[derive(Debug)]
pub struct GameState {
pub hands: HashMap<Player, Cards>,
pub hands: FnvHashMap<Player, Cards>,
pub board: BoardState,
pub deck: Cards,
}
@ -582,7 +582,7 @@ impl GameState {
deck.pop().unwrap()
}).collect::<Vec<_>>();
(player, hand)
}).collect::<HashMap<_, _>>();
}).collect::<FnvHashMap<_, _>>();
GameState {
hands: hands,
@ -605,7 +605,7 @@ impl GameState {
// get the game state view of a particular player
pub fn get_view(&self, player: Player) -> BorrowedGameView {
let mut other_hands = HashMap::new();
let mut other_hands = FnvHashMap::default();
for (&other_player, hand) in &self.hands {
if player != other_player {
other_hands.insert(other_player, hand);

View file

@ -3,6 +3,7 @@ extern crate getopts;
extern crate log;
extern crate rand;
extern crate crossbeam;
extern crate fnv;
mod helpers;
mod game;

View file

@ -1,5 +1,5 @@
use rand::{self, Rng, SeedableRng};
use std::collections::HashMap;
use fnv::FnvHashMap;
use std::fmt;
use crossbeam;
@ -25,17 +25,15 @@ fn new_deck(seed: u32) -> Cards {
pub fn simulate_once(
opts: &GameOptions,
game_strategy: Box<GameStrategy>,
seed_opt: Option<u32>,
seed: u32,
) -> GameState {
let seed = seed_opt.unwrap_or(rand::thread_rng().next_u32());
let deck = new_deck(seed);
let mut game = GameState::new(opts, deck);
let mut strategies = game.get_players().map(|player| {
(player, game_strategy.initialize(player, &game.get_view(player)))
}).collect::<HashMap<Player, Box<PlayerStrategy>>>();
}).collect::<FnvHashMap<Player, Box<PlayerStrategy>>>();
while !game.is_over() {
let player = game.board.player;
@ -69,14 +67,14 @@ pub fn simulate_once(
#[derive(Debug)]
struct Histogram {
pub hist: HashMap<Score, u32>,
pub hist: FnvHashMap<Score, u32>,
pub sum: Score,
pub total_count: u32,
}
impl Histogram {
pub fn new() -> Histogram {
Histogram {
hist: HashMap::new(),
hist: FnvHashMap::default(),
sum: 0,
total_count: 0,
}
@ -127,7 +125,7 @@ pub fn simulate<T: ?Sized>(
progress_info: Option<u32>,
) where T: GameStrategyConfig + Sync {
let first_seed = first_seed_opt.unwrap_or(rand::thread_rng().next_u32());
let first_seed = first_seed_opt.unwrap_or_else(|| rand::thread_rng().next_u32());
let strat_config_ref = &strat_config;
crossbeam::scope(|scope| {
@ -154,7 +152,7 @@ pub fn simulate<T: ?Sized>(
);
}
}
let game = simulate_once(&opts, strat_config_ref.initialize(&opts), Some(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);

View file

@ -1,6 +1,6 @@
use std::rc::Rc;
use std::cell::{RefCell};
use std::collections::{HashMap, HashSet};
use fnv::{FnvHashMap, FnvHashSet};
use strategy::*;
use game::*;
@ -31,13 +31,13 @@ impl GameStrategyConfig for CheatingStrategyConfig {
}
pub struct CheatingStrategy {
player_hands_cheat: Rc<RefCell<HashMap<Player, Cards>>>,
player_hands_cheat: Rc<RefCell<FnvHashMap<Player, Cards>>>,
}
impl CheatingStrategy {
pub fn new() -> CheatingStrategy {
CheatingStrategy {
player_hands_cheat: Rc::new(RefCell::new(HashMap::new())),
player_hands_cheat: Rc::new(RefCell::new(FnvHashMap::default())),
}
}
}
@ -56,7 +56,7 @@ impl GameStrategy for CheatingStrategy {
}
pub struct CheatingPlayerStrategy {
player_hands_cheat: Rc<RefCell<HashMap<Player, Cards>>>,
player_hands_cheat: Rc<RefCell<FnvHashMap<Player, Cards>>>,
me: Player,
}
impl CheatingPlayerStrategy {
@ -120,7 +120,7 @@ impl CheatingPlayerStrategy {
}
fn find_useless_card(&self, view: &BorrowedGameView, hand: &Cards) -> Option<usize> {
let mut set: HashSet<Card> = HashSet::new();
let mut set: FnvHashSet<Card> = FnvHashSet::default();
for (i, card) in hand.iter().enumerate() {
if view.board.is_dead(card) {

View file

@ -1,4 +1,4 @@
use std::collections::{HashMap, HashSet};
use fnv::{FnvHashMap, FnvHashSet};
use std::cmp::Ordering;
use strategy::*;
@ -185,14 +185,14 @@ impl Question for AdditiveComboQuestion {
struct CardPossibilityPartition {
index: usize,
n_partitions: u32,
partition: HashMap<Card, u32>,
partition: FnvHashMap<Card, u32>,
}
impl CardPossibilityPartition {
fn new(
index: usize, max_n_partitions: u32, card_table: &CardPossibilityTable, view: &OwnedGameView
) -> CardPossibilityPartition {
let mut cur_block = 0;
let mut partition = HashMap::new();
let mut partition = FnvHashMap::default();
let mut n_partitions = 0;
let has_dead = card_table.probability_is_dead(&view.board) != 0.0;
@ -288,7 +288,7 @@ impl GameStrategy for InformationStrategy {
view.board.get_players().map(|player| {
let hand_info = HandInfo::new(view.board.hand_size);
(player, hand_info)
}).collect::<HashMap<_,_>>();
}).collect::<FnvHashMap<_,_>>();
Box::new(InformationPlayerStrategy {
me: player,
@ -301,7 +301,7 @@ impl GameStrategy for InformationStrategy {
pub struct InformationPlayerStrategy {
me: Player,
public_info: HashMap<Player, HandInfo<CardPossibilityTable>>,
public_info: FnvHashMap<Player, HandInfo<CardPossibilityTable>>,
public_counts: CardCounts, // what any newly drawn card should be
last_view: OwnedGameView, // the view on the previous turn
}
@ -550,8 +550,8 @@ impl InformationPlayerStrategy {
}
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();
let mut useless: FnvHashSet<usize> = FnvHashSet::default();
let mut seen: FnvHashMap<Card, usize> = FnvHashMap::default();
for (i, card_table) in hand.iter().enumerate() {
if card_table.probability_is_dead(view.get_board()) == 1.0 {
@ -792,7 +792,7 @@ impl InformationPlayerStrategy {
(0 .. n - 1).into_iter().map(|i| { (player + 1 + i) % n }).collect()
}
fn get_best_hint_of_options(&self, hint_player: Player, hint_option_set: HashSet<Hinted>) -> Hinted {
fn get_best_hint_of_options(&self, hint_player: Player, hint_option_set: FnvHashSet<Hinted>) -> Hinted {
let view = &self.last_view;
// using hint goodness barely helps
@ -864,7 +864,7 @@ impl InformationPlayerStrategy {
2 => {
// NOTE: this doesn't do that much better than just hinting
// the first thing that doesn't match the hint_card
let mut hint_option_set = HashSet::new();
let mut hint_option_set = FnvHashSet::default();
for card in hand {
if card.color != hint_card.color {
hint_option_set.insert(Hinted::Color(card.color));
@ -889,7 +889,7 @@ impl InformationPlayerStrategy {
}
2 => {
// Any value hint for a card other than the first
let mut hint_option_set = HashSet::new();
let mut hint_option_set = FnvHashSet::default();
for card in hand {
if card.value != hint_card.value {
hint_option_set.insert(Hinted::Value(card.value));
@ -899,7 +899,7 @@ impl InformationPlayerStrategy {
}
3 => {
// Any color hint for a card other than the first
let mut hint_option_set = HashSet::new();
let mut hint_option_set = FnvHashSet::default();
for card in hand {
if card.color != hint_card.color {
hint_option_set.insert(Hinted::Color(card.color));