A Universal Chess Interface (UCI) protocol parser and message generator.
Vampirc UCI is a Universal Chess Interface (UCI) protocol parser and
serializer.
The UCI protocol is a way for a chess engine to communicate with a chessboard GUI, such as Cute Chess.
The Vampirc Project is a chess engine and chess library suite, written in Rust. It is named for the
Slovenian grandmaster Vasja Pirc, and, I guess, vampires? I dunno.
Vampirc UCI uses the PEST parser to parse the UCI messages. If you want to build your own
abstractions of the protocol, the corresponding PEG grammar is available here.
To use the crate, declare a dependency on it in your Cargo.toml file:
[dependencies]
vampirc-uci = "0.11"
Then reference the vampirc_uci
crate in your crate root:
extern crate vampirc_uci;
parse..
functions. See Choosing the parsing function.
use vampirc_uci::parse;
use vampirc_uci::{UciMessage, MessageList, UciTimeControl, Serializable};
let messages: MessageList = parse("uci\nposition startpos moves e2e4 e7e5\ngo ponder\n");
for m in messages {
match m {
UciMessage::Uci => {
// Initialize the UCI mode of the chess engine.
}
UciMessage::Position { startpos, fen, moves } => {
// Set up the starting position in the engine and play the moves e2-e4 and e7-e5
}
UciMessage::Go { time_control, search_control } {
if let Some(tc) = time_control {
match tc {
UciTimeControl::Ponder => {
// Put the engine into ponder mode ("think" on opponent's time)
}
_ => {...}
}
}
}
_ => {...}
}
}
let message = UciMessage::Option(UciOptionConfig::Spin {
name: "Selectivity".to_string(),
default: Some(2),
min: Some(0),
max: Some(4),
});
println!(message); // Outputs "option name Selectivity type spin default 2 min 0 max 4"
stdin
:for line in io::stdin().lock().lines() {
let msg: UciMessage = parse_one(&line.unwrap());
println!(“Received message: {}”, msg);
}
## Choosing the parsing function
There are several parsing functions available, depending on your need and use case. They differ in what
they return and how they handle unrecognized input. The following table may be of assistance in selecting the
parsing function:
| Function | Returns | Can skip terminating newline | On unrecognised input... |
| -------------------- | ----------------------------------------|------------------------------|---------------------------------------------|
| `parse` | `MessageList` (a `Vec` of `UciMessage`) | On last command | Ignores it |
| `parse_strict` | `MessageList` (a `Vec` of `UciMessage`) | On last command | Throws a `pest::ParseError` |
| `parse_with_unknown` | `MessageList` (a `Vec` of `UciMessage`) | On last command | Wraps it in a `UciMessage::Unknown` variant |
| `parse_one` | `UciMessage` | Yes | Wraps it in a `UciMessage::Unknown` variant |
From my own experience, I recommend using either `parse_with_unknown` if your string can contain multiple commands, or
else `parse_one` if you're doing line by line parsing. That way, your chess engine or tooling can at least log
unrecognised input, available from `UciMessage::Unknown(String, Error)` variant.
## Integration with the chess crate (since 0.9.0)
This library (optionally) integrates with the [chess crate](https://crates.io/crates/chess). First, include the
`vampirc-uci` crate into your project with the `chess` feature:
```toml
[dependencies]
vampirc-uci = {version = "0.11", features = ["chess"]}
This will cause the vampirc_uci’s internal representation of moves, squares and pieces to be replaced with chess
crate’s representation of those concepts. Full table below:
vampirc_uci ‘s representation | chess’ representation |
---|---|
vampirc_uci::UciSquare |
chess::Square |
vampirc_uci::UciPiece |
chess::Piece |
vampirc_uci::UciMove |
chess::ChessMove |
WARNING
chess
is a fairly heavy create with some heavy dependencies, so probably only use the integration feature if you’re
building your own chess engine or tooling with it.
The full API documentation is available at docs.rs.
parse_with_unknown(&str)
so that it correctly recognizes as much of input as possible. For example, whereasuci\ndebug on\nucinewgame\nabc\nstop\nquit
would be returned as a single Uci::Unknown
message, theUci::Unknown
.btime
std:
:Duration
to the chrono crate’schrono::Duration
(doc). This is an API-breaking change, hence the version increase.go
message.parse_one(&str)
method that parses and returns a single command, to be used in a loopstdin
or other BufReader
. See example above.u64
into std:
:Duration
(breakingparse()
or friends doesn’t need tostdin:
:stdin().lock().lines()
, which strips the newline characters from the end -UciMessage::direction(&self)
method as public.UciMessage::info_string()
utility function.go
command (see Parser cannot parse “go\n”).ByteVecUciMessage
as a UciMessage
wrapper that keeps the serialized form of the message in the struct as a byte Vector. Useful ifAsRef<[u8]>
trait for funnelling the messages into a futures::Sink
orparse_with_unknown()
method that instead of ignoring unknown messages (like parse
) or throwing an error (like parse_strict
) returnsUciMessage::Unknown
variant.info
message, with the UciAttributeInfooption
message.<empty>
strings in option
and setoption
.This section used to recommend using the vampirc-io crate to connect your
UCI-based chess engine to the GUI, but honestly, with recent advances to Rust’s async stack support, it is probably
just easier if you do it yourself using, for example, the async-std library.
The library is functionally complete – it supports the parsing and serialization to string of all the messages
described by the UCI specification. Before the 1.0 version can be released, though, this library needs to be battle
tested more, especially in the upcoming Vampirc chess engine.
Furthermore, as I am fairly new to Rust, I want to make sure the implementation of this protocol parser is Rust-idiomatic
before releasing 1.0. For this reason, the API should not be considered completely stable until 1.0 is released.
Additionally, some performance testing would also not go amiss.
uci
debug
isready
register
position
setoption
ucinewgame
stop
ponderhit
quit
go
id
uciok
readyok
bestmove
copyprotection
registration
option
info