Fix uci_position bugs and add test
This commit is contained in:
71
src/uci.rs
71
src/uci.rs
@@ -3,11 +3,13 @@ use std::{
|
|||||||
str::SplitWhitespace,
|
str::SplitWhitespace,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{game::Game, r#move::Move, search::search};
|
use crate::{game::Game, r#move::Move, search::search, square::Square};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
Uci,
|
Uci,
|
||||||
IsReady,
|
IsReady,
|
||||||
|
UciNewGame,
|
||||||
Position,
|
Position,
|
||||||
Go,
|
Go,
|
||||||
Quit,
|
Quit,
|
||||||
@@ -17,6 +19,7 @@ fn parse_command(parts: &mut SplitWhitespace) -> Result<Command, String> {
|
|||||||
match parts.next() {
|
match parts.next() {
|
||||||
Some("uci") => Ok(Command::Uci),
|
Some("uci") => Ok(Command::Uci),
|
||||||
Some("isready") => Ok(Command::IsReady),
|
Some("isready") => Ok(Command::IsReady),
|
||||||
|
Some("ucinewgame") => Ok(Command::UciNewGame),
|
||||||
Some("position") => Ok(Command::Position),
|
Some("position") => Ok(Command::Position),
|
||||||
Some("go") => Ok(Command::Go),
|
Some("go") => Ok(Command::Go),
|
||||||
Some("quit") => Ok(Command::Quit),
|
Some("quit") => Ok(Command::Quit),
|
||||||
@@ -32,14 +35,7 @@ pub enum Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_response(handle_out: &mut impl Write, response: Response) -> Result<(), String> {
|
fn write_response(handle_out: &mut impl Write, response: Response) -> Result<(), String> {
|
||||||
let output = match response {
|
writeln!(handle_out, "{}", response).map_err(|e| e.to_string())?;
|
||||||
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())?;
|
handle_out.flush().map_err(|e| e.to_string())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -49,7 +45,7 @@ use std::fmt;
|
|||||||
impl fmt::Display for Response {
|
impl fmt::Display for Response {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::UciOk => write!(f, "uciok"),
|
Self::UciOk => write!(f, "id name ippos\nid author stefiosif\nuciok"),
|
||||||
Self::ReadyOk => write!(f, "readyok"),
|
Self::ReadyOk => write!(f, "readyok"),
|
||||||
Self::BestMove(best_move) => write!(f, "bestmove {}", best_move),
|
Self::BestMove(best_move) => write!(f, "bestmove {}", best_move),
|
||||||
Self::Info(info) => write!(f, "{}", info),
|
Self::Info(info) => write!(f, "{}", info),
|
||||||
@@ -91,7 +87,7 @@ impl Default for UciParameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uci_position(mut position: SplitWhitespace) -> Result<Game, String> {
|
pub fn uci_position(position: &mut SplitWhitespace) -> Result<Game, String> {
|
||||||
let state = position.next().ok_or("Expected startpos or fen")?;
|
let state = position.next().ok_or("Expected startpos or fen")?;
|
||||||
let mut game = match state {
|
let mut game = match state {
|
||||||
"startpos" => Game::new(),
|
"startpos" => Game::new(),
|
||||||
@@ -99,6 +95,10 @@ pub fn uci_position(mut position: SplitWhitespace) -> Result<Game, String> {
|
|||||||
_ => return Err("Expected startpos or fen".to_string()),
|
_ => return Err("Expected startpos or fen".to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if Some("moves") != position.next() {
|
||||||
|
return Ok(game);
|
||||||
|
}
|
||||||
|
|
||||||
for mv_str in position {
|
for mv_str in position {
|
||||||
let mv = Move::parse_from_str(mv_str)?;
|
let mv = Move::parse_from_str(mv_str)?;
|
||||||
game.board.make_move(&mv, game.board.state.next_turn());
|
game.board.make_move(&mv, game.board.state.next_turn());
|
||||||
@@ -109,18 +109,28 @@ 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) -> Result<Move, String> {
|
pub fn uci_go(go: &mut SplitWhitespace, game: &mut Game) -> Result<Move, String> {
|
||||||
let mut params = UciParameters::new();
|
let mut params = UciParameters::new();
|
||||||
while let Some(subcommand) = go.next() {
|
while let Some(subcommand) = go.next() {
|
||||||
match subcommand {
|
match subcommand {
|
||||||
"depth" => params.add_depth(go.next().unwrap().parse::<u8>().ok().unwrap()),
|
"depth" => {
|
||||||
"movetime" => params.add_movetime(go.next().unwrap().parse::<usize>().ok().unwrap()),
|
let depth_str = go.next().ok_or("Expected depth value")?;
|
||||||
|
let depth = depth_str.parse::<u8>().map_err(|_| "Invalid depth value")?;
|
||||||
|
params.add_depth(depth);
|
||||||
|
}
|
||||||
|
"movetime" => {
|
||||||
|
let movetime_str = go.next().ok_or("Expected movetime value")?;
|
||||||
|
let movetime = movetime_str
|
||||||
|
.parse::<usize>()
|
||||||
|
.map_err(|_| "Invalid movetime value")?;
|
||||||
|
params.add_movetime(movetime);
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
search(game, params.depth.unwrap_or(MAX_DEPTH));
|
search(game, params.depth.unwrap_or(MAX_DEPTH));
|
||||||
|
|
||||||
Ok(Move::new(0, 0))
|
Ok(Move::new(Square::B8, Square::C6))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uci_loop() -> Result<(), String> {
|
pub fn uci_loop() -> Result<(), String> {
|
||||||
@@ -137,13 +147,14 @@ pub fn uci_loop() -> Result<(), String> {
|
|||||||
let response = match command {
|
let response = match command {
|
||||||
Command::Uci => Response::UciOk,
|
Command::Uci => Response::UciOk,
|
||||||
Command::IsReady => Response::ReadyOk,
|
Command::IsReady => Response::ReadyOk,
|
||||||
|
Command::UciNewGame => Response::Info("Clear cached game.".to_string()),
|
||||||
Command::Position => {
|
Command::Position => {
|
||||||
params.add_game(uci_position(parts)?);
|
params.add_game(uci_position(&mut parts)?);
|
||||||
Response::Info("Initialized position.".to_string())
|
Response::Info("Initialized position.".to_string())
|
||||||
}
|
}
|
||||||
Command::Go => {
|
Command::Go => {
|
||||||
if let Some(ref mut game) = params.game {
|
if let Some(ref mut game) = params.game {
|
||||||
let best_move = uci_go(parts, game)?;
|
let best_move = uci_go(&mut parts, game)?;
|
||||||
Response::BestMove(best_move.parse_into_str())
|
Response::BestMove(best_move.parse_into_str())
|
||||||
} else {
|
} else {
|
||||||
Response::Info("Going!".to_string())
|
Response::Info("Going!".to_string())
|
||||||
@@ -161,13 +172,33 @@ pub fn uci_loop() -> Result<(), String> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::fen::from_fen;
|
use crate::{
|
||||||
|
fen::from_fen,
|
||||||
|
uci::{parse_command, Command},
|
||||||
|
};
|
||||||
|
|
||||||
const FEN: [&str; 1] = ["r3k2r/2p1p1qp/2npb3/1p3p2/p3P1pP/P1PB1Q2/1P1PNPP1/R3K2R w KQkq - 0 1"];
|
use super::uci_position;
|
||||||
|
|
||||||
|
const FEN: [&str; 2] = [
|
||||||
|
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
||||||
|
"r1bqkbnr/pppppppp/2n4B/8/3P4/8/PPP1PPPP/RN1QKBNR b KQkq - 2 2",
|
||||||
|
];
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_uci_position() -> Result<(), String> {
|
fn test_uci_position() -> Result<(), String> {
|
||||||
let mut _game = from_fen(FEN[0])?;
|
let command_position = "position startpos";
|
||||||
|
let mut parts = command_position.split_whitespace();
|
||||||
|
let command = parse_command(&mut parts)?;
|
||||||
|
|
||||||
|
assert_eq!(command, Command::Position);
|
||||||
|
assert_eq!(from_fen(FEN[0]).unwrap(), uci_position(&mut parts)?);
|
||||||
|
|
||||||
|
let command_position_moves = "position startpos moves d2d4 b8c6 c1h6";
|
||||||
|
let mut parts = command_position_moves.split_whitespace();
|
||||||
|
let command = parse_command(&mut parts)?;
|
||||||
|
|
||||||
|
assert_eq!(command, Command::Position);
|
||||||
|
assert_eq!(from_fen(FEN[1]).unwrap(), uci_position(&mut parts)?);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user