advance on execution

This commit is contained in:
Baptiste Fouques 2023-01-11 12:07:28 +01:00
parent 745817d47a
commit 74cd37666e
3 changed files with 173 additions and 122 deletions

View File

@ -1,5 +1,5 @@
[package] [package]
name = "chess-uci" name = "chess_uci"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
@ -8,3 +8,4 @@ edition = "2021"
[dependencies] [dependencies]
chess = "3.2.0" chess = "3.2.0"
itertools = "0.10.5" itertools = "0.10.5"
log = "0.4.17"

View File

@ -1,80 +1,51 @@
#![allow(dead_code)] #![allow(dead_code)]
/// Manage UCI messages and link into chess component /// Manage UCI messages and link into chess component
pub mod uci_engine { mod uci_command;
use itertools::join;
mod chess_move { use log::warn;
pub struct Move {} use std::io::*;
} use crate::uci_command::*;
mod chess_info{
pub struct Info {} pub struct UciEngine<Fi: Read, Fo: Write> {
} source: Fi,
mod chess_option{ destination: Fo,
pub struct Opt{} uciok: bool,
id: Id,
}
impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
pub fn new(source: Fi, destination: Fo) -> UciEngine<Fi, Fo> {
UciEngine::<Fi, Fo>{
source, destination,
id: Id::new(),
uciok: false}
} }
pub struct UciEngine { pub fn name(&self) -> Option<String> {
name: String, self.id.name()
author: String,
} }
impl UciEngine { pub fn author(&self) -> Option<String> {
pub fn new(name: &str, author: &str) -> UciEngine { self.id.author()
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>} pub fn update(&mut self, id: &Id){
impl Id { if self.is_uciok() {warn!("Engine info should not be updated now (uciok)");}
pub fn new(name: Option<&str>, author: Option<&str>) -> Id { self.id.update(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 { pub fn update_from_str(&mut self, name: Option<&str>, author: Option<&str>){
Id{id: Id}, if self.is_uciok() {warn!("Engine info should not be updated now (uciok)");}
UciOk, self.id.update_from_str(name, author);
ReadyOk, }
BestMove{best_move: chess_move::Move, ponder: chess_move::Move},
CopyProtection, // unimplemented pub fn uciok(&mut self){
Registration, // unimplemented self.uciok = true;
Info{infos: Vec<chess_info::Info>}, }
Opt{options: Vec<chess_option::Opt>},
pub fn is_uciok(&self) -> bool {
self.uciok
} }
/// Parse UCI commands /// Parse UCI commands
@ -90,68 +61,50 @@ pub mod uci_engine {
/// e.g. "id author Stefan MK\n" /// e.g. "id author Stefan MK\n"
/// ///
/// ```rust /// ```rust
/// use chess_uci::uci_engine::{parse, UciCommand, Id, UciEngine}; /// use chess_uci::*;
/// let mut engine = UciEngine::new("Test", "Bat"); /// use std::io;
/// let mut engine = UciEngine::new(io::empty(), io::sink());
/// ///
/// engine.exec(&parse(&mut "id name Baptiste".to_string()).expect("simple id name command")); /// engine.exec("id name Baptiste");
/// assert_eq!(engine.name(), "Baptiste"); /// assert_eq!(engine.name().expect(""), "Baptiste");
/// ///
/// engine.exec(&parse(&mut "id author Monique Jouve".to_string()).expect("simple id author command")); /// engine.exec("id author Monique Jouve");
/// assert_eq!(engine.author(), "Monique Jouve"); /// assert_eq!(engine.author().expect(""), "Monique Jouve");
/// ///
/// ``` /// ```
pub fn parse(message: &mut String) -> Result<UciCommand,&'static str> { ///
let mut message_iter = message.split_whitespace(); /// * uciok
///
match message_iter.next() { /// Must be sent after the id and optional options to tell the GUI that the engine
None => Err("No command provided"), /// has sent all infos and is ready in uci mode.
///
Some("id") => /// ```rust
match message_iter.collect::<Vec<&str>>().as_slice() { /// use chess_uci::*;
[] => Err("Empty id command"), /// use std::io;
["name"] => Err("Empty id name command"), /// let mut engine = UciEngine::new(io::empty(), io::sink());
["author"] => Err("Empty id author command"), /// assert_eq!(engine.is_uciok(), false);
["name", tail @ ..] => Ok(UciCommand::Id{id: Id::new(Some(&join(tail, " ")), None)}), ///
["author", tail @ ..] => Ok(UciCommand::Id{id: Id::new(None, Some(&join(tail, " ")))}), /// engine.exec("id name Baptiste");
_ => Err("Invalid id subcommand") /// assert_eq!(engine.name().expect(""), "Baptiste");
}, /// assert_eq!(engine.is_uciok(), false);
Some("uciok") => unimplemented!(), ///
Some("readyok") => unimplemented!(), /// engine.exec("id author Monique Jouve");
Some("bestmove") => unimplemented!(), /// assert_eq!(engine.author().expect(""), "Monique Jouve");
Some("copyprotection") => unimplemented!(), /// assert_eq!(engine.is_uciok(), false);
Some("registration") => unimplemented!(), ///
Some("info") => unimplemented!(), /// engine.exec(" uciok");
Some("option") => unimplemented!(), /// assert_eq!(engine.is_uciok(), true);
Some(_) => Err("Unknown command provided"), /// ```
pub fn exec(&mut self, command: &str){
match parse (&mut command.to_string()) {
Ok(EngineCommand::Id{id}) => self.update(&id),
Ok(EngineCommand::UciOk) => self.uciok(),
Ok(_) => {unimplemented!("command not implemented")},
Err(_) => warn!("Not a command"),
} }
} }
impl UciEngine { pub fn next(&mut self) {
pub fn exec(&mut self, command: &UciCommand){ exec(self.source.read_line());
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");
} }
} }

97
src/uci_command.rs Normal file
View File

@ -0,0 +1,97 @@
use itertools::join;
use std::time::Duration;
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()
}
}
pub struct Move {}
pub struct Info {}
pub struct Opt{}
pub struct Position{}
pub enum EngineCommand {
Id{id: Id},
UciOk,
ReadyOk,
BestMove{best_move: Move, ponder: Move},
CopyProtection, // unimplemented
Registration, // unimplemented
Info{infos: Vec<Info>},
Opt{options: Vec<Opt>},
}
pub enum GuiCommand {
Uci,
Debug{mode: bool},
IsReady,
SetOption{option: Opt},
Register, // unimplemented
UciNewGame,
Position{position: Option<Position>, moves: Vec<Move>},
Go,
SearchMoves{moves: Vec<Move>},
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") => unimplemented!(),
Some(_) => Err("Unknown command provided"),
}
}