|
|
|
//! UCI is a simple library to allow people to ignore the lower-level protocol needed to create chess engines.
|
|
|
|
//! The engine is fully generic. By specifying a valid reader and writing you can send the messages to STDIN
|
|
|
|
//! and STDOUT, per the standard - or to memory for testing.
|
|
|
|
|
|
|
|
mod commands;
|
|
|
|
|
|
|
|
use std::io::{BufRead, Write};
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Engine<'a, R, W> {
|
|
|
|
pub name: &'a str,
|
|
|
|
pub author: &'a str,
|
|
|
|
pub reader: R,
|
|
|
|
pub writer: W,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Notes to delete later:
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// A way to make this comfortable for users to use is this provides easy access to commands as well as a
|
|
|
|
/// loop and stuff they can use. This way they don't have to override anything - they just include this
|
|
|
|
/// in their code for their engine to make the communication portion easy.
|
|
|
|
///
|
|
|
|
/// Think of this in the manner of a game engine. They don't provide the loop and everything, but they do
|
|
|
|
/// provide convenience functions and stuff to make _building_ that loop easier.
|
|
|
|
///
|
|
|
|
/// In other words, the engine writer still needs to know how the standard works. They just don't need to
|
|
|
|
/// implement all the nasty details.
|
|
|
|
/// For example, a start up function calls the correct "boot up" code for the engine so they only have to
|
|
|
|
/// worry about calling "boot up" prior to their main engine loop.
|
|
|
|
///
|
|
|
|
/// Additionally this code should have a parser. You call it with the reader supplied and it waits for a command
|
|
|
|
/// and parses it into a tuple of some kind for the user.
|
|
|
|
|
|
|
|
impl<'a, R, W> Engine<'a, R, W>
|
|
|
|
where
|
|
|
|
R: BufRead,
|
|
|
|
W: Write,
|
|
|
|
{
|
|
|
|
pub fn new(name: &'a str, author: &'a str, reader: R, writer: W) -> Engine<'a, R, W> {
|
|
|
|
|
|
|
|
// TODO: This should also take an EngineOptions thing that indicates which options are supported
|
|
|
|
// so that when called it can send them easily.
|
|
|
|
// Engine options are all optional and appeared to be fixed by the UCI standard.
|
|
|
|
|
|
|
|
Engine {
|
|
|
|
name: name,
|
|
|
|
author: author,
|
|
|
|
reader: reader,
|
|
|
|
writer: writer,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sends identification messages to the writer for the GUI to pick up
|
|
|
|
pub fn identify(&mut self) {
|
|
|
|
let name_id: String = format!("{} {} {}\n", commands::ID, commands::NAME, self.name);
|
|
|
|
let author_id: String = format!("{} {} {}\n", commands::ID, commands::AUTHOR, self.author);
|
|
|
|
|
|
|
|
// For these two writes we can panic - there's no possibility of recovery if the engine fails at this stage
|
|
|
|
write!(&mut self.writer, "{}", name_id).expect("failed to send name identification to writer");
|
|
|
|
write!(&mut self.writer, "{}", author_id).expect("failed to send author identification to writer");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sends all available options in the options configuration and a final UCIOK meaning we are reading to go.
|
|
|
|
pub fn send_available_options(&mut self) {
|
|
|
|
// NOTE: Options can be represented as an array of EngineOption in the options.rs
|
|
|
|
// file and values are the associated options.
|
|
|
|
// This function will construct the proper string from the objects.
|
|
|
|
// Construct the strings using the `option_string` function of each engine option. Let it tell you
|
|
|
|
// what it is.
|
|
|
|
// TODO: This needs to be tested majorly
|
|
|
|
|
|
|
|
// Again this command must complete before we can say the engine is connected, so panicking at this stage is ok
|
|
|
|
write!(&mut self.writer, "{}", commands::UCIOK).expect("failed to send `uciok` command");
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ready(&mut self) {
|
|
|
|
// TODO: TESTS TO MAKE SURE IT SENDS READYOK
|
|
|
|
}
|
|
|
|
}
|