Add main uci communcation loop, no tests
This commit is contained in:
125
src/uci.rs
125
src/uci.rs
@@ -1,25 +1,62 @@
|
|||||||
use std::str::SplitWhitespace;
|
use std::{
|
||||||
|
io::{self, BufRead, Write},
|
||||||
|
str::SplitWhitespace,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{game::Game, r#move::Move, search::search};
|
use crate::{game::Game, r#move::Move, search::search};
|
||||||
|
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
Uci,
|
Uci,
|
||||||
IsReady,
|
IsReady,
|
||||||
UciNewGame,
|
Position,
|
||||||
Position(String),
|
|
||||||
Go,
|
Go,
|
||||||
Stop,
|
|
||||||
Quit,
|
Quit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_command(parts: &mut SplitWhitespace) -> Result<Command, String> {
|
||||||
|
match parts.next() {
|
||||||
|
Some("uci") => Ok(Command::Uci),
|
||||||
|
Some("isready") => Ok(Command::IsReady),
|
||||||
|
Some("position") => Ok(Command::Position),
|
||||||
|
Some("go") => Ok(Command::Go),
|
||||||
|
Some("quit") => Ok(Command::Quit),
|
||||||
|
_ => Err("Unrecognised command".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum Response {
|
pub enum Response {
|
||||||
Id(String),
|
|
||||||
UciOk,
|
UciOk,
|
||||||
ReadyOk,
|
ReadyOk,
|
||||||
BestMove(String),
|
BestMove(String),
|
||||||
Info(String),
|
Info(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_response(handle_out: &mut impl Write, response: Response) -> Result<(), String> {
|
||||||
|
let output = match response {
|
||||||
|
Response::UciOk => "uciok".to_string(),
|
||||||
|
Response::ReadyOk => "readyok".to_string(),
|
||||||
|
Response::BestMove(best_move) => format!("bestmove {}", best_move),
|
||||||
|
Response::Info(info) => info,
|
||||||
|
};
|
||||||
|
|
||||||
|
writeln!(handle_out, "{}", output).map_err(|e| e.to_string())?;
|
||||||
|
handle_out.flush().map_err(|e| e.to_string())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
impl fmt::Display for Response {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::UciOk => write!(f, "uciok"),
|
||||||
|
Self::ReadyOk => write!(f, "readyok"),
|
||||||
|
Self::BestMove(best_move) => write!(f, "bestmove {}", best_move),
|
||||||
|
Self::Info(info) => write!(f, "{}", info),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct SearchParameters {
|
struct SearchParameters {
|
||||||
movetime: Option<usize>,
|
movetime: Option<usize>,
|
||||||
depth: Option<u8>,
|
depth: Option<u8>,
|
||||||
@@ -66,7 +103,7 @@ pub fn uci_position(mut position: SplitWhitespace) -> Result<Game, String> {
|
|||||||
|
|
||||||
const MAX_DEPTH: u8 = 5;
|
const MAX_DEPTH: u8 = 5;
|
||||||
|
|
||||||
pub fn uci_go(mut go: SplitWhitespace, game: &mut Game) -> Response {
|
pub fn uci_go(mut go: SplitWhitespace, game: &mut Game) -> Result<Move, String> {
|
||||||
let mut params = SearchParameters::new();
|
let mut params = SearchParameters::new();
|
||||||
while let Some(subcommand) = go.next() {
|
while let Some(subcommand) = go.next() {
|
||||||
match subcommand {
|
match subcommand {
|
||||||
@@ -75,9 +112,65 @@ pub fn uci_go(mut go: SplitWhitespace, game: &mut Game) -> Response {
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
search(game, params.depth.unwrap_or(MAX_DEPTH));
|
search(game, params.depth.unwrap_or(MAX_DEPTH));
|
||||||
Response::BestMove(String::from("value"))
|
|
||||||
|
Ok(Move::new(0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UciGame {
|
||||||
|
game: Option<Game>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UciGame {
|
||||||
|
const fn new() -> Self {
|
||||||
|
Self { game: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_game_state(&mut self, game: Game) {
|
||||||
|
self.game = Some(game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for UciGame {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uci_loop() -> Result<(), String> {
|
||||||
|
let stdin = io::stdin();
|
||||||
|
let stdout = io::stdout();
|
||||||
|
let handle_in = stdin.lock();
|
||||||
|
let mut handle_out = stdout.lock();
|
||||||
|
let mut uci_game = UciGame::new();
|
||||||
|
|
||||||
|
for line in handle_in.lines() {
|
||||||
|
let line_str = line.unwrap_or_else(|_| "quit".to_string());
|
||||||
|
let mut parts = line_str.split_whitespace();
|
||||||
|
let command = parse_command(&mut parts)?;
|
||||||
|
let response = match command {
|
||||||
|
Command::Uci => Response::UciOk,
|
||||||
|
Command::IsReady => Response::ReadyOk,
|
||||||
|
Command::Position => {
|
||||||
|
uci_game.set_game_state(uci_position(parts)?);
|
||||||
|
Response::Info("Initialized position.".to_string())
|
||||||
|
}
|
||||||
|
Command::Go => {
|
||||||
|
if let Some(ref mut game) = uci_game.game {
|
||||||
|
let best_move = uci_go(parts, game)?;
|
||||||
|
Response::BestMove(best_move.parse_into_str())
|
||||||
|
} else {
|
||||||
|
Response::Info("Going!".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Command::Quit => break,
|
||||||
|
};
|
||||||
|
|
||||||
|
write_response(&mut handle_out, response)?;
|
||||||
|
handle_out.flush().map_err(|e| e.to_string())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -90,8 +183,20 @@ mod tests {
|
|||||||
fn test_uci_position() -> Result<(), String> {
|
fn test_uci_position() -> Result<(), String> {
|
||||||
let mut _game = from_fen(FEN[0])?;
|
let mut _game = from_fen(FEN[0])?;
|
||||||
|
|
||||||
// check that the board state is as expected after using uci position and compare
|
Ok(())
|
||||||
// with a separate fen that created the update instance by itself
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uci_go() -> Result<(), String> {
|
||||||
|
let mut _game = from_fen(FEN[0])?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uci_loop() -> Result<(), String> {
|
||||||
|
let mut _game = from_fen(FEN[0])?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user