send uci info

This commit is contained in:
Moritz 2025-11-20 10:20:56 +01:00
parent d5b679b6bf
commit 711569b8e5
8 changed files with 118 additions and 59 deletions

View file

@ -1,5 +1,5 @@
use chess_engine::board::Board;
use chess_engine::movegen::picker::MoveGenerator;
use chess_engine::movegen::picker::MovePicker;
use chess_engine::movegen::legal_check::is_other_king_attacked;
use criterion::{criterion_group, criterion_main, Criterion};
@ -8,7 +8,7 @@ fn count_legal_moves_recursive(board: &mut Board, depth: u8) -> u64 {
return 1_u64;
}
let mut generator = MoveGenerator::new();
let mut generator = MovePicker::new();
let mut leaf_nodes = 0_u64;
while let Some(mv) = generator.next(board) {

View file

@ -99,7 +99,7 @@ def main():
try:
# The suite_score is still a raw float, e.g., 95.5
suite_score = float(suite_result.stdout.strip())
suite_score = float(suite_result.stdout.strip().splitlines()[-1].strip())
except ValueError:
print(f"Error: Could not convert suite output to a number.")
print(f"Received: '{suite_result.stdout}'")

View file

@ -3,6 +3,7 @@ use crate::r#move::Move;
use crate::search::alpha_beta;
use crate::tt::TranspositionTable; // Import TT
use std::time::{Instant, Duration};
use crate::uci::UCI;
pub struct Engine {
pub name: String,
@ -44,6 +45,7 @@ impl Engine {
let mut nodes = 0;
// Initial search at depth 1
let (mut opt_move, mut _score) = alpha_beta(
&mut self.board,
1,
@ -56,8 +58,12 @@ impl Engine {
&mut self.tt
);
// If we timed out immediately at depth 1 (very rare), opt_move might be None.
// But usually, we have at least one move here.
let mut depth = 2;
// Iterative Deepening
while start_time.elapsed() < time_limit {
let (new_move, new_score) = alpha_beta(
&mut self.board,
@ -71,19 +77,27 @@ impl Engine {
&mut self.tt
);
if start_time.elapsed() > time_limit {
// FIX: Only update if we actually got a move back (didn't timeout)
if let Some(mv) = new_move {
opt_move = Some(mv);
_score = new_score;
// Optional: Move send_info here to update the GUI after every completed depth
UCI::send_info(Some(depth as usize), Some(nodes), None, None, None, None);
} else {
// If new_move is None, the search was aborted due to time.
// We discard the partial results and stop increasing depth.
break;
}
opt_move = new_move;
_score = new_score;
depth += 1;
}
if let Some(mv) = opt_move {
mv.to_algebraic()
} else {
// Fallback: If even depth 1 failed (e.g. 0ms time limit), try to return *any* legal move
// or just return null if truly nothing works.
"null".to_string()
}
}

View file

@ -1,7 +1,8 @@
use chess_engine::engine::Engine;
use chess_engine::uci::uci_mainloop;
use chess_engine::uci::UCI;
fn main() {
let mut engine = Engine::new("Yakari".to_string(), "EiSiMo".to_string());
uci_mainloop(&mut engine);
let mut uci = UCI { engine };
uci.uci_mainloop();
}

View file

@ -1,6 +1,6 @@
use crate::board::Board;
use crate::movegen::non_sliders::{generate_king_moves, generate_knight_moves};
use crate::movegen::pawns::generate_pawn_moves;
use crate::movegen::non_sliders::*;
use crate::movegen::pawns::*;
use crate::movegen::sliders::*;
use crate::r#move::{Move, MoveList};
@ -30,12 +30,12 @@ impl GenStage {
}
}
pub struct MoveGenerator {
pub struct MovePicker {
buffer: MoveList,
stage: GenStage,
}
impl MoveGenerator {
impl MovePicker {
pub fn new() -> Self {
Self {
buffer: MoveList::new(),

View file

@ -2,7 +2,7 @@ use crate::board::{Board, Color};
use crate::eval::evaluate_board;
use crate::movegen::legal_check::*;
use crate::r#move::Move;
use crate::movegen::picker::MoveGenerator;
use crate::movegen::picker::MovePicker;
use crate::tt::{TranspositionTable, NodeType};
use std::time::{Instant, Duration};
@ -90,7 +90,7 @@ pub fn alpha_beta(
let mut legal_moves_found = false;
let alpha_orig = alpha;
let mut picker = MoveGenerator::new();
let mut picker = MovePicker::new();
let mut moves_tried = 0;
loop {

View file

@ -1,7 +1,13 @@
use std::io::{self, BufRead};
use crate::engine::Engine;
pub fn uci_mainloop(engine: &mut Engine) {
pub struct UCI {
// TODO lifetime specifier
pub engine: Engine,
}
impl UCI {
pub fn uci_mainloop(&mut self) {
loop {
for line in io::stdin().lock().lines() {
let input = line.unwrap_or_else(|_| "quit".to_string());
@ -13,8 +19,8 @@ pub fn uci_mainloop(engine: &mut Engine) {
match tokens[0] {
"uci" => {
println!("id name {}", engine.name);
println!("id author {}", engine.author);
println!("id name {}", self.engine.name);
println!("id author {}", self.engine.author);
println!("uciok");
}
"isready" => {
@ -27,18 +33,18 @@ pub fn uci_mainloop(engine: &mut Engine) {
if tokens.len() > 1 {
if tokens[1] == "fen" {
let fen = tokens[2..].join(" ");
engine.setpos_fen(&fen);
self.engine.setpos_fen(&fen);
} else if tokens[1] == "startpos" {
if tokens.len() > 2 && tokens[2] == "moves" {
engine.setpos_startpos(&tokens[3..]);
self.engine.setpos_startpos(&tokens[3..]);
} else {
engine.setpos_startpos(&[]);
self.engine.setpos_startpos(&[]);
}
}
}
}
"go" => {
println!("bestmove {}", engine.search(1000_u64));
println!("bestmove {}", self.engine.search(1000_u64));
}
"stop" => {
// TODO stop search as soon as possible
@ -53,3 +59,41 @@ pub fn uci_mainloop(engine: &mut Engine) {
}
}
}
pub fn send_info(
depth: Option<usize>,
nodes: Option<u64>,
time: Option<u64>,
nps: Option<u64>,
score_cp: Option<i32>,
pv: Option<&str>
) {
let mut output = String::from("info");
if let Some(d) = depth {
output.push_str(&format!(" depth {}", d));
}
if let Some(s) = score_cp {
output.push_str(&format!(" score cp {}", s));
}
if let Some(n) = nodes {
output.push_str(&format!(" nodes {}", n));
}
if let Some(n) = nps {
output.push_str(&format!(" nps {}", n));
}
if let Some(t) = time {
output.push_str(&format!(" time {}", t));
}
if let Some(p) = pv {
output.push_str(&format!(" pv {}", p));
}
println!("{}", output);
}
}

View file

@ -1,13 +1,13 @@
use chess_engine::board::Board;
use chess_engine::movegen::legal_check::is_other_king_attacked;
use chess_engine::movegen::picker::MoveGenerator;
use chess_engine::movegen::picker::MovePicker;
fn count_legal_moves_recursive(board: &mut Board, depth: u8) -> u64 {
if depth == 0 {
return 1_u64;
}
let mut generator = MoveGenerator::new();
let mut generator = MovePicker::new();
let mut leaf_nodes = 0_u64;
while let Some(mv) = generator.next(board) {