Usage

How to run FollyChess and connect it to a chess GUI.

Once you have compiled the engine, you can use it through a chess GUI or directly on the command line.

Using with a chess GUI #

FollyChess implements the Universal Chess Interface (UCI). It does not draw a board itself; a chess GUI does that and talks to the engine for you. Some GUIs that work well:

In your GUI, add a new engine and select the bazel-bin/cli/follychess binary when prompted.

Running on the command line #

You can also talk to the engine directly via your shell. This is useful for debugging and scripting:

bazel-bin/cli/follychess

The engine then waits for commands. FollyChess supports a subset of the UCI protocol, described below. In the examples, commands you type are shown in bold; the rest is engine output.

uci #

Starts the UCI protocol. The engine identifies itself and lists its options.

isready #

Synchronizes with the engine. FollyChess answers readyok once it has finished its internal setup.

d #

A custom command (not part of UCI). Prints the current position:

d
8: r n b q k b n r
7: p p p p p p p p
6: . . . . . . . .
5: . . . . . . . .
4: . . . . . . . .
3: . . . . . . . .
2: P P P P P P P P
1: R N B Q K B N R
   a b c d e f g h

   w KQkq - 0 1

position #

Sets up the board. It supports these forms:

Starting position. position startpos resets the board to the starting position.

FEN string. position fen <fenstring> sets the board to a position given in Forsyth–Edwards Notation:

position fen 8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1
d
8: . . . . . . . .
7: . . p . . . . .
6: . . . p . . . .
5: K P . . . . . r
4: . R . . . p . k
3: . . . . . . . .
2: . . . . P . P .
1: . . . . . . . .
   a b c d e f g h

   w - - 0 1

Adding moves. position [startpos | fen <fenstring>] moves <move1> <move2> ... applies a sequence of moves to the given position:

position startpos moves e2e4 e7e5 g1f3
d
8: r n b q k b n r
7: p p p p . p p p
6: . . . . . . . .
5: . . . . p . . .
4: . . . . P . . .
3: . . . . . N . .
2: P P P P . P P P
1: R N B Q K B . R
   a b c d e f g h

   b KQkq - 3 2

Moves use long algebraic notation:

TypeFormatExample
Standard<from><to> e2e4, g1f3
Castling<from><to> e1g1 (white kingside), e8c8 (black queenside)
Promotion<from><to><piece> a7a8q (queen), h2h1n (knight)

go #

Calculates the best move for the current position. The search can be limited in three ways:

Depth. go depth <plies> searches to a fixed depth. The engine reports each completed iteration and finishes with the best move it found:

go depth 3
info depth 1 score cp 69 nodes 41 nps 408 tthits 0 tthitrate 0.00 pv e2e4
info depth 2 score cp 0 nodes 182 nps 1799 tthits 0 tthitrate 0.00 pv e2e4 e7e5
info depth 3 score cp 41 nodes 908 nps 8715 tthits 1 tthitrate 0.00 pv d2d4 d7d5 c1f4
bestmove d2d4

Time. go movetime <milliseconds> searches for a fixed amount of time, going as deep as the budget allows. When the time runs out, the engine plays the best move from the last iteration it completed:

go movetime 1000
info depth 1 score cp 69 nodes 41 nps 451 tthits 0 tthitrate 0.00 pv e2e4
...
info depth 6 score cp 5 nodes 75501 nps 116195 tthits 2133 tthitrate 0.04 pv d2d4 d7d5 e2e4 d5e4 f1b5 c8d7
bestmove d2d4

Nodes. go nodes <count> stops the search once roughly that many positions have been visited. Unlike a time limit, a node limit produces the same result on every run and on any machine, which makes it useful for testing:

go nodes 20000
info depth 1 score cp 69 nodes 41 nps 451 tthits 0 tthitrate 0.00 pv e2e4
...
info depth 5 score cp 34 nodes 11217 nps 75929 tthits 417 tthitrate 0.05 pv d2d4 d7d5 c1f4 c8f5 b1d2
bestmove d2d4

The limits can be combined, in which case the search stops at whichever limit is reached first. With no arguments, go searches to a default depth of 6. Regardless of the limits, the engine always completes at least a depth-1 search so that it can produce a move.

bench #

A custom command (not part of UCI). Searches a fixed suite of 46 positions at a fixed depth (6 by default, or bench <depth>). The suite spans the opening, sharp and quiet middlegames, endgames, and terminal positions. Each position's regular search output goes to standard output, while the position headers and the summary go to standard error, so that standard output carries nothing but engine protocol output:

bench

Position: 1/46 (rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1)
info depth 1 score cp 69 nodes 41 nps 2182 tthits 0 tthitrate 0.00 pv e2e4
...
info depth 6 score cp 5 nodes 75410 nps 1487441 tthits 2135 tthitrate 0.04 pv d2d4 d7d5 e2e4 d5e4 f1b5 c8d7
bestmove d2d4

Position: 2/46 (r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 10)
...

===========================
Total time (ms) : 5259
Nodes searched  : 14539344
Nodes/second    : 2764353

The Nodes searched count is deterministic: the same source code produces the same count on every run and on any machine. This makes it a signature of the search. A refactor that is not meant to change search behavior must leave the count unchanged, while a change to pruning or move ordering shows up as a different count. Nodes/second tracks raw search speed.

quit #

Ends the engine process.