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 aredebug()
andregister()
. -
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()
andstop()
; 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.