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"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										195
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										195
									
								
								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 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 fn author(&self) -> Option<String> {
 | 
			
		||||
        self.id.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 => {}
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            match &author {
 | 
			
		||||
                Some(author) => self.author = Some(author.to_string()),
 | 
			
		||||
                None => {}
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    pub fn update(&mut self, id: &Id){
 | 
			
		||||
        if self.is_uciok() {warn!("Engine info should not be updated now (uciok)");}
 | 
			
		||||
        self.id.update(id);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    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 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 fn uciok(&mut self){
 | 
			
		||||
        self.uciok = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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
									
								
							
							
						
						
									
										97
									
								
								src/uci_command.rs
									
									
									
									
									
										Normal 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"),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user