Create executable over stockfish
This commit is contained in:
parent
74cd37666e
commit
c125ce3dfc
|
@ -3,9 +3,18 @@ name = "chess_uci"
|
|||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
path="src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name="chess"
|
||||
path="src/main.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
chess = "3.2.0"
|
||||
env_logger = "0.10.0"
|
||||
itertools = "0.10.5"
|
||||
log = "0.4.17"
|
||||
|
||||
|
|
56
src/lib.rs
56
src/lib.rs
|
@ -3,25 +3,43 @@
|
|||
/// Manage UCI messages and link into chess component
|
||||
mod uci_command;
|
||||
|
||||
use log::warn;
|
||||
use log::{info, warn};
|
||||
use std::io::*;
|
||||
use crate::uci_command::*;
|
||||
|
||||
pub struct UciEngine<Fi: Read, Fo: Write> {
|
||||
pub struct UciEngine<Fi: BufRead, Fo: Write> {
|
||||
source: Fi,
|
||||
destination: Fo,
|
||||
uciok: bool,
|
||||
id: Id,
|
||||
}
|
||||
|
||||
impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
|
||||
impl<Fi: BufRead, Fo: Write> UciEngine<Fi, Fo> {
|
||||
pub fn new(source: Fi, destination: Fo) -> UciEngine<Fi, Fo> {
|
||||
UciEngine::<Fi, Fo>{
|
||||
source, destination,
|
||||
id: Id::new(),
|
||||
id: Id::new(),
|
||||
uciok: false}
|
||||
}
|
||||
|
||||
pub fn init(&mut self){
|
||||
self.push(GuiCommand::Uci);
|
||||
|
||||
// Consume commands until uciok messages
|
||||
while !self.uciok {
|
||||
self.pull();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_game(&mut self) {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
pub fn terminate(&mut self, reason: &str) {
|
||||
self.uciok = false;
|
||||
info!("UCI termination: {}", reason);
|
||||
}
|
||||
|
||||
pub fn name(&self) -> Option<String> {
|
||||
self.id.name()
|
||||
}
|
||||
|
@ -34,7 +52,7 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
|
|||
if self.is_uciok() {warn!("Engine info should not be updated now (uciok)");}
|
||||
self.id.update(id);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
@ -84,12 +102,6 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
|
|||
/// 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");
|
||||
|
@ -99,12 +111,30 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
|
|||
match parse (&mut command.to_string()) {
|
||||
Ok(EngineCommand::Id{id}) => self.update(&id),
|
||||
Ok(EngineCommand::UciOk) => self.uciok(),
|
||||
Ok(EngineCommand::Opt { options: _ }) => {},
|
||||
Ok(_) => {unimplemented!("command not implemented")},
|
||||
Err(_) => warn!("Not a command"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next(&mut self) {
|
||||
exec(self.source.read_line());
|
||||
pub fn pull(&mut self) {
|
||||
let mut command = String::new();
|
||||
match self.source.read_line(&mut command) {
|
||||
Ok(0) => self.terminate("Chess engine closed connection."),
|
||||
Ok(_) => {
|
||||
info!("← {}", command);
|
||||
self.exec(&command)
|
||||
},
|
||||
Err(reason) => warn!("Unable to read from engine: {reason}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, command: GuiCommand) {
|
||||
let command_str = command.to_string();
|
||||
match self.destination.write(&command_str.as_bytes()){
|
||||
Ok(n) if n == command_str.len() => info!("☒ gui: {command_str} "),
|
||||
Ok(n) => warn!("⚠ gui: {command_str} truncated at {n}"),
|
||||
Err(reason) => warn!("Unable to send command {command_str}: {reason}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
extern crate chess_uci;
|
||||
|
||||
use chess_uci::*;
|
||||
|
||||
use std::process::{Command, Stdio};
|
||||
use std::io::BufReader;
|
||||
|
||||
pub fn main(){
|
||||
env_logger::init();
|
||||
|
||||
println!("Launching hardcoded stockfish program (should be in PATH)");
|
||||
|
||||
// launch chess program
|
||||
let process = match Command::new("stockfish")
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn() {
|
||||
Err(why) => panic!("couldn't spawn stockfish: {}", why),
|
||||
Ok(process) => process,
|
||||
};
|
||||
|
||||
let (sf_in,sf_out) = (process.stdin.expect("Program stdin"), process.stdout.expect("Program stdout"));
|
||||
let mut uci = UciEngine::new(BufReader::new(sf_out), sf_in);
|
||||
uci.init();
|
||||
|
||||
println!("Engine: {} \nby: {}",
|
||||
if let Some(name) = uci.name() {name} else {"Not defined".to_string()},
|
||||
if let Some(author) = uci.author() {author} else {"Not defined".to_string()});
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
use itertools::join;
|
||||
use std::time::Duration;
|
||||
use std::fmt;
|
||||
|
||||
use chess::ChessMove;
|
||||
|
||||
mod uci_command{}
|
||||
|
||||
|
@ -18,7 +21,7 @@ impl Id {
|
|||
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()
|
||||
}
|
||||
|
@ -27,7 +30,6 @@ impl Id {
|
|||
self.author.clone()
|
||||
}
|
||||
}
|
||||
pub struct Move {}
|
||||
pub struct Info {}
|
||||
pub struct Opt{}
|
||||
pub struct Position{}
|
||||
|
@ -36,7 +38,7 @@ pub enum EngineCommand {
|
|||
Id{id: Id},
|
||||
UciOk,
|
||||
ReadyOk,
|
||||
BestMove{best_move: Move, ponder: Move},
|
||||
BestMove{best_move: ChessMove, ponder: Option<ChessMove>},
|
||||
CopyProtection, // unimplemented
|
||||
Registration, // unimplemented
|
||||
Info{infos: Vec<Info>},
|
||||
|
@ -50,9 +52,9 @@ pub enum GuiCommand {
|
|||
SetOption{option: Opt},
|
||||
Register, // unimplemented
|
||||
UciNewGame,
|
||||
Position{position: Option<Position>, moves: Vec<Move>},
|
||||
Position{position: Option<Position>, moves: Vec<ChessMove>},
|
||||
Go,
|
||||
SearchMoves{moves: Vec<Move>},
|
||||
SearchMoves{moves: Vec<ChessMove>},
|
||||
Ponder,
|
||||
WTime{time: Duration},
|
||||
BTime{time: Duration},
|
||||
|
@ -90,8 +92,18 @@ pub fn parse(message: &mut String) -> Result<EngineCommand,&'static str> {
|
|||
Some("copyprotection") => unimplemented!(),
|
||||
Some("registration") => unimplemented!(),
|
||||
Some("info") => unimplemented!(),
|
||||
Some("option") => unimplemented!(),
|
||||
Some("option") => Ok(EngineCommand::Opt { options: Vec::new() }), // todo!("Parse options lines")
|
||||
Some(_) => Err("Unknown command provided"),
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for GuiCommand {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result{
|
||||
match self {
|
||||
GuiCommand::Uci => write!(f, "uci\n"),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue