C. Lente

Stockfish in R

{stockfish} is an R package that implements the UCI open communication protocol and ships with Stockfish 11, a very popular, open source, powerful chess engine written in C++.

Installation

Install the released version of {stockfish} from CRAN:

install.packages("stockfish")

Or install the development version of from GitHub with:

# install.packages("remotes")
remotes::install_github("curso-r/stockfish")

You can also find more (and more recent) versions of the Stockfish engine to use with {stockfish}at their download page.

Example

{stockfish} is as simple to use as any other UCI package. You should start the engine with fish$new() and send commands with its internal methods, only remembering to run quit() once you’re done.

library(stockfish)

# Start the engine
engine <- fish$new()

# Examine background process
engine$process
#> PROCESS 'stockfish', running, pid 173670.

# Search for best move
engine$go()
#> [1] "bestmove e2e4 ponder d7d5"

# Setup a game from FEN
engine$ucinewgame()
engine$position("6rk/2Q3p1/5qBp/5P2/8/7P/6PK/8 w - - 15 51")
engine$go()
#> [1] "bestmove g6f7 ponder g8d8"

# Stop the engine
engine$quit()

Usage

fish, this package’s main class, represents a Stockfish engine, allowing the user to send commands and receive outputs according to the UCI protocol. In short, a fish object, when created, spawns a detached Stockfish process and pipes into its stdin and stdout.

For more information, see its full documentation by running ?fish.

Bundled Stockfish

This package comes bundled with Stockfish, a very popular, open source, powerful chess engine written in C++. It can achieve an ELO of 3516, runs on Windows, macOS, Linux, iOS and Android, and can be compiled in less than a minute.

When installing {stockfish} (lower case), Stockfish’s (upper case) source code is compiled and the resulting executable is stored with your R packages. This is not a system-wide installation! You don’t have to give it administrative privileges to run or even worry about any additional software.

The only downside is that the bundled version of the engine is Stockfish 11, not the most recent Stockfish 12. This is because the 12th version needs additional downloads, which would dramatically increase the installation time. If you want to, you can download the version of your choosing and pass the executable as an argument to fish$new().

UCI Protocol

UCI (Universal Chess Interface) is an open communication protocol that enables chess engines to communicate with user interfaces. Strictly speaking, the fish class implements the UCI protocol as publicized by Stefan-Meyer Kahlen, just with a focus on the Stockfish engine. This means that some methods are not implemented (see Common Gotchas) and that all tests are run on Stockfish, but everything else should work fine with other engines.

The quoted text at the end of the documentation of each method was extracted directly from the official UCI protocol, so you can see exactly what that command can do. In general, the commands are pretty self-explanatory, except for long algebraic notation (LAN), the move notation used by UCI. In this notation, moves are recorded using the starting and ending positions of each piece, e.g. e2e4, e7e5, e1g1 (white short castling), e7e8q (for promotion), 0000 (nullmove).

Implementation

All the heavy lifting of the fish class is done by the {processx} package. The Stockfish process is created with processx::process$new and IO is done with write_input() and read_output(). An important aspect of the communication protocol of any UCI engine is waiting for replies, and here this is done with a loop that queries the process with poll_io() and stops once the output comes back empty.

Before implementing the UCI protocol manually, this package used {bigchess}. It is a great package created by @rosawojciech, but it has some dependencies that are beyond the scope of this package and ultimately I wanted more control over the API (e.g. using {R6}).

Common Gotchas

The fish class has some specifics that the user should keep in mind when trying to communicate with Stockfish. Some of them are due to implementation choices, but others are related to the UCI protocol itself. This is by no means a comprehensive list (and you should probably read UCI’s documentation), but here are a few things to look out for:

  • Not every UCI method is implemented: since {stockfish} was made with Stockfish (and mainly Stockfish 11) in mind, a couple of UCI methods that don’t work with the engine were not implemented. They are debug() and register().

  • Most methods return silently: since most UCI commands don’t output anything or output boilerplate text, most methods return silently. The exceptions are run(), isready(), go() and stop(); you can see exactly what they return by reading their documentations.

  • Not every Stockfish option will work: at least when using the bundled version of Stockfish, not every documented option will work with setoption(). This happens because, as described above, this package comes with Stockfish 11, which is not the most recent version. Options that will not work are labeled with an asterisk.

  • Times are in milliseconds: unlike most R functions, every method that takes a time interval expects them in milliseconds, not seconds.