mod uci;
use crate::evaluation::SearchTree;
use crate::physical::*;
use std::io;
pub use uci::*;
#[allow(dead_code)]
struct EngineOptions {}
impl EngineOptions {
fn new() -> Self {
Self {}
}
}
pub struct Ocelot {
pub(crate) board: Board,
pub(crate) depth: i32,
ponder: Option<Box<dyn Action>>,
allowed_time: f64,
evaluation: f64,
}
impl Ocelot {
pub fn new(board: &Board, depth: i32, allowed_time: f64) -> Self {
Self {
board: board.duplicate(),
depth,
ponder: None,
allowed_time,
evaluation: 0.0,
}
}
pub fn safe_best_move(&mut self) -> Box<dyn Action> {
let mut tree = SearchTree::new(&self.board, self.depth, self.allowed_time);
tree.safe_best_move()
}
pub fn perform_on_self(&mut self, mut action: Box<dyn Action>) {
action.perform_on(&mut self.board);
}
pub fn uci_loop(&mut self) {
loop {
let mut input = String::new();
let _ = io::stdin().read_line(&mut input);
if !self.interpret_uci(input) {
break;
}
}
}
fn interpret_uci(&mut self, input: String) -> bool {
let mut words = input.split_whitespace();
let Some(command) = words.nth(0) else {
return true;
};
let command_tail = input.split_at(command.len() + 1).1;
match command {
"quit" => return false,
"uci" => {
println!("uciok");
}
"ucinewgame" => {}
"isready" => {
println!("readyok");
} "setoption" => {} "position" => {
self.position(command_tail);
}
"go" => {
self.go(command_tail);
}
"ponderhit" => {
if let Some(pondered) = &mut self.ponder {
pondered.perform_on(&mut self.board);
}
}
"stop" => {} "d" => {
println!("{}", self.board.draw());
}
"eval" => {
println!("{}", self.evaluation);
}
_ => {
eprintln!("Ocelot::interpret_uci(): Command {command} isn't implemented.");
}
}
true
}
fn go(&mut self, _command: &str) {
let mut tree = SearchTree::new(&self.board, self.depth, self.allowed_time);
let mut best_move = tree.safe_best_move();
let maybe_best_position = tree.root.best_child;
if let Some(value) = tree.root.best_value {
self.evaluation = value;
}
let ponder = if let Some(best_pos) = *maybe_best_position {
if let Some(ponder) = best_pos.best_move {
ponder.generate()
} else {
String::from("0000")
}
} else {
String::from("0000")
};
best_move.perform_on(&mut self.board);
println!("bestmove {} ponder {ponder}", best_move.generate());
}
fn position(&mut self, repr: &str) {
let repr = repr.replace("fen ", "");
let result = Board::parse(repr.to_string());
if let Ok(board) = result {
self.board = board;
}
if repr.contains("moves") {
let mut halves = repr.split("moves");
let move_reprs = halves.nth(1).unwrap().split_whitespace();
for move_repr in move_reprs {
let action =
uci::parse_action(move_repr.to_string().trim().to_string(), &mut self.board);
self.perform_on_self(action);
}
}
}
}