Skip to content

Understanding the code

Fabian Fichter edited this page Mar 3, 2023 · 5 revisions

To understand the code base of this project it is a very good start if you already have some understanding of chess engine programming in general or specifically the code base of Stockfish, which is the chess engine this project is based on.

Stockfish

As a starting point to understand the code of Stockfish you can check out the resources listed in its readme. The chess programming wiki contains a lot of information about the techniques used in Stockfish and about Stockfish itself.

Fairy-Stockfish

Overview

Fairy-Stockfish is based on Stockfish and extends it with the support for chess variants in order to get a chess variant engine that can make use of all the search techniques that make Stockfish the strongest chess engine. It is the result of several projects to create Stockfish forks for specific variants like Makruk, Shatranj, and S-Chess, and the desire to merge them into one in order to simplify development and to make the addition of new variants as easy as possible.

Design

The fundamental design decision for the variant support was to make the rule implementation rule/feature-centric and not variant-centric (like the Stockfish fork for lichess), which means that the position representation and move generation consider the individual rules of a chess variant independently so that a variant can simply be defined as a set of such rules like board size, piece types, etc. This generality of course comes at the expense of performance, but on the upside allows very fast implementation of new variants and even the addition of variants at runtime through a variant configuration file.

Furthermore, the generality allows the search and evaluation code to share features between variants with similar rules, e.g., drop variants like crazyhouse and shogi, so that improvements in playing strength usually apply to many variants and do not need to be implemented separately for every one of them. Therefore, and due to making use of Stockfish's powerful search algorithm, Fairy-Stockfish usually is able to play variants at master or even super-human level even if the rules of the variant were user-defined and not known during development, since it can re-use its knowledge from variants with similar rules.

Code base

Depending on what you are mostly interested in, there are several areas of the code base that can be clustered topic-wise.

Variant definition

  • variant.h contains the class definition of a variant object and as such defines the set of available rule options.
  • variant.cpp contains the concrete definition of the built-in variants.
  • variants.ini is an example of a variant configuration file and also contains documentation of the meaning of the variant attributes defined in variant.h.
  • parser.h/parser.cpp contain the code for parsing of variant configuration files.
  • piece.h/piece.cpp define the movements of the piece types.

Variant rule implementation

  • position.h defines the position object and wraps the access to the variant attributes (see variant.h) of a position.
  • position.cpp contains most of the logic for FEN parsing and generation, legality checking and doing/undoing of moves, as well as the variant-specific game end criteria.
  • movegen.cpp generates the pseudo-legal moves for all pieces and therefore also is core part of the variant rule implementations.

Bitboards

The implementation of bitboards and magics for fairy pieces and larger board sizes can be found in:

  • types.h defines the Bitboard data type as 64 or 128 bit.
  • bitboard.h/bitboard.cpp implement operations on bitboards and the generation and access of magics for slider move generation.
  • magic.h contains precomputed magics to speed up the startup for architectures without pext support where the computation of magics on the 12x10 board can be slow.

Protocols

The supported UCI dialects (UCI, UCCI, USI) and the CECP/XBoard protocol are implemented in:

  • uci.h/uci.cpp/ucioption.cpp
  • xboard.h/xboard.cpp
  • partner.h/partner.cpp for the partner communication in the CECP protocol for four-player variants (e.g., bughouse).

Evaluation

Code related to position evaluation:

  • evaluate.cpp is the central place for position evaluation.
  • psqt.cpp modifies the piece values based on variant rules and initializes the piece-square tables.
  • pawns.cpp evaluates pawn structures, also in regards to king safety
  • material.cpp and endgame.cpp contain code for evaluation of material imbalances and specific endgames.

Search

The search is mostly the same as official Stockfish, but some search techniques are modified or skipped in variants where they do not work well in the way they are used for chess.

  • search.cpp is the central place for the tree search algorithm.
  • movepick.cpp, tt.cpp, and timeman.cpp are mostly unchanged compared to official Stockfish, but contain some minor tweaks for variants.

Tests

In tests/perft.sh some perft data for variants can be found that is used for CI testing.

Python binding

Originally started as a separate fork, a python binding is now developed as part of the main repository. It can be used as a python chess variant library for move generation, etc., see, e.g., https://github.com/gbtami/pychess-variants and https://github.com/ianfab/fairyfishtest.

  • pyffish.cpp contains the python binding code along with a few additional features like SAN/notation generation.
  • setup.py/test.py (in the root directory) for package installation and testing