//! 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}; use std::vec; #[derive(Debug)] pub struct Engine<'a, R, W> { pub name: &'a str, pub author: &'a str, pub reader: R, pub writer: W, pub engine_options: Vec, } /// 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_options: Vec) -> Engine<'a, R, W> { Engine { name: name, author: author, reader: reader, writer: writer, engine_options: engine_options, } } /// 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"); } /// Sends `readyok` to the GUI pub fn ready(&mut self) { write!(&mut self.writer, "{}", commands::READYOK).expect("failed to send `readyok` command"); } }