use std::{io::stdin, thread::{Builder, JoinHandle, spawn, sleep}, str::Split, time::Duration}; use crate::{board::{Board, io::IO, color::Color}, moves::Move}; use super::Grossmeister; const NAME: &str = "Chessnost"; const AUTHOR: &str = "Eugene Sokolov"; impl Grossmeister { pub fn start(&mut self) { let mut search_handle = None; loop { let mut cmd = String::new(); stdin().read_line(&mut cmd).unwrap(); let mut tokens = cmd.trim().split(' '); if let Some(token) = tokens.next() { match token { "uci" => { println!("id name {}", NAME); println!("id author {}", AUTHOR); println!("uciok"); } "debug" => { if let Some(token) = tokens.next() { match token { "on" => self.debug = true, "off" => self.debug = false, _ => { panic!("Wrong option to debug: {}. CMD: {}", token, cmd); }, } }; } "isready" => { println!("readyok"); } "setoption" => { todo!() } "ucinewgame" => { // TODO: clear transposition table } "position" => { if let Some(token) = tokens.next() { match token { "startpos" => { self.board = Board::new(); if let Some(token) = tokens.next() { if token == "moves" { for token in tokens.by_ref() { let input_move = Move::from_notation(token.chars()); let moves = self.board.generate_pseudolegal_moves(); if let Some(mov) = moves .iter() .find(|m| m.source == input_move.source && m.target == input_move.target) { self.board.make_move(*mov); } else { panic!("Illegal move: {}", input_move); } } } else { panic!("Unexpected token: {}. CMD: {}", token, cmd); } } } "fen" => { // TODO: handle "moves" command after "fen"? let index = "position fen".len() + 1; if let Some(fen) = cmd.get(index..) { self.board = Board::from_FEN(fen.to_string()); }; } _ => {} } } else { todo!("Decide what to do when position is now provided") } } "go" => { search_handle = Some(self.parse_go(tokens)); } "stop" => { self.should_halt.store(true, std::sync::atomic::Ordering::Relaxed); if let Some(hand) = search_handle.take() { // Search returns new SELF that is more powerful // because he evaluated many new positions and // his transposition table is more saturated *self = hand.join().unwrap(); } } "ponderhit" => todo!(), "quit" => break, _ => {}, } } } } fn parse_go(&mut self, mut tokens: Split) -> JoinHandle { if let Some(token) = tokens.next() { match token { "searchmoves" => todo!(), "ponder" => todo!(), "wtime" => { if let Some(time) = tokens.next() { let time: u64 = time.parse().unwrap(); self.board.clock.time[Color::White as usize] = Duration::from_millis(time); } } "btime" => { if let Some(time) = tokens.next() { let time: u64 = time.parse().unwrap(); self.board.clock.time[Color::Black as usize] = Duration::from_millis(time); } } "winc" => { if let Some(time) = tokens.next() { let time: u64 = time.parse().unwrap(); self.board.clock.increment[Color::White as usize] = Duration::from_millis(time); } } "binc" => { if let Some(time) = tokens.next() { let time: u64 = time.parse().unwrap(); self.board.clock.increment[Color::White as usize] = Duration::from_millis(time); } } "movestogo" => {} "depth" => { if let Some(depth) = tokens.next() { let depth: u8 = depth.parse().unwrap(); return self.create_search_thread(depth); } }, "nodes" => todo!(), "mate" => todo!(), "movetime" => { if let Some(time) = tokens.next() { let time: u64 = time.parse().unwrap(); let duration = Duration::from_millis(time); self.create_terminator_thread(duration); return self.create_search_thread(u8::MAX) } }, "infinite" => { return self.create_search_thread(u8::MAX); }, _ => {} } return self.parse_go(tokens) } let color = self.board.color(); let duration = self.board.clock.time[color as usize] / 20 + self.board.clock.increment[color as usize]; self.create_terminator_thread(duration); self.create_search_thread(u8::MAX) } fn create_terminator_thread(&self, duration: Duration) -> JoinHandle<()> { let should_halt = self.should_halt.clone(); spawn(move || { println!("info string terminating search in {:?}", duration); sleep(duration); should_halt.store(true, std::sync::atomic::Ordering::Relaxed); }) } fn create_search_thread(&self, depth: u8) -> JoinHandle { // Clone current self and move it // into thread to analyze a position let mut gm = self.clone(); spawn(move || { gm.iterative_deepening(depth); gm }) } }