I just released a library for Ruby for interacting with UCI-compliant chess engines and, after that, I can see that there is a lot about UCI that I don’t like. Here it is, and how I propose to fix it.

Important note: When Rudolf Huber and Stefan Meyer-Kahlen designed the UCI protocol, it was (and still is) a huge advancement over XBoard and I give them all due credit for their hard work. This is not meant to be a personal dig at their skills or effort. That having been said, I believe that it was designed from a chess-players perspective first and not a programmers perspective and there are many drawbacks there.

Problem #1: The command-response cycle is not constant.

When first opening a connection to a UCI engine you may or may not get a greeting from the engine. When issuing commands you may or may not get a response, regardless of if the command was successful. Some commands only return a response when successful and some only on failure.

“isready” returns “readyok” on success, but anything else on failure. “setoption” only returns something on failure. “position” never returns anything. “go” may return “bestmove”, OR “info” but there is no guarantee when or how.

All this leads to a madding list of special cases for every command.

Solution #1: Standardize the command-response cycle.

I’ve worked with a lot of text-based protocols over the years, and the good ones all share a common theme: their responses to commands are always uniform regardless of the command. Let’s take the same approach here.

We see a glimpse of how to do this in the ‘uci’ command which says that the response for the command must end in ‘uciok’, which signals then end of response for this command. It ALSO, unintentionally, signals success.

I propose that ever successful command must send ‘OK’ as the last line returned if the command was a success, even if there is no content. If the command failed, the last line should be ‘FAIL’. For example:

Why is this good? It provides a definite indicator that:

  1. The command succeeded or failed.
  2. The command is finished.

This makes consuming the interface much easier because you don’t want to wait for the buffer to be empty, you just have to look for ‘OK’ or ‘FAIL’.

 

Problem #2: “info” is not informative.

The “info” blocks that are sent from the engine while “thinking” are supposed to give insight in to the state of the engine, but the info is formatted in such a way that it’s basically useless.

This is not directly the fault of the UCI spec, but it is a side-effect. Engine designers want to put detailed info in their info-lines but , from the may the UCI spec dictates, it becomes an unparseable mess very quickly.

An example “info” line is:

info nps 15937

..and that’s easy to parse, but they never stay that simple:

info slv 5 5 score cp 13 depth 1 nodes 13 ups 1 1 time 15 pv f1b5 x xv r 12

There is no guaranteed order and no format requirement. Thus, it is not machine parable unless you make a special case for how each engine, individually, choses to format this info.

Solution #2: Well-defined records

The issue here is that we don’t know what the record separator is. It appears to be “space”, but that’s ambiguous because space also separated keys from values. Instead, return something inherently machine parable but still human readable like YAML or JSON:

Problem #3: no standardized “end of game”.

There is nothing in UCI to state when a game is over. Saying it’s “up to the client” is a cop-out, since every major engine now has it’s own way of saying when it thinks there is no hope:

  • stockfish: bestmove (none)
  • fruit and rybka: bestmove a1a1
  • Robolitto: bestmove NULL

And, even though we can use those to infer, we have no way of assessing context: did the engine send this because it because of a mate or something else? Did it mate, or did it get mated? Did it hit the 50-move-rule? What? All this tells us is the engine threw it’s hands up and stormed off. The end.

Solution #3: standard responses for endgames.

This one’s easy, accept that engine know when they’ve been mates and standardize the response:

 Conclusion

UCI is really good for a lot of things. What is needs is love from people who are programmers first and chess-player second. I am not a chess player. I don’t even like chess.

  • Renehewitt

    Hi Matthew and how are you?  I’ve been working with your code for playing music on a web site with the listener selecting each track.  However, I can’t seem to find a code which will allow the music to automatically play after each other until the end of the list.

    Do you have some code for that?