first working
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "uci"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
engine = { path = "../engine" }
|
||||
chess = "3.2.0"
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
use chess::{ChessMove, Game};
|
||||
use engine::{legal_action_mask, Engine};
|
||||
use std::io;
|
||||
use std::str::FromStr;
|
||||
|
||||
const ENGINE_NAME: &str = "Chess Dragon";
|
||||
const ENGINE_AUTHOR: &str = "Drake Marino";
|
||||
|
||||
|
||||
|
||||
pub fn uci_loop() {
|
||||
let stdin = io::stdin();
|
||||
|
||||
let mut game = Game::new();
|
||||
let mut engine = Engine::default();
|
||||
|
||||
|
||||
loop {
|
||||
let mut input = String::new();
|
||||
if stdin.read_line(&mut input).is_err() {
|
||||
break;
|
||||
}
|
||||
|
||||
let input = input.trim();
|
||||
if input.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let parts: Vec<&str> = input.split_whitespace().collect();
|
||||
let command = parts[0];
|
||||
match command {
|
||||
"uci" => uci_uci(),
|
||||
"id" => uci_id(),
|
||||
"option" => uci_option(),
|
||||
"setoption" => uci_setoption(input),
|
||||
"ucinewgame" => uci_ucinewgame(&mut game),
|
||||
"position" => uci_position(input, &mut game),
|
||||
"go" => uci_go(input, &mut game, &mut engine),
|
||||
_ => panic!("Invalid command!"),
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// UCI Commands
|
||||
|
||||
fn uci_id() {
|
||||
println!("id name {}", ENGINE_NAME);
|
||||
println!("id author {}", ENGINE_AUTHOR);
|
||||
}
|
||||
|
||||
fn uci_option() {
|
||||
// none currently implemented
|
||||
}
|
||||
|
||||
fn uci_uci() {
|
||||
uci_id();
|
||||
uci_option();
|
||||
println!("uciok");
|
||||
}
|
||||
|
||||
fn uci_setoption(input: &str) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
fn uci_ucinewgame(game: &mut Game) {
|
||||
*game = Game::new();
|
||||
}
|
||||
|
||||
fn uci_position(input: &str, game: &mut Game) {
|
||||
let mut tokens = input.split_whitespace();
|
||||
|
||||
if tokens.next().unwrap() != "position" {
|
||||
panic!("position command not provided!");
|
||||
}
|
||||
|
||||
let moves: Vec<String>;
|
||||
|
||||
match tokens.next().unwrap() {
|
||||
"startpos" => {
|
||||
*game = Game::new();
|
||||
moves = tokens.skip_while(|&t| t != "moves").skip(1).map(|s| s.to_string()).collect();
|
||||
}
|
||||
"fen" => {
|
||||
// FEN has 6 space-separated fields
|
||||
let fen_fields: Vec<&str> = tokens.by_ref().take(6).collect();
|
||||
if fen_fields.len() != 6 {
|
||||
panic!("fen field invalid!");
|
||||
}
|
||||
let fen = fen_fields.join(" ");
|
||||
*game = Game::from_str(&fen).expect("Invalid board position");
|
||||
moves = tokens.skip_while(|&t| t != "moves").skip(1).map(|s| s.to_string()).collect();
|
||||
}
|
||||
_ => panic!("Position command invalid!"),
|
||||
}
|
||||
|
||||
for mv in moves {
|
||||
game.make_move(ChessMove::from_str(&mv).expect("Invalid move!"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn uci_go(input: &str, game: &mut Game, engine: &mut Engine) {
|
||||
let parts: Vec<&str> = input.split_whitespace().collect();
|
||||
|
||||
let mut wtime = None;
|
||||
let mut btime = None;
|
||||
let mut winc = None;
|
||||
let mut binc = None;
|
||||
let mut movetime = None;
|
||||
let mut max_depth = None;
|
||||
let mut max_nodes = None;
|
||||
|
||||
let mut i = 1; // Skip "go"
|
||||
while i < parts.len() {
|
||||
match parts[i] {
|
||||
"wtime" => {
|
||||
if i + 1 < parts.len() {
|
||||
wtime = parts[i + 1].parse::<u64>().ok();
|
||||
i += 2;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
"btime" => {
|
||||
if i + 1 < parts.len() {
|
||||
btime = parts[i + 1].parse::<u64>().ok();
|
||||
i += 2;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
"winc" => {
|
||||
if i + 1 < parts.len() {
|
||||
winc = parts[i + 1].parse::<u64>().ok();
|
||||
i += 2;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
"binc" => {
|
||||
if i + 1 < parts.len() {
|
||||
binc = parts[i + 1].parse::<u64>().ok();
|
||||
i += 2;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
"movetime" => {
|
||||
if i + 1 < parts.len() {
|
||||
movetime = parts[i + 1].parse::<u64>().ok();
|
||||
i += 2;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
"depth" => {
|
||||
if i + 1 < parts.len() {
|
||||
max_depth = parts[i + 1].parse::<u16>().ok();
|
||||
i += 2;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
"infinite" => {
|
||||
max_depth = Some(100);
|
||||
i += 1;
|
||||
}
|
||||
"nodes" => {
|
||||
if i + 1 < parts.len() {
|
||||
max_nodes = parts[i + 1].parse::<usize>().ok();
|
||||
i += 2;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update search settings
|
||||
if let Some(wt) = wtime {
|
||||
engine.search_settings.wtime = wt;
|
||||
}
|
||||
if let Some(bt) = btime {
|
||||
engine.search_settings.btime = bt;
|
||||
}
|
||||
if let Some(wi) = winc {
|
||||
engine.search_settings.winc = wi;
|
||||
}
|
||||
if let Some(bi) = binc {
|
||||
engine.search_settings.binc = bi;
|
||||
}
|
||||
if let Some(mt) = movetime {
|
||||
engine.search_settings.movetime = Some(mt);
|
||||
}
|
||||
if let Some(max_depth) = max_depth {
|
||||
engine.search_settings.max_depth = Some(max_depth);
|
||||
}
|
||||
if let Some(nodes) = max_nodes {
|
||||
engine.search_settings.max_nodes = Some(nodes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn main() {
|
||||
uci_loop();
|
||||
}
|
||||
Reference in New Issue
Block a user