hanabi.rs/src/main.rs

149 lines
4.7 KiB
Rust
Raw Normal View History

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;
extern crate fnv;
2016-03-06 01:54:46 +01:00
mod helpers;
2016-03-06 01:54:46 +01:00
mod game;
mod simulator;
2016-04-04 09:26:42 +02:00
mod strategy;
mod strategies {
pub mod examples;
2016-03-13 10:05:05 +01:00
pub mod cheating;
2016-03-27 19:47:58 +02:00
pub mod information;
}
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();
2016-03-20 20:40:27 +01:00
opts.optopt("l", "loglevel",
"Log level, one of 'trace', 'debug', 'info', 'warn', and 'error'",
"LOGLEVEL");
opts.optopt("n", "ntrials",
"Number of games to simulate (default 1)",
2016-03-20 20:40:27 +01:00
"NTRIALS");
opts.optopt("o", "output",
"Number of games after which to print an update",
"OUTPUT_FREQ");
2016-03-20 20:40:27 +01:00
opts.optopt("t", "nthreads",
"Number of threads to use for simulation (default 1)",
2016-03-20 20:40:27 +01:00
"NTHREADS");
opts.optopt("s", "seed",
"Seed for PRNG (default random)",
2016-03-20 20:40:27 +01:00
"SEED");
opts.optopt("p", "nplayers",
"Number of players",
"NPLAYERS");
opts.optopt("g", "strategy",
"Which strategy to use. One of 'random', 'cheat', and 'info'",
2016-03-20 20:40:27 +01:00
"STRATEGY");
opts.optflag("h", "help",
"Print this help menu");
2016-03-14 02:11:20 +01:00
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() });
let progress_info = matches.opt_str("o").map(|freq_str| { u32::from_str(&freq_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-20 20:40:27 +01:00
let game_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
2016-03-20 20:40:27 +01:00
let strategy_str : &str = &matches.opt_str("g").unwrap_or("cheat".to_string());
2016-04-04 09:26:42 +02:00
let strategy_config : Box<strategy::GameStrategyConfig + Sync> = match strategy_str {
2016-03-20 20:40:27 +01:00
"random" => {
Box::new(strategies::examples::RandomStrategyConfig {
hint_probability: 0.4,
play_probability: 0.2,
2016-04-04 09:26:42 +02:00
}) as Box<strategy::GameStrategyConfig + Sync>
2016-03-20 20:40:27 +01:00
},
"cheat" => {
Box::new(strategies::cheating::CheatingStrategyConfig::new())
2016-04-04 09:26:42 +02:00
as Box<strategy::GameStrategyConfig + Sync>
2016-03-20 20:40:27 +01:00
},
2016-03-27 19:47:58 +02:00
"info" => {
Box::new(strategies::information::InformationStrategyConfig::new())
2016-04-04 09:26:42 +02:00
as Box<strategy::GameStrategyConfig + Sync>
2016-03-27 19:47:58 +02:00
},
2016-03-20 20:40:27 +01:00
_ => {
print_usage(&program, opts);
panic!("Unexpected strategy argument {}", strategy_str);
},
};
simulator::simulate(&game_opts, strategy_config, seed, n, n_threads, progress_info);
2016-03-06 01:54:46 +01:00
}