Taylor Bockman 7 years ago
parent
commit
78e23831e0
  1. 6
      src/commands.rs
  2. 45
      src/lib.rs

6
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";

45
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");
}
}

Loading…
Cancel
Save