use std::collections::BTreeMap; use engine::{Command, SearchInfo}; use board::Board; pub fn parse_command(command: &str) -> Result { let parts = command.split_whitespace().collect::>(); if parts.len() > 0 { let command = parts[0]; let args: Vec<&str> = parts.into_iter().skip(1).collect(); match command { "uci" => Ok(Command::Uci), "isready" => Ok(Command::IsReady), "ucinewgame" => Ok(Command::NewGame), "setoption" => parse_setoption(&args), "position" => parse_position(&args), "go" => parse_go(&args), "stop" => Ok(Command::Stop), "quit" | "exit" => Ok(Command::Quit), /*"isready" => cmd_isready(cmd, r, s), "position" => cmd_position(cmd, r, s), "print" => cmd_print(cmd, r, s), "go" => cmd_go(cmd, r, s), "stop" => cmd_stop(cmd, r, s), "ucinewgame" => cmd_newgame(cmd, r, s), //"setoption" => cmd_setoption(cmd, r, s), "quit" | "exit" => cmd_quit(cmd, r, s),*/ "" => Ok(Command::Ping), _cmd => { Err("unknown command".to_owned()) } } } else { Err("no command".to_owned()) } } fn parse_position(args: &Vec<&str>) -> Result { //let position = args[0]; //args.drain(0..1); let mut arg_iter = args.iter(); let &position = arg_iter.next().ok_or("no position type argument")?; let mut board = Board::default(); if position == "startpos" { } else if position == "fen" { let fen_parts: Vec<&str> = arg_iter.by_ref().take(6).map(|p| *p).collect::>(); if fen_parts.len() != 6 { return Err("invalid fen arguments".to_owned()); } board = Board::from_fen(fen_parts.as_slice()).ok_or("invalid fen")?; } else { return Err("invalid position type".to_owned()); } let pmov = arg_iter.next(); let moves = if let Some(&moves) = pmov { if moves != "moves" { return Err("expected nothing or 'moves'".to_owned()); } arg_iter.map(|m| String::from(*m)).collect::>() } else { Vec::new() }; Ok(Command::Position{ pos: board, moves }) } pub fn parse_go(args: &Vec<&str>) -> Result { let mut options: BTreeMap = BTreeMap::new(); let mut opt_name: Option<&str> = None; let mut si = SearchInfo::new(); for &arg in args { if let Some(on) = opt_name { options.insert(on.to_owned(), arg.to_owned()); opt_name = None; } else if arg == "infinite" { si.infinite = true; } else if arg == "perft" { si.perft = true; } else { opt_name = Some(arg); } } si.movetime = options.get("movetime").map(|x| x.parse::<_>().unwrap_or(0)); si.depth = options.get("depth").map(|x| x.parse::<_>().unwrap_or(0)); si.wtime = options.get("wtime").map(|x| x.parse::<_>().unwrap_or(0)); si.btime = options.get("btime").map(|x| x.parse::<_>().unwrap_or(0)); si.winc = options.get("winc").map(|x| x.parse::<_>().unwrap_or(0)); si.binc = options.get("binc").map(|x| x.parse::<_>().unwrap_or(0)); si.movestogo = options.get("movestogo").map(|x| x.parse::<_>().unwrap_or(0)); Ok(Command::Go(si)) } pub fn parse_setoption(args: &Vec<&str>) -> Result { enum State { None, Name, Value } let mut state = State::None; let mut name: String = String::new(); let mut value: String = String::new(); let extend_string = |s: &mut String, ex: &str| { if !s.is_empty() { s.push_str(" "); } s.push_str(ex); }; for arg in args { match *arg { "name" => { state = State::Name; }, "value" => { state = State::Value; }, any => { match state { State::Name => extend_string(&mut name, any), State::Value => extend_string(&mut value, any), State::None => return Err("invalid option".to_owned()) } } } } Ok(Command::SetOption { name: name, val: value }) }