use r2pipe::R2Pipe; use structopt::StructOpt; use std::path::PathBuf; use std::time::Duration; // we're using a custom int type here, as we want to set defaults using // structopt which leads to a problem, as structopt only allows strings to be // set as default values () #[derive(Debug)] struct Int(u64); impl std::str::FromStr for Int { type Err = Box; fn from_str(s: &str) -> Result { Ok(Int(s.parse::().unwrap())) } } impl std::fmt::Display for Int { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.0) } } // we're using a custom "Delay" type here, as we want to define the duration // #of a game round, but structopt (as with the int stuff above) can't use time // durations (it's time, not easy!). [derive(Debug)] #[derive(Debug)] struct Delay(Duration); impl std::str::FromStr for Delay { type Err = Box; fn from_str(s: &str) -> Result { Ok(Delay(Duration::from_secs(s.parse::().unwrap()))) } } #[derive(Debug)] struct Bot { // Path defines the path to the source of the bot path: PathBuf, // Source defines the source of the bot after being compiled with rasm2 source: Option, // Addr defines the initial address the bot is placed at addr: Option, // Regs defines the state of the registers of the bot // It is used to store the registers after each round and restore them in the // next round when the bot's turn has come regs: Option, } #[derive(Debug, PartialEq, Clone)] struct BotPaths(Vec); impl std::str::FromStr for BotPaths { type Err = Box; fn from_str(s: &str) -> Result { Ok(BotPaths(s.split(",").map(|x| x.trim().to_owned()).collect())) } } // these are the options you can use, list them nicely using // `cargo run -- --help` #[derive(Debug, StructOpt)] #[structopt(about = "Yet another r2wars implementation, made with <3 @ AFRA Berlin")] struct Opt { #[structopt(short = "a", long = "arch", default_value = "x86")] architecture: String, #[structopt(short = "b", long = "bits", default_value = "64")] bits: Int, #[structopt(long = "memsize", default_value = "4096")] memory_size: Int, #[structopt(long = "maxbotsize", default_value = "256")] max_bot_size: Int, #[structopt(long = "bots", default_value = "bots/warrior0.asm, bots/warrior1.asm")] bots: BotPaths, #[structopt(long = "delay", default_value = "1")] game_round_duration_seconds: Delay, } fn init_arena(r2p: &mut R2Pipe, opt: &Opt) { println!("[ ] Initializing the arena"); println!("[ ] Allocating {} bytes of memory...", opt.memory_size); let _ = r2p.cmd(format!("malloc://{}", opt.memory_size).as_str()) .expect("could not allocate memory"); println!("[ ] General configuration..."); let _ = r2p.cmd(format!("e asm.arch = {}", opt.architecture).as_str()) .expect("could not set the desired architecture"); let _ = r2p.cmd(format!("e asm.bits = {}", opt.bits).as_str()) .expect("could not set the desired bits"); println!("[ ] ...Done"); println!("[ ] Theming..."); let _ = r2p.cmd("e scr.color = 3").expect("set color err"); let _ = r2p.cmd("e scr.color.args = true").expect("set color err"); let _ = r2p.cmd("e scr.color.bytes = true").expect("set color err"); let _ = r2p.cmd("e scr.color.grep = true").expect("set color err"); let _ = r2p.cmd("e scr.color.ops = true").expect("set color err"); let _ = r2p.cmd("e scr.color.pipe = true").expect("set color err"); let _ = r2p.cmd("e scr.bgfill = true").expect("set color err"); let _ = r2p.cmd("e scr.utf8 = true").expect("set color err"); let _ = r2p.cmd("e hex.cols = 32").expect("set hex col width err"); println!("[ ] ...Done"); println!("[ ] ESIL..."); let _ = r2p.cmd("aei").expect("init esil vm failed"); // init ESIL VM let _ = r2p.cmd("aeim").expect("init esil vm stack failed"); // init ESIL VM stack println!("[ ] ...Done"); } fn build_bots(opt: &Opt, bots: &mut Vec) { for bot_path in opt.bots.0.clone().into_iter() { bots.push( build_bot(PathBuf::from(bot_path)) .expect("could not build a bot!") ) } } fn build_bot(bot_path: PathBuf) -> Result { let mut r2p = r2pipe::open_pipe!(Some("--").to_owned()).expect("could not open r2pipe"); let source = r2p.cmd(format!("rasm2 -a {} -b {} -f {:?}", "x86", "32", bot_path).as_str()) .expect("failed to build the bot!"); let new_bot: Bot = Bot { path: bot_path, source: Some(source), addr: None, regs: None, }; Ok(new_bot) } fn main() -> Result<(), Box> { let mut bots: Vec = vec![]; let opt = Opt::from_args(); println!("{:?}", opt.architecture); println!("{:?}", opt.bits); println!("{:?}", opt.memory_size); println!("{:?}", opt.max_bot_size); println!("{:?}", opt.bots); println!("{:?}", opt.game_round_duration_seconds); let path = Some("--".to_owned()); let mut r2p = r2pipe::open_pipe!(path).expect("could not open r2pipe"); init_arena(&mut r2p, &opt); build_bots(&opt, &mut bots); for bot in bots { println!("{:?}", bot); } r2p.close(); Ok(()) }