chess_uci/src/lib.rs

158 lines
4.9 KiB
Rust

#![allow(dead_code)]
/// Manage UCI messages and link into chess component
pub mod uci_engine {
use itertools::join;
mod chess_move {
pub struct Move {}
}
mod chess_info{
pub struct Info {}
}
mod chess_option{
pub struct Opt{}
}
pub struct UciEngine {
name: String,
author: String,
}
impl UciEngine {
pub fn new(name: &str, author: &str) -> UciEngine {
UciEngine{name: name.to_string(), author: author.to_string()}
}
pub fn name(&self) -> String {
self.name.clone()
}
pub fn author(&self) -> String {
self.author.clone()
}
pub fn update(&mut self, id: &Id){
match &id.name {
Some(name) => self.name = name.clone(),
None => {}
}
match &id.author {
Some(author) => self.author = author.clone(),
None => {}
}
}
}
pub struct Id {name: Option<String>, author: Option<String>}
impl Id {
pub fn new(name: Option<&str>, author: Option<&str>) -> Id {
Id{
name: if let Some(name) = name {Some(name.to_string())} else {None},
author: if let Some(author) = author {Some(author.to_string())} else {None}
}
}
pub fn update(&mut self, name: Option<&str>, author: Option<&str>){
match &name {
Some(name) => self.name = Some(name.to_string()),
None => {}
}
match &author {
Some(author) => self.author = Some(author.to_string()),
None => {}
}
}
}
pub enum UciCommand {
Id{id: Id},
UciOk,
ReadyOk,
BestMove{best_move: chess_move::Move, ponder: chess_move::Move},
CopyProtection, // unimplemented
Registration, // unimplemented
Info{infos: Vec<chess_info::Info>},
Opt{options: Vec<chess_option::Opt>},
}
/// Parse UCI commands
///
/// * id
/// * name *x*
///
/// this must be sent after receiving the "uci" command to identify the engine,
/// e.g. "id name Shredder X.Y\n"
/// * author *x*
///
/// this must be sent after receiving the "uci" command to identify the engine,
/// e.g. "id author Stefan MK\n"
///
/// ```rust
/// use chess_uci::uci_engine::{parse, UciCommand, Id, UciEngine};
/// let mut engine = UciEngine::new("Test", "Bat");
///
/// engine.exec(&parse(&mut "id name Baptiste".to_string()).expect("simple id name command"));
/// assert_eq!(engine.name(), "Baptiste");
///
/// engine.exec(&parse(&mut "id author Monique Jouve".to_string()).expect("simple id author command"));
/// assert_eq!(engine.author(), "Monique Jouve");
///
/// ```
pub fn parse(message: &mut String) -> Result<UciCommand,&'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(UciCommand::Id{id: Id::new(Some(&join(tail, " ")), None)}),
["author", tail @ ..] => Ok(UciCommand::Id{id: Id::new(None, Some(&join(tail, " ")))}),
_ => Err("Invalid id subcommand")
},
Some("uciok") => unimplemented!(),
Some("readyok") => unimplemented!(),
Some("bestmove") => unimplemented!(),
Some("copyprotection") => unimplemented!(),
Some("registration") => unimplemented!(),
Some("info") => unimplemented!(),
Some("option") => unimplemented!(),
Some(_) => Err("Unknown command provided"),
}
}
impl UciEngine {
pub fn exec(&mut self, command: &UciCommand){
match command {
UciCommand::Id{id} => self.update(&id),
_ => unimplemented!(),
}
}
}
}
#[cfg(test)]
mod tests {
use super::uci_engine::*;
#[test]
fn new_uci() {
let mut engine = UciEngine::new("Test", "Bat");
assert_eq!(engine.name(), "Test");
assert_eq!(engine.author(), "Bat");
let new_id = Id::new(Some("Test 1"), None);
engine.update(&new_id);
assert_eq!(engine.name(), "Test 1");
assert_eq!(engine.author(), "Bat");
let new_id = Id::new(Some("Test 2"), Some("Bat 1"));
engine.update(&new_id);
assert_eq!(engine.name(), "Test 2");
assert_eq!(engine.author(), "Bat 1");
}
}