advance on execution
This commit is contained in:
parent
745817d47a
commit
74cd37666e
|
@ -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"
|
||||
|
|
185
src/lib.rs
185
src/lib.rs
|
@ -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,
|
||||
}
|
||||
|
||||
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 {
|
||||
name: String,
|
||||
author: String,
|
||||
pub fn name(&self) -> Option<String> {
|
||||
self.id.name()
|
||||
}
|
||||
|
||||
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 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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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