diff --git a/src/commands.rs b/src/commands.rs index ac8cc1f..4f142e1 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -48,6 +48,12 @@ pub const QUIT: &'static str = "quit\n"; /// ID is used to signal the engine name and author to the GUI pub const ID: &'static str = "id"; +/// NAME is used to signal the engine name +pub const NAME: &'static str = "name"; + +/// AUTHOR is used to signal the engine author +pub const AUTHOR: &'static str = "author"; + /// UCIOK is sent after the ID and optional options to tell the GUI that the engine has sent all infos and is ready /// in UCI mode pub const UCIOK: &'static str = "uciok\n"; diff --git a/src/lib.rs b/src/lib.rs index df935d1..ad0cc8a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,26 +1,53 @@ //! 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; - -pub struct Engine<'a> { +pub struct Engine<'a, R, W> { pub name: &'a str, pub author: &'a str, + pub mut reader: R, + pub mut writer: W, } /// Notes to delete later: /// -/// The user will have to provide code to run for the lifecycle. Moreover the user will have to overwrite a handful -/// of methods that need explicit contact with the underlying engine code to determine what to do before doing a -/// "run". There needs to be a "loop" that kicks off a thread to monitor stdin and also calculations, etc. -/// It will be worth taking the time to map out exactly how a user will be able to use this generic UCI interface -/// effectively without losing too much and/or making their lives hard. +/// +/// 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> Engine<'a> { - pub fn new(name: &'a str, author: &'a str) -> Engine<'a> { +impl<'a> Engine<'a, R, W> { + pub fn new(name: &'a str, author: &'a str, reader: R, writer: W) -> Engine<'a> { Engine { name: name, author: author, + reader: R, + writer: W, } } + + /// Sends identification messages to the writer for the GUI to pick up + /// TODO: Write tests for this. Reference: + /// https://stackoverflow.com/questions/28370126/how-can-i-test-stdin-and-stdout + pub fn identify(&self) { + let name_id: String = fmt!("{} {} {}", constants::ID, constants::NAME, self.name); + let author_id: String = fmt!("{} {} {}", constants::ID, constants::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"); + } }