pleco-rs / Pleco

A Rust-based re-write of the Stockfish Chess Engine

Home Page:https://crates.io/crates/pleco

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Universal Chess Interface support and associated `UCISearcher` Trait.

sfleischman105 opened this issue · comments

In order to be considered a modern chess engine, Pleco needs to support the Universal Chess Interface (shorthand is UCI) inside of both the engine, as well as the primary searcher. More information about UCI can be found here.

There are four parts I would like to outline for implementing this.

1) main.rs args

When given the command "uci" as an argument (or stdin after load), Engine::uci(...) should be called, letting the Engine handle it from there.

2) Engine

The Engine must contain a Engine::uci(...) method to allow for communication to and from the GUI. Communication uses stdin and stdout to pass commands back and forth. The command "isready" should allow the engine the opportunity to get both a UCI compatible Searcher (more on this later) and a Board object ready. The GUI can send in options to the Engine before the game actually begins, starting with the "setoption" command. All commands leading up to "go" (which starts the game) can be implemented with a simple IO loop.

3) Mid Game Message sending to / from UCI Searcher

When the Searcher is in the midst of searching, the Engine must act as an intermediary between the GUI and the Searcher. Mid-search, the GUI should only be able to send the command "stop" to the Searcher, which should within reasonable time stop the Search and return the best move found so good.

Some problems that need to be dealt with in concern of this:

  • How do we allow stdin to be scanned in a separate thread, but without impacting search performance?
  • What type of structure do we need to pass into the UCI Searcher that allows for checking when to stop?

Furthermore, the Engine needs to be able to do the opposite: Await information from the UCI Searcher and relay that information to the GUI.

4) Implementing the UCISearcher Trait

The UCISearcher Trait should mark specific Searchers as UCI compatible. Currently, the UCISearcher implementation is the following:

pub trait UCISearcher: Searcher {
   fn uci_move(board: Board, timer: &Timer, rx: Arc<Mutex<Option<GuiToEngine>>>) -> BitMove where Self: Sized;
}

Some notes on this:

  • Receiver needs to be solidified in uci_move as determined by item 3.
  • A Sender needs to be given in somewhere, to allow the chess board to communicate back.
  • `fn configuration()' or similar function should allow easily setting up options.

Hey, I have some experience with UCI and would be happy to work on an implementation. Perhaps you could select a license for the project first? It can be messy to try to do it later once you already have contributions from a number of people.

Any and all help is appreciated @jbg ! And good idea, I just added an MIT license to the Repo.

UCI Searcher Trait Solved with #35. Currently stands as follows:

pub trait UCISearcher: Searcher {
    fn uci_setup(board: Board, stop: Arc<AtomicBool>) -> Self where Self: Sized;

    fn uci_go(&mut self, limits: UCILimit) -> BitMove;
}

The stop [Arc] must still be handled through an Engine Thread as determined by point 2.

A new enum, [UCILimit] is defined to give the UCI Searcher an idea of when it should stop by itself (away from the GUI calling stop. Currently the options are:

  1. [UCILimit::Infinite], which means to keep searching until the GUI calls stop.
  2. [UCILimit::Time(Timer)], which means to search with a game standard clock in mind.
  3. [UCILimit::Depth(ply)], search up to a given depth.

Changed Searcher and UCI Searcher Trait with #49 , It now is represented as:

pub trait Searcher {
    fn name() -> &'static str where Self: Sized;

    fn best_move(board: Board, limit: UCILimit) -> BitMove
    where
        Self: Sized;

    fn best_move_depth(board: Board, max_depth: u16) -> BitMove
    where
        Self: Sized {
        Self::best_move(board, UCILimit::Depth(max_depth))
    }
}

pub trait UCISearcher: Searcher {
    fn uci_setup(board: Board, stop: Arc<AtomicBool>) -> Self where Self: Sized;

    fn uci_go(&mut self, limits: UCILimit, use_stdout: bool) -> BitMove;
}

This will need to be done in order for #56.

Closed due to the removal of the UCISearcher trait.