command line parsing

This commit is contained in:
Jeff Wu 2016-03-13 18:11:20 -07:00
parent adaa513ff8
commit 7f5feacbc7
4 changed files with 73 additions and 27 deletions

6
Cargo.lock generated
View file

@ -2,10 +2,16 @@
name = "rust_hanabi" name = "rust_hanabi"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"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)", "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)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "getopts"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.7" version = "0.2.7"

View file

@ -6,3 +6,4 @@ authors = ["Jeff Wu <wuthefwasthat@gmail.com>"]
[dependencies] [dependencies]
rand = "*" rand = "*"
log = "*" log = "*"
getopts = "*"

View file

@ -1,6 +1,7 @@
extern crate rand; extern crate getopts;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate rand;
mod game; mod game;
mod simulator; mod simulator;
@ -10,13 +11,13 @@ mod strategies {
} }
mod info; mod info;
#[allow(unused_imports)] use getopts::Options;
use log::LogLevel::{Trace, Debug, Info, Warn, Error}; use std::str::FromStr;
struct SimpleLogger; struct SimpleLogger;
impl log::Log for SimpleLogger { impl log::Log for SimpleLogger {
fn enabled(&self, metadata: &log::LogMetadata) -> bool { fn enabled(&self, metadata: &log::LogMetadata) -> bool {
metadata.level() <= Debug metadata.level() <= log::LogLevel::Trace
} }
fn log(&self, record: &log::LogRecord) { fn log(&self, record: &log::LogRecord) {
@ -26,37 +27,75 @@ impl log::Log for SimpleLogger {
} }
} }
fn print_usage(program: &str, opts: Options) {
print!("{}", opts.usage(&format!("Usage: {} [options]", program)));
}
fn main() { fn main() {
// TODO: make a binary with command line options 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");
opts.optopt("s", "seed", "Seed for PRNG (can only be used with n=1)", "SEED");
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 }
_ => { panic!("Unexpected log level argument {}", log_level_str); }
};
log::set_logger(|max_log_level| { log::set_logger(|max_log_level| {
// max_log_level.set(log::LogLevelFilter::Trace); max_log_level.set(log_level);
max_log_level.set(log::LogLevelFilter::Info);
Box::new(SimpleLogger) Box::new(SimpleLogger)
}).unwrap(); }).unwrap();
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() });
// TODO: make these configurable
let opts = game::GameOptions { let opts = game::GameOptions {
num_players: 4, num_players: 4,
hand_size: 4, hand_size: 4,
num_hints: 8, num_hints: 8,
num_lives: 3, num_lives: 3,
}; };
let n = 1000;
// simulator::simulate(&opts, &strategies::examples::AlwaysDiscard, n); // TODO: make this configurable
// simulator::simulate_symmetric(&opts, strategies::examples::AlwaysPlayConfig, n); // let strategy = strategies::examples::AlwaysPlayConfig;
// simulator::simulate_symmetric( // let strategy = strategies::examples::RandomStrategyConfig {
// &opts,
// strategies::examples::RandomStrategyConfig {
// hint_probability: 0.4, // hint_probability: 0.4,
// play_probability: 0.2, // play_probability: 0.2,
// }, // };
// n let strategy = strategies::cheating::CheatingStrategyConfig::new();
// ); if n == 1 {
simulator::simulate_symmetric( simulator::simulate_symmetric_once(&opts, strategy, seed);
&opts, } else {
strategies::cheating::CheatingStrategyConfig::new(), simulator::simulate_symmetric(&opts, strategy, n);
n }
);
// simulator::simulate_symmetric_once( // simulator::simulate_symmetric_once(
// &opts, Some(999), // &opts, Some(999),
// strategies::cheating::CheatingStrategyConfig::new(), // strategies::cheating::CheatingStrategyConfig::new(),

View file

@ -14,8 +14,8 @@ pub trait StrategyConfig {
pub fn simulate_once<'a>( pub fn simulate_once<'a>(
opts: &GameOptions, opts: &GameOptions,
strat_configs: &Vec<Box<StrategyConfig + 'a>>,
seed_opt: Option<u32>, seed_opt: Option<u32>,
strat_configs: &Vec<Box<StrategyConfig + 'a>>
) -> Score { ) -> Score {
let seed = if let Some(seed) = seed_opt { let seed = if let Some(seed) = seed_opt {
@ -69,7 +69,7 @@ pub fn simulate_once<'a>(
pub fn simulate<'a>(opts: &GameOptions, strat_configs: &Vec<Box<StrategyConfig + 'a>>, n_trials: u32) -> f32 { pub fn simulate<'a>(opts: &GameOptions, strat_configs: &Vec<Box<StrategyConfig + 'a>>, n_trials: u32) -> f32 {
let mut total_score = 0; let mut total_score = 0;
for seed in 0..n_trials { for seed in 0..n_trials {
let score = simulate_once(&opts, Some(seed), strat_configs); let score = simulate_once(&opts, strat_configs, Some(seed));
debug!("Scored: {:?}", score); debug!("Scored: {:?}", score);
if score != 25 { if score != 25 {
info!("Seed with non-perfect score: {:?}", seed); info!("Seed with non-perfect score: {:?}", seed);
@ -83,15 +83,15 @@ pub fn simulate<'a>(opts: &GameOptions, strat_configs: &Vec<Box<StrategyConfig +
pub fn simulate_symmetric_once<'a, S: StrategyConfig + Clone + 'a>( pub fn simulate_symmetric_once<'a, S: StrategyConfig + Clone + 'a>(
opts: &GameOptions, opts: &GameOptions,
strat_config: S,
seed_opt: Option<u32>, seed_opt: Option<u32>,
strat_config: S
) -> Score { ) -> Score {
let mut strat_configs = Vec::new(); let mut strat_configs = Vec::new();
for _ in 0..opts.num_players { for _ in 0..opts.num_players {
strat_configs.push(Box::new(strat_config.clone()) as Box<StrategyConfig + 'a>); strat_configs.push(Box::new(strat_config.clone()) as Box<StrategyConfig + 'a>);
} }
simulate_once(opts, seed_opt, &strat_configs) simulate_once(opts, &strat_configs, seed_opt)
} }
pub fn simulate_symmetric<'a, S: StrategyConfig + Clone + 'a>(opts: &GameOptions, strat_config: S, n_trials: u32) -> f32 { pub fn simulate_symmetric<'a, S: StrategyConfig + Clone + 'a>(opts: &GameOptions, strat_config: S, n_trials: u32) -> f32 {