advance on execution
This commit is contained in:
parent
745817d47a
commit
74cd37666e
|
@ -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"
|
||||||
|
|
185
src/lib.rs
185
src/lib.rs
|
@ -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){
|
pub fn update(&mut self, id: &Id){
|
||||||
match &id.name {
|
if self.is_uciok() {warn!("Engine info should not be updated now (uciok)");}
|
||||||
Some(name) => self.name = name.clone(),
|
self.id.update(id);
|
||||||
None => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match &id.author {
|
pub fn update_from_str(&mut self, name: Option<&str>, author: Option<&str>){
|
||||||
Some(author) => self.author = author.clone(),
|
if self.is_uciok() {warn!("Engine info should not be updated now (uciok)");}
|
||||||
None => {}
|
self.id.update_from_str(name, author);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Id {name: Option<String>, author: Option<String>}
|
pub fn uciok(&mut self){
|
||||||
impl Id {
|
self.uciok = true;
|
||||||
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 {
|
pub fn is_uciok(&self) -> bool {
|
||||||
Some(author) => self.author = Some(author.to_string()),
|
self.uciok
|
||||||
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
|
/// 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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue