Add uci movetime, hash and initialize TT based on size in MBs
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io::{BufRead, Write},
|
||||
str::SplitWhitespace,
|
||||
};
|
||||
@@ -13,7 +14,7 @@ use crate::{
|
||||
movegen::r#move::Move,
|
||||
search::{
|
||||
iterative_deepening, time::TimeInfo, transposition_table::TranspositionTable, INC,
|
||||
MAX_DEPTH, MAX_TT_SIZE, TIME,
|
||||
MAX_DEPTH, TIME,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -26,6 +27,7 @@ pub enum Command {
|
||||
Go,
|
||||
Stop,
|
||||
Quit,
|
||||
SetOption,
|
||||
}
|
||||
|
||||
fn parse_command(parts: &mut SplitWhitespace) -> anyhow::Result<Command> {
|
||||
@@ -37,6 +39,7 @@ fn parse_command(parts: &mut SplitWhitespace) -> anyhow::Result<Command> {
|
||||
Some("go") => Ok(Command::Go),
|
||||
Some("stop") => Ok(Command::Stop),
|
||||
Some("quit") => Ok(Command::Quit),
|
||||
Some("setoption") => Ok(Command::SetOption),
|
||||
_ => bail!("Unrecognised command"),
|
||||
}
|
||||
}
|
||||
@@ -75,10 +78,11 @@ struct UciParameters {
|
||||
btime: Option<u128>,
|
||||
winc: Option<u128>,
|
||||
binc: Option<u128>,
|
||||
options: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl UciParameters {
|
||||
const fn new() -> Self {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
depth: None,
|
||||
game: None,
|
||||
@@ -86,9 +90,15 @@ impl UciParameters {
|
||||
btime: None,
|
||||
winc: None,
|
||||
binc: None,
|
||||
options: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_move_time(&mut self, movetime: u128) {
|
||||
self.wtime = Some(movetime);
|
||||
self.btime = Some(movetime);
|
||||
}
|
||||
|
||||
fn add_depth(&mut self, depth: u8) {
|
||||
self.depth = Some(depth);
|
||||
}
|
||||
@@ -112,6 +122,10 @@ impl UciParameters {
|
||||
fn add_game(&mut self, game: Game) {
|
||||
self.game = Some(game);
|
||||
}
|
||||
|
||||
fn add_option(&mut self, name: String, value: String) {
|
||||
self.options.insert(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for UciParameters {
|
||||
@@ -156,6 +170,7 @@ pub fn uci_go(go_iter: &mut SplitWhitespace, game: &mut Game) -> anyhow::Result<
|
||||
"winc" => params.add_winc(parse_next(go_iter, "winc")?),
|
||||
"binc" => params.add_binc(parse_next(go_iter, "binc")?),
|
||||
"depth" => params.add_depth(parse_next(go_iter, "depth")?),
|
||||
"movetime" => params.add_move_time(parse_next(go_iter, "movetime")?),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@@ -173,9 +188,34 @@ pub fn uci_go(go_iter: &mut SplitWhitespace, game: &mut Game) -> anyhow::Result<
|
||||
.ok_or_else(|| anyhow!("No stored best move found"))
|
||||
}
|
||||
|
||||
fn parse_next<T: std::str::FromStr>(go_iter: &mut SplitWhitespace, val: &str) -> anyhow::Result<T> {
|
||||
go_iter
|
||||
.next()
|
||||
fn uci_option(option_iter: &mut SplitWhitespace, game: &mut Game) -> anyhow::Result<()> {
|
||||
let mut params = UciParameters::new();
|
||||
|
||||
//TODO: Implement the rest of the options and refactor
|
||||
while let Some(subcommand) = option_iter.next() {
|
||||
if subcommand == "name" {
|
||||
let name: String = parse_next(option_iter, "name")?;
|
||||
option_iter.next();
|
||||
let value: String = parse_next(option_iter, "value")?;
|
||||
params.add_option(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(name) = params.options.get("name") {
|
||||
if name == "Hash" {
|
||||
let value = params.options.get("value").expect("Expected key value");
|
||||
let size = value
|
||||
.parse::<usize>()
|
||||
.map_err(|_| anyhow!("Invalid value for Hash"))?;
|
||||
game.tt = TranspositionTable::new_with_mb_size(size);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_next<T: std::str::FromStr>(iter: &mut SplitWhitespace, val: &str) -> anyhow::Result<T> {
|
||||
iter.next()
|
||||
.ok_or_else(|| anyhow!("Expected {val}"))
|
||||
.and_then(|v| v.parse::<T>().map_err(|_| anyhow!("Invalid {val}")))
|
||||
}
|
||||
@@ -192,18 +232,14 @@ pub fn uci_loop<R: BufRead, W: Write>(input: R, mut output: W) -> anyhow::Result
|
||||
Command::IsReady => write_response(&mut output, &Response::ReadyOk)?,
|
||||
Command::UciNewGame => {
|
||||
if let Some(game) = params.game.as_mut() {
|
||||
game.tt = TranspositionTable::new(MAX_TT_SIZE);
|
||||
game.tt = TranspositionTable::new();
|
||||
game.board = Board::startpos();
|
||||
} else {
|
||||
let game = Game::new();
|
||||
params.add_game(game);
|
||||
}
|
||||
write_response(&mut output, &Response::Info("Clear cache".to_string()))?;
|
||||
}
|
||||
Command::Position => {
|
||||
//TODO: doesnt have to create a new game every time, we can just update the game
|
||||
params.add_game(uci_position(&mut parts)?);
|
||||
}
|
||||
Command::Position => params.add_game(uci_position(&mut parts)?),
|
||||
Command::Go => {
|
||||
if let Some(game) = params.game.as_mut() {
|
||||
match uci_go(&mut parts, game) {
|
||||
@@ -222,6 +258,14 @@ pub fn uci_loop<R: BufRead, W: Write>(input: R, mut output: W) -> anyhow::Result
|
||||
}
|
||||
Command::Stop => break,
|
||||
Command::Quit => break,
|
||||
Command::SetOption => {
|
||||
if let Some(game) = params.game.as_mut() {
|
||||
uci_option(&mut parts, game)?;
|
||||
} else {
|
||||
let game = Game::new();
|
||||
params.add_game(game);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
output.flush().map_err(|e| anyhow!(e))?
|
||||
@@ -299,7 +343,6 @@ mod tests {
|
||||
let expected_response = "id name zeal\n\
|
||||
id author stefiosif\n\
|
||||
uciok\n\
|
||||
Clear cache\n\
|
||||
bestmove e3f2\n";
|
||||
let actual_response = String::from_utf8(output).expect("Invalid UTF-8 in output");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user