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]
name = "chess-uci"
name = "chess_uci"
version = "0.1.0"
edition = "2021"
@ -8,3 +8,4 @@ edition = "2021"
[dependencies]
chess = "3.2.0"
itertools = "0.10.5"
log = "0.4.17"

View File

@ -1,80 +1,51 @@
#![allow(dead_code)]
/// Manage UCI messages and link into chess component
pub mod uci_engine {
use itertools::join;
mod uci_command;
mod chess_move {
pub struct Move {}
}
mod chess_info{
pub struct Info {}
}
mod chess_option{
pub struct Opt{}
use log::warn;
use std::io::*;
use crate::uci_command::*;
pub struct UciEngine<Fi: Read, Fo: Write> {
source: Fi,
destination: Fo,
uciok: bool,
id: Id,
}
pub struct UciEngine {
name: String,
author: String,
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}
}
impl UciEngine {
pub fn new(name: &str, author: &str) -> UciEngine {
UciEngine{name: name.to_string(), author: author.to_string()}
pub fn name(&self) -> Option<String> {
self.id.name()
}
pub fn name(&self) -> String {
self.name.clone()
}
pub fn author(&self) -> String {
self.author.clone()
pub fn author(&self) -> Option<String> {
self.id.author()
}
pub fn update(&mut self, id: &Id){
match &id.name {
Some(name) => self.name = name.clone(),
None => {}
if self.is_uciok() {warn!("Engine info should not be updated now (uciok)");}
self.id.update(id);
}
match &id.author {
Some(author) => self.author = author.clone(),
None => {}
}
}
pub fn update_from_str(&mut self, name: Option<&str>, author: Option<&str>){
if self.is_uciok() {warn!("Engine info should not be updated now (uciok)");}
self.id.update_from_str(name, author);
}
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 => {}
pub fn uciok(&mut self){
self.uciok = true;
}
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>},
pub fn is_uciok(&self) -> bool {
self.uciok
}
/// Parse UCI commands
@ -90,68 +61,50 @@ pub mod uci_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");
/// use chess_uci::*;
/// 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"));
/// assert_eq!(engine.name(), "Baptiste");
/// engine.exec("id name Baptiste");
/// assert_eq!(engine.name().expect(""), "Baptiste");
///
/// engine.exec(&parse(&mut "id author Monique Jouve".to_string()).expect("simple id author command"));
/// assert_eq!(engine.author(), "Monique Jouve");
/// engine.exec("id 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();
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"),
///
/// * uciok
///
/// Must be sent after the id and optional options to tell the GUI that the engine
/// has sent all infos and is ready in uci mode.
///
/// ```rust
/// use chess_uci::*;
/// use std::io;
/// let mut engine = UciEngine::new(io::empty(), io::sink());
/// assert_eq!(engine.is_uciok(), false);
///
/// engine.exec("id name Baptiste");
/// assert_eq!(engine.name().expect(""), "Baptiste");
/// assert_eq!(engine.is_uciok(), false);
///
/// engine.exec("id author Monique Jouve");
/// assert_eq!(engine.author().expect(""), "Monique Jouve");
/// assert_eq!(engine.is_uciok(), false);
///
/// engine.exec(" uciok");
/// assert_eq!(engine.is_uciok(), true);
/// ```
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 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");
pub fn next(&mut self) {
exec(self.source.read_line());
}
}

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"),
}
}