2016-03-14 02:11:20 +01:00
|
|
|
extern crate getopts;
|
2016-03-06 10:35:19 +01:00
|
|
|
#[macro_use]
|
|
|
|
extern crate log;
|
2016-03-14 02:11:20 +01:00
|
|
|
extern crate rand;
|
2016-03-18 06:44:02 +01:00
|
|
|
extern crate crossbeam;
|
2016-03-06 01:54:46 +01:00
|
|
|
|
|
|
|
mod game;
|
2016-03-11 07:26:32 +01:00
|
|
|
mod simulator;
|
|
|
|
mod strategies {
|
|
|
|
pub mod examples;
|
2016-03-13 10:05:05 +01:00
|
|
|
pub mod cheating;
|
2016-03-11 07:26:32 +01:00
|
|
|
}
|
2016-03-06 11:13:08 +01:00
|
|
|
mod info;
|
2016-03-06 01:54:46 +01:00
|
|
|
|
2016-03-14 02:11:20 +01:00
|
|
|
use getopts::Options;
|
|
|
|
use std::str::FromStr;
|
2016-03-06 10:35:19 +01:00
|
|
|
|
|
|
|
struct SimpleLogger;
|
|
|
|
impl log::Log for SimpleLogger {
|
|
|
|
fn enabled(&self, metadata: &log::LogMetadata) -> bool {
|
2016-03-14 02:11:20 +01:00
|
|
|
metadata.level() <= log::LogLevel::Trace
|
2016-03-06 10:35:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fn log(&self, record: &log::LogRecord) {
|
|
|
|
if self.enabled(record.metadata()) {
|
|
|
|
println!("{} - {}", record.level(), record.args());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-14 02:11:20 +01:00
|
|
|
|
|
|
|
fn print_usage(program: &str, opts: Options) {
|
|
|
|
print!("{}", opts.usage(&format!("Usage: {} [options]", program)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-06 01:54:46 +01:00
|
|
|
fn main() {
|
2016-03-14 02:11:20 +01:00
|
|
|
let args: Vec<String> = std::env::args().collect();
|
|
|
|
let program = args[0].clone();
|
|
|
|
|
|
|
|
let mut opts = Options::new();
|
|
|
|
opts.optopt("l", "loglevel", "Log level, one of 'trace', 'debug', 'info', 'warn', and 'error'", "LOGLEVEL");
|
|
|
|
opts.optopt("n", "ntrials", "Number of games to simulate", "NTRIALS");
|
2016-03-18 06:44:02 +01:00
|
|
|
opts.optopt("t", "nthreads", "Number of threads to use for simulation", "NTHREADS");
|
2016-03-14 02:11:20 +01:00
|
|
|
opts.optopt("s", "seed", "Seed for PRNG (can only be used with n=1)", "SEED");
|
2016-03-19 07:34:07 +01:00
|
|
|
opts.optopt("p", "nplayers", "Number of players", "NPLAYERS");
|
2016-03-14 02:11:20 +01:00
|
|
|
opts.optflag("h", "help", "Print this help menu");
|
|
|
|
let matches = match opts.parse(&args[1..]) {
|
|
|
|
Ok(m) => { m }
|
|
|
|
Err(f) => {
|
|
|
|
print_usage(&program, opts);
|
|
|
|
panic!(f.to_string())
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if matches.opt_present("h") {
|
|
|
|
return print_usage(&program, opts);
|
|
|
|
}
|
|
|
|
if !matches.free.is_empty() {
|
|
|
|
return print_usage(&program, opts);
|
|
|
|
}
|
|
|
|
|
|
|
|
let log_level_str : &str = &matches.opt_str("l").unwrap_or("info".to_string());
|
|
|
|
let log_level = match log_level_str {
|
|
|
|
"trace" => { log::LogLevelFilter::Trace }
|
|
|
|
"debug" => { log::LogLevelFilter::Debug }
|
|
|
|
"info" => { log::LogLevelFilter::Info }
|
|
|
|
"warn" => { log::LogLevelFilter::Warn }
|
|
|
|
"error" => { log::LogLevelFilter::Error }
|
2016-03-19 07:34:07 +01:00
|
|
|
_ => {
|
|
|
|
print_usage(&program, opts);
|
|
|
|
panic!("Unexpected log level argument {}", log_level_str);
|
|
|
|
}
|
2016-03-14 02:11:20 +01:00
|
|
|
};
|
2016-03-13 21:50:38 +01:00
|
|
|
|
2016-03-06 10:35:19 +01:00
|
|
|
log::set_logger(|max_log_level| {
|
2016-03-14 02:11:20 +01:00
|
|
|
max_log_level.set(log_level);
|
2016-03-06 10:35:19 +01:00
|
|
|
Box::new(SimpleLogger)
|
2016-03-07 06:44:17 +01:00
|
|
|
}).unwrap();
|
2016-03-06 10:35:19 +01:00
|
|
|
|
2016-03-14 02:11:20 +01:00
|
|
|
let n = u32::from_str(&matches.opt_str("n").unwrap_or("1".to_string())).unwrap();
|
|
|
|
|
|
|
|
let seed = matches.opt_str("s").map(|seed_str| { u32::from_str(&seed_str).unwrap() });
|
|
|
|
|
2016-03-18 06:44:02 +01:00
|
|
|
let n_threads = u32::from_str(&matches.opt_str("t").unwrap_or("1".to_string())).unwrap();
|
|
|
|
|
2016-03-19 07:34:07 +01:00
|
|
|
let n_players = u32::from_str(&matches.opt_str("p").unwrap_or("4".to_string())).unwrap();
|
|
|
|
let hand_size = match n_players {
|
|
|
|
2 => 5,
|
|
|
|
3 => 5,
|
|
|
|
4 => 4,
|
|
|
|
5 => 4,
|
|
|
|
_ => { panic!("There should be 2 to 5 players, not {}", n_players); }
|
|
|
|
};
|
|
|
|
|
2016-03-06 07:49:40 +01:00
|
|
|
let opts = game::GameOptions {
|
2016-03-19 07:34:07 +01:00
|
|
|
num_players: n_players,
|
|
|
|
hand_size: hand_size,
|
2016-03-06 07:49:40 +01:00
|
|
|
num_hints: 8,
|
|
|
|
num_lives: 3,
|
2016-03-19 07:34:07 +01:00
|
|
|
// hanabi rules are a bit ambiguous about whether you can give hints that match 0 cards
|
|
|
|
allow_empty_hints: false,
|
2016-03-06 07:49:40 +01:00
|
|
|
};
|
2016-03-14 02:11:20 +01:00
|
|
|
|
|
|
|
// TODO: make this configurable
|
2016-03-18 06:44:02 +01:00
|
|
|
// let strategy_config = strategies::examples::RandomStrategyConfig {
|
|
|
|
// hint_probability: 0.4,
|
|
|
|
// play_probability: 0.2,
|
|
|
|
// };
|
|
|
|
let strategy_config = strategies::cheating::CheatingStrategyConfig::new();
|
|
|
|
simulator::simulate(&opts, &strategy_config, seed, n, n_threads);
|
2016-03-06 01:54:46 +01:00
|
|
|
}
|