first working

This commit is contained in:
2026-05-23 15:06:10 -05:00
commit 764252b0c4
32 changed files with 9465 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
[package]
name = "uci"
version = "0.1.0"
edition = "2024"
[dependencies]
engine = { path = "../engine" }
chess = "3.2.0"
+216
View File
@@ -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();
}