This commit is contained in:
Baptiste Fouques 2023-01-30 15:56:01 +01:00
parent b48f52c41c
commit 69cbe46f1d
3 changed files with 317 additions and 150 deletions

View File

@ -3,15 +3,16 @@
/// Manage UCI messages and link into chess component
pub mod uci_command;
use crate::uci_command::*;
use log::{info, warn};
use std::io::*;
use std::time::Duration;
use std::result::Result;
use crate::uci_command::*;
use std::time::Duration;
use chess::{Game, Board, ChessMove};
use chess::{Board, ChessMove, Game};
const DEFAULT_TIME: (Option<Duration>, Option<Duration>) = (Some(Duration::from_secs(120 * 60)), None);
const DEFAULT_TIME: (Option<Duration>, Option<Duration>) =
(Some(Duration::from_secs(120 * 60)), None);
/// Structure used to manage a chess game with a uci engine.
///
@ -49,28 +50,30 @@ pub struct UciEngine<Fi: Read, Fo: Write> {
}
pub enum UciOption {
Ponder{value: bool},
UCIElo{value: Option<u32>},
Ponder { value: bool },
UCIElo { value: Option<u32> },
}
#[derive(Clone, Copy)]
pub enum Player{Human{elo: Option<u32>}, Machine{elo: Option<u32>}}
pub enum Player {
Human { elo: Option<u32> },
Machine { elo: Option<u32> },
}
pub enum GameOption {
WhiteTotalTime{value: Option<Duration>},
BlackTotalTime{value: Option<Duration>},
WhiteIncrement{value: Option<Duration>},
BlackIncrement{value: Option<Duration>},
WhitePlayer{value: Player},
BlackPlayer{value: Player},
WhiteTotalTime { value: Option<Duration> },
BlackTotalTime { value: Option<Duration> },
WhiteIncrement { value: Option<Duration> },
BlackIncrement { value: Option<Duration> },
WhitePlayer { value: Player },
BlackPlayer { value: Player },
}
impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
/// Create new game manager
///
/// Requires line by line input and output streams to communicate with uci engine
pub fn new(source: Option<Fi>, destination: Option<Fo>) -> UciEngine<Fi, Fo> {
UciEngine::<Fi, Fo>{
UciEngine::<Fi, Fo> {
source: source.map(|x| BufReader::new(x)),
destination,
id: Id::default(),
@ -78,25 +81,49 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
initial: Board::default(),
game: Game::new(),
time: [DEFAULT_TIME; 2],
player: [Player::Human{elo: None}; 2],
player: [Player::Human { elo: None }; 2],
}
}
pub fn game_option(&mut self, option: GameOption) -> GameOption {
let old_value: GameOption;
match option {
GameOption::WhiteTotalTime{value} => {old_value = GameOption::WhiteTotalTime { value: self.time[Color::White.to_index()].0 };
self.time[Color::White.to_index()].0 = value},
GameOption::BlackTotalTime{value} => {old_value = GameOption::BlackTotalTime { value: self.time[Color::Black.to_index()].0 };
self.time[Color::Black.to_index()].0 = value},
GameOption::WhiteIncrement{value} => {old_value = GameOption::WhiteIncrement { value: self.time[Color::White.to_index()].1 };
self.time[Color::White.to_index()].1 = value},
GameOption::BlackIncrement{value} => {old_value = GameOption::BlackIncrement { value: self.time[Color::Black.to_index()].1 };
self.time[Color::Black.to_index()].1 = value},
GameOption::WhitePlayer{value} => {old_value = GameOption::WhitePlayer { value: self.player[Color::White.to_index()] };
self.player[Color::White.to_index()] = value},
GameOption::BlackPlayer{value} => {old_value = GameOption::WhitePlayer { value: self.player[Color::Black.to_index()] };
self.player[Color::Black.to_index()] = value},
GameOption::WhiteTotalTime { value } => {
old_value = GameOption::WhiteTotalTime {
value: self.time[Color::White.to_index()].0,
};
self.time[Color::White.to_index()].0 = value
}
GameOption::BlackTotalTime { value } => {
old_value = GameOption::BlackTotalTime {
value: self.time[Color::Black.to_index()].0,
};
self.time[Color::Black.to_index()].0 = value
}
GameOption::WhiteIncrement { value } => {
old_value = GameOption::WhiteIncrement {
value: self.time[Color::White.to_index()].1,
};
self.time[Color::White.to_index()].1 = value
}
GameOption::BlackIncrement { value } => {
old_value = GameOption::BlackIncrement {
value: self.time[Color::Black.to_index()].1,
};
self.time[Color::Black.to_index()].1 = value
}
GameOption::WhitePlayer { value } => {
old_value = GameOption::WhitePlayer {
value: self.player[Color::White.to_index()],
};
self.player[Color::White.to_index()] = value
}
GameOption::BlackPlayer { value } => {
old_value = GameOption::WhitePlayer {
value: self.player[Color::Black.to_index()],
};
self.player[Color::Black.to_index()] = value
}
}
old_value
@ -105,7 +132,7 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
/// Launch uci engine initialisation
///
/// Retrieve data from uci engine (until uciok command from engine)
pub fn init(&mut self){
pub fn init(&mut self) {
self.push(GuiCommand::Uci);
// Consume commands until uciok messages
@ -140,16 +167,17 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
/// uci.make_move(ChessMove::from_str("e2e4").expect("error converting e2e4"));
/// ```
pub fn make_move(&mut self, chess_move: ChessMove) -> bool {
if self.game.make_move(chess_move) {
self.push(GuiCommand::Position { position: Some(self.initial), moves: self.game.actions().to_vec() });
if self.game.make_move(chess_move) {
self.push(GuiCommand::Position {
position: Some(self.initial),
moves: self.game.actions().to_vec(),
});
true
} else {
false
}
}
fn terminate(&mut self, reason: &str) {
self.uciok = false;
info!("UCI termination: {}", reason);
@ -165,13 +193,17 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
self.id.author()
}
fn update(&mut self, id: &Id){
if self.is_uciok() {warn!("Engine info should not be updated now (uciok)");}
fn update(&mut self, id: &Id) {
if self.is_uciok() {
warn!("Engine info should not be updated now (uciok)");
}
self.id.update(id);
}
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)");}
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);
}
@ -180,17 +212,20 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
/// if `EngineCommand::Id`: update name or authorship of the engine
/// if `EngineCommand::UciOk`: end engine initialization phase
pub fn exec(&mut self, command: &str) -> Result<EngineCommand, &'static str> {
let uci_command = parse (&mut command.to_string());
match uci_command.clone() {
Ok(EngineCommand::Id{id}) => self.update(&id),
let uci_command = parse(&mut command.to_string());
match uci_command.clone() {
Ok(EngineCommand::Id { id }) => self.update(&id),
Ok(EngineCommand::UciOk) => self.uciok(),
Ok(EngineCommand::Opt { options: _ }) => {},
Ok(EngineCommand::Info { infos: _ }) |
Ok(EngineCommand::BestMove { best_move: _, ponder: _ }) |
Ok(EngineCommand::ReadyOk)
=> {},
Ok(EngineCommand::Registration)|
Ok(EngineCommand::CopyProtection)=> {unimplemented!("command not implemented")},
Ok(EngineCommand::Opt { options: _ }) => {}
Ok(EngineCommand::Info { infos: _ })
| Ok(EngineCommand::BestMove {
best_move: _,
ponder: _,
})
| Ok(EngineCommand::ReadyOk) => {}
Ok(EngineCommand::Registration) | Ok(EngineCommand::CopyProtection) => {
unimplemented!("command not implemented")
}
Err(_) => warn!("Not a command"),
};
uci_command
@ -198,16 +233,21 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
/// Retrieve a line from the uci engine input stream and parse it
pub fn pull(&mut self) -> Option<EngineCommand> {
if let Some(source) = &mut self.source {
let mut command = String::new();
match source.read_line(&mut command) {
Ok(0) => {self.terminate("Chess engine closed connection."); None},
Ok(0) => {
self.terminate("Chess engine closed connection.");
None
}
Ok(_) => {
info!("← {}", command);
self.exec(&command).ok()
},
Err(reason) => {warn!("Unable to read from engine: {reason}"); None},
}
Err(reason) => {
warn!("Unable to read from engine: {reason}");
None
}
}
} else {
info!("❌ No connected uci engine");
@ -220,9 +260,18 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
if let Some(source) = &mut self.source {
let mut data = String::new();
match source.read_line(&mut data) {
Ok(0) => {self.terminate("Chess engine closed connection."); None},
Ok(_) => {info!("↜ {}", data); Some(data.clone())},
Err(reason) => {warn!("Unable to read from engine: {reason}"); None},
Ok(0) => {
self.terminate("Chess engine closed connection.");
None
}
Ok(_) => {
info!("↜ {}", data);
Some(data.clone())
}
Err(reason) => {
warn!("Unable to read from engine: {reason}");
None
}
}
} else {
info!("❌ No connected uci engine");
@ -234,7 +283,7 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
pub fn push(&mut self, command: GuiCommand) {
if let Some(destination) = &mut self.destination {
let command_str = command.to_string();
match destination.write(command_str.as_bytes()){
match 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}"),
@ -245,7 +294,7 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
}
/// Push string (not a game manager integrated command) to the Uci engine output stream
pub fn push_raw(&mut self, data: &str){
pub fn push_raw(&mut self, data: &str) {
if let Some(destination) = &mut self.destination {
match destination.write(data.as_bytes()) {
Ok(n) if n == data.len() => info!("↝ raw: {data}"),
@ -258,8 +307,8 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
}
}
impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
fn uciok(&mut self){
impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
fn uciok(&mut self) {
self.uciok = true;
}
@ -270,30 +319,38 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
pub fn human_play(&mut self, chess_move: ChessMove) -> Result<ChessMove, &'static str> {
match self.player[self.side_to_move().to_index()] {
Player::Human{..} => {
Player::Human { .. } => {
if self.make_move(chess_move) {
Ok(chess_move)
} else {
Err("Invalid move for human player")
}
},
Player::Machine {..} => Err("Not a human to play for current color.")
}
Player::Machine { .. } => Err("Not a human to play for current color."),
}
}
pub fn go(&mut self) -> Result<(), &'static str> {
match self.player[self.side_to_move().to_index()] {
Player::Human{..} => Err("Not a machine to play for current color."),
Player::Machine {elo} =>
{
Player::Human { .. } => Err("Not a machine to play for current color."),
Player::Machine { elo } => {
if self.is_uciok() {
if let Some(elo) = elo {
self.push(GuiCommand::SetOption {option: Opt::UCILimitStrength{value: true}});
self.push(GuiCommand::SetOption {option: Opt::UCIElo{value: elo}});
self.push(GuiCommand::SetOption {
option: Opt::UCILimitStrength { value: true },
});
self.push(GuiCommand::SetOption {
option: Opt::UCIElo { value: elo },
});
}
let (wtime, wincr) = self.time[Color::White.to_index()];
let (btime, bincr) = self.time[Color::Black.to_index()];
self.push(GuiCommand::Go{wtime, wincr, btime, bincr});
self.push(GuiCommand::Go {
wtime,
wincr,
btime,
bincr,
});
Ok(())
} else {
@ -302,10 +359,19 @@ impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
}
}
}
pub fn stop(&mut self) -> Result<(), &'static str> {
match self.player[self.side_to_move().to_index()] {
Player::Human { .. } => Err("Not a machine to play for current color."),
Player::Machine { .. } => {
self.push(GuiCommand::Stop);
Ok(())
}
}
}
}
use chess::{Square, Piece, Color};
impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
use chess::{Color, Piece, Square};
impl<Fi: Read, Fo: Write> UciEngine<Fi, Fo> {
pub fn piece_on(&self, square: Square) -> Option<Piece> {
self.game.current_position().piece_on(square)
}

View File

@ -1,20 +1,31 @@
use itertools::join;
use std::{time::Duration, str::FromStr};
use std::fmt;
use std::{str::FromStr, time::Duration};
use chess::{ChessMove, Board, Action};
use chess::{Action, Board, ChessMove};
#[derive(Clone, Default)]
pub struct Id {name: Option<String>, author: Option<String>}
pub struct Id {
name: Option<String>,
author: Option<String>,
}
impl Id {
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(&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 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> {
@ -28,10 +39,10 @@ impl Id {
#[derive(Debug, Clone)]
pub struct Info {}
#[derive(Debug, Clone)]
pub enum Opt{
UCILimitStrength{value: bool},
UCIElo{value: u32},
SlowMover{value: u32},
pub enum Opt {
UCILimitStrength { value: bool },
UCIElo { value: u32 },
SlowMover { value: u32 },
}
impl Opt {
pub fn name(&self) -> &str {
@ -43,7 +54,7 @@ impl Opt {
}
}
impl fmt::Display for Opt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Opt::UCILimitStrength { value } => write!(f, "{value}"),
Opt::UCIElo { value } => write!(f, "{value}"),
@ -54,91 +65,160 @@ impl fmt::Display for Opt {
#[derive(Clone)]
pub enum EngineCommand {
Id{id: Id},
Id {
id: Id,
},
UciOk,
ReadyOk,
BestMove{best_move: ChessMove, ponder: Option<ChessMove>},
BestMove {
best_move: ChessMove,
ponder: Option<ChessMove>,
},
CopyProtection, // unimplemented
Registration, // unimplemented
Info{infos: Vec<Info>},
Opt{options: Vec<Opt>},
Registration, // unimplemented
Info {
infos: Vec<Info>,
},
Opt {
options: Vec<Opt>,
},
}
#[derive(Debug)]
pub enum GuiCommand {
Uci,
Debug{mode: bool},
Debug {
mode: bool,
},
IsReady,
SetOption{option: Opt},
SetOption {
option: Opt,
},
Register, // unimplemented
UciNewGame,
Position{position: Option<Board>, moves: Vec<Action>},
Go{wtime: Option<Duration>, wincr: Option<Duration>,
btime: Option<Duration>, bincr: Option<Duration>},
Position {
position: Option<Board>,
moves: Vec<Action>,
},
Go {
wtime: Option<Duration>,
wincr: Option<Duration>,
btime: Option<Duration>,
bincr: Option<Duration>,
},
Stop,
PonderHit,
Quit,
}
pub fn parse(message: &mut str) -> Result<EngineCommand,&'static str> {
pub fn parse(message: &mut str) -> 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::default(); id.update_from_str(Some(&join(tail, " ")), None); id}}),
["author", tail @ ..] => Ok(EngineCommand::Id{id: { let mut id = Id::default(); id.update_from_str(None, Some(&join(tail, " "))); id}}),
_ => Err("Invalid id subcommand")
},
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::default();
id.update_from_str(Some(&join(tail, " ")), None);
id
},
}),
["author", tail @ ..] => Ok(EngineCommand::Id {
id: {
let mut id = Id::default();
id.update_from_str(None, Some(&join(tail, " ")));
id
},
}),
_ => Err("Invalid id subcommand"),
},
Some("uciok") => Ok(EngineCommand::UciOk),
Some("readyok") => unimplemented!(),
Some("bestmove") =>
match message_iter.collect::<Vec<&str>>().as_slice() {
[] => Err("Empty bestmove command"),
[chessmove] => Ok(EngineCommand::BestMove { best_move: ChessMove::from_str(chessmove).expect("chessmove is invalid"), ponder: None }),
[_, "ponder"] => Err("Empty ponder in bestmove command"),
[chessmove, "ponder", chess_ponder] => Ok(EngineCommand::BestMove {
best_move: ChessMove::from_str(chessmove).expect("chessmove is invalid"),
ponder: Some(ChessMove::from_str(chess_ponder).expect("chessmove ponder is invalid")) }),
_ => Err("Invalid chessmove subcommand")
Some("bestmove") => match message_iter.collect::<Vec<&str>>().as_slice() {
[] => Err("Empty bestmove command"),
[chessmove] => Ok(EngineCommand::BestMove {
best_move: ChessMove::from_str(chessmove).expect("chessmove is invalid"),
ponder: None,
}),
[_, "ponder"] => Err("Empty ponder in bestmove command"),
[chessmove, "ponder", chess_ponder] => Ok(EngineCommand::BestMove {
best_move: ChessMove::from_str(chessmove).expect("chessmove is invalid"),
ponder: Some(
ChessMove::from_str(chess_ponder).expect("chessmove ponder is invalid"),
),
}),
_ => Err("Invalid chessmove subcommand"),
},
Some("copyprotection") => unimplemented!(),
Some("registration") => unimplemented!(),
Some("info") => Ok(EngineCommand::Info { infos: Vec::new() }), //todo!("parse info lines")
Some("option") => Ok(EngineCommand::Opt { options: Vec::new() }), // todo!("Parse options lines")
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{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
GuiCommand::Uci => writeln!(f, "uci"),
GuiCommand::UciNewGame => writeln!(f, "ucinewgame"),
GuiCommand::Position { position, moves } => {
writeln!(f, "position {} moves {}",
match position { None => "startpos".to_string(),
Some(board) if *board == Board::default() => "startpos".to_string(),
Some(board) =>"fen ".to_string() + &board.to_string()},
join(moves.iter().map(|x| if let Action::MakeMove(chessmove) = x
{" ".to_string() + &chessmove.to_string()} else {"".to_string()}), "")
writeln!(
f,
"position {} moves {}",
match position {
None => "startpos".to_string(),
Some(board) if *board == Board::default() => "startpos".to_string(),
Some(board) => "fen ".to_string() + &board.to_string(),
},
join(
moves
.iter()
.map(|x| if let Action::MakeMove(chessmove) = x {
" ".to_string() + &chessmove.to_string()
} else {
"".to_string()
}),
""
)
)
}
GuiCommand::SetOption { option } => {
writeln!(f, "setoption name {} value {}", option.name(), option)
writeln!(f, "setoption name {} value {}", option.name(), option)
}
GuiCommand::Go { wtime, wincr, btime, bincr } => {
let wtime = if let Some(wtime) = wtime {format!(" wtime {}", wtime.as_millis())} else {"".to_string()};
let btime = if let Some(btime) = btime {format!(" btime {}", btime.as_millis())} else {"".to_string()};
let wincr = if let Some(wincr) = wincr {format!(" wincr {}", wincr.as_millis())} else {"".to_string()};
let bincr = if let Some(bincr) = bincr {format!(" bincr {}", bincr.as_millis())} else {"".to_string()};
GuiCommand::Go {
wtime,
wincr,
btime,
bincr,
} => {
let wtime = if let Some(wtime) = wtime {
format!(" wtime {}", wtime.as_millis())
} else {
"".to_string()
};
let btime = if let Some(btime) = btime {
format!(" btime {}", btime.as_millis())
} else {
"".to_string()
};
let wincr = if let Some(wincr) = wincr {
format!(" wincr {}", wincr.as_millis())
} else {
"".to_string()
};
let bincr = if let Some(bincr) = bincr {
format!(" bincr {}", bincr.as_millis())
} else {
"".to_string()
};
writeln!(f, "go{}{}{}{}", wtime, btime, wincr, bincr)
}
@ -146,9 +226,9 @@ impl fmt::Display for GuiCommand {
GuiCommand::PonderHit => writeln!(f, "ponderhit"),
GuiCommand::Quit => writeln!(f, "quit"),
GuiCommand::Register|GuiCommand::Debug { .. }|GuiCommand::IsReady
=> unimplemented!("{:?}", self),
GuiCommand::Register | GuiCommand::Debug { .. } | GuiCommand::IsReady => {
unimplemented!("{:?}", self)
}
}
}
}

View File

@ -2,13 +2,13 @@ extern crate chess;
extern crate chess_uci;
use chess::ChessMove;
use chess_uci::*;
use chess_uci::uci_command::EngineCommand;
use chess_uci::*;
use std::process::{Command, Stdio};
use std::str::FromStr;
pub fn main(){
pub fn main() {
env_logger::init();
println!("Launching hardcoded stockfish program (should be in PATH)");
@ -17,26 +17,47 @@ pub fn main(){
let process = match Command::new("stockfish")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn() {
Err(why) => panic!("couldn't spawn stockfish: {}", why),
Ok(process) => process,
};
.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 (sf_in, sf_out) = (
process.stdin.expect("Program stdin"),
process.stdout.expect("Program stdout"),
);
let mut uci = UciEngine::new(Some(sf_out), Some(sf_in));
uci.game_option(GameOption::WhitePlayer { value: Player::Human { elo: None } });
uci.game_option(GameOption::BlackPlayer { value: Player::Machine { elo: Some(1500) } });
uci.game_option(GameOption::WhitePlayer {
value: Player::Human { elo: None },
});
uci.game_option(GameOption::BlackPlayer {
value: Player::Machine { elo: Some(1500) },
});
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()});
uci.push(uci_command::GuiCommand::SetOption { option: uci_command::Opt::SlowMover { value: 11 }});
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()
}
);
uci.push(uci_command::GuiCommand::SetOption {
option: uci_command::Opt::SlowMover { value: 11 },
});
uci.new_game();
uci.push_raw("d\n");
uci.human_play(ChessMove::from_str("e2e4").expect("error converting e2e4")).expect("can not make human move");
uci.human_play(ChessMove::from_str("e2e4").expect("error converting e2e4"))
.expect("can not make human move");
uci.push_raw("d\n");
@ -46,8 +67,8 @@ pub fn main(){
match uci.pull() {
Some(EngineCommand::BestMove { best_move, .. }) => {
uci.make_move(best_move);
break
},
break;
}
Some(EngineCommand::Info { .. }) => continue,
_ => continue,
}