chess_uci/chess_uci/src/uci_command.rs

124 lines
3.8 KiB
Rust

use itertools::join;
use std::time::Duration;
use std::fmt;
use chess::{ChessMove, Board, Action};
mod uci_command{}
pub struct Id {name: Option<String>, author: Option<String>}
impl Id {
pub fn new() -> Id {
Id{name: None, author: None}
}
pub fn update(&mut self, id: &Id){
if let Some(name) = &id.name {self.name = Some(name.clone());}
if let Some(author) = &id.author {self.author = Some(author.clone());}
}
pub fn update_from_str(&mut self, name: Option<&str>, author: Option<&str>){
if let Some(name) = name {self.name = Some(name.to_string());}
if let Some(author) = author {self.author = Some(author.to_string());}
}
pub fn name(&self) -> Option<String> {
self.name.clone()
}
pub fn author(&self) -> Option<String> {
self.author.clone()
}
}
#[derive(Debug)]
pub struct Info {}
#[derive(Debug)]
pub struct Opt{}
pub enum EngineCommand {
Id{id: Id},
UciOk,
ReadyOk,
BestMove{best_move: ChessMove, ponder: Option<ChessMove>},
CopyProtection, // unimplemented
Registration, // unimplemented
Info{infos: Vec<Info>},
Opt{options: Vec<Opt>},
}
#[derive(Debug)]
pub enum GuiCommand {
Uci,
Debug{mode: bool},
IsReady,
SetOption{option: Opt},
Register, // unimplemented
UciNewGame,
Position{position: Option<Board>, moves: Vec<Action>},
Go,
SearchMoves{moves: Vec<ChessMove>},
Ponder,
WTime{time: Duration},
BTime{time: Duration},
WInc{increment: Duration},
BInc{increment: Duration},
MovesToGo{number: u16},
Depth{number: u16},
Nodes{number: u16},
Mate{number: u16},
MoveTime{time: Duration},
Infinite,
Stop,
PonderHit,
Quit,
}
pub fn parse(message: &mut String) -> Result<EngineCommand,&'static str> {
let mut message_iter = message.split_whitespace();
match message_iter.next() {
None => Err("No command provided"),
Some("id") =>
match message_iter.collect::<Vec<&str>>().as_slice() {
[] => Err("Empty id command"),
["name"] => Err("Empty id name command"),
["author"] => Err("Empty id author command"),
["name", tail @ ..] => Ok(EngineCommand::Id{id: { let mut id = Id::new(); id.update_from_str(Some(&join(tail, " ")), None); id}}),
["author", tail @ ..] => Ok(EngineCommand::Id{id: { let mut id = Id::new(); id.update_from_str(None, Some(&join(tail, " "))); id}}),
_ => Err("Invalid id subcommand")
},
Some("uciok") => Ok(EngineCommand::UciOk),
Some("readyok") => unimplemented!(),
Some("bestmove") => unimplemented!(),
Some("copyprotection") => unimplemented!(),
Some("registration") => unimplemented!(),
Some("info") => unimplemented!(),
Some("option") => Ok(EngineCommand::Opt { options: Vec::new() }), // todo!("Parse options lines")
Some(_) => Err("Unknown command provided"),
}
}
impl fmt::Display for GuiCommand {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result{
match self {
GuiCommand::Uci => write!(f, "uci\n"),
GuiCommand::UciNewGame => write!(f, "ucinewgame\n"),
GuiCommand::Position { position, moves } => {
write!(f, "position {} moves {}\n",
match position { None => "startpos".to_string(),
Some(board) if *board == Board::default() => "startpos".to_string(),
Some(board) =>"fen ".to_string() + &board.to_string()},
join(moves.into_iter().map(|x| if let Action::MakeMove(chessmove) = x
{chessmove.to_string()} else {"".to_string()}), "")
)
}
a => unimplemented!("{:?}", a),
}
}
}