Syzygy endgame tablebase probing

Syzygy tablebases provide WDL50 (win/draw/loss under the 50-move rule) and DTZ50’’ (distance to zeroing) information with rounding for all endgame positions with up to 7 pieces. Positions with castling rights are not included.

Warning

Ensure tablebase files match the known checksums. Maliciously crafted tablebase files may cause denial of service.

chess.syzygy.open_tablebase(directory: str, *, load_wdl: bool = True, load_dtz: bool = True, max_fds: int | None = 128, VariantBoard: ~typing.Type[~chess.Board] = <class 'chess.Board'>) Tablebase[source]

Opens a collection of tables for probing. See Tablebase.

Note

Generally probing requires tablebase files for the specific material composition, as well as material compositions transitively reachable by captures and promotions. This is important because 6-piece and 5-piece (let alone 7-piece) files are often distributed separately, but are both required for 6-piece positions. Use add_directory() to load tables from additional directories.

Parameters:

max_fds – If max_fds is not None, will at most use max_fds open file descriptors at any given time. The least recently used tables are closed, if necessary.

class chess.syzygy.Tablebase(*, max_fds: int | None = 128, VariantBoard: ~typing.Type[~chess.Board] = <class 'chess.Board'>)[source]

Manages a collection of tablebase files for probing.

add_directory(directory: str, *, load_wdl: bool = True, load_dtz: bool = True) int[source]

Adds tables from a directory.

By default, all available tables with the correct file names (e.g., WDL files like KQvKN.rtbw and DTZ files like KRBvK.rtbz) are added.

The relevant files are lazily opened when the tablebase is actually probed.

Returns the number of table files that were found.

probe_wdl(board: Board) int[source]

Probes WDL tables for win/draw/loss information under the 50-move rule, assuming the position has been reached directly after a capture or pawn move.

Probing is thread-safe when done with different board objects and if board objects are not modified during probing.

Returns 2 if the side to move is winning, 0 if the position is a draw and -2 if the side to move is losing.

Returns 1 in case of a cursed win and -1 in case of a blessed loss. Mate can be forced but the position can be drawn due to the fifty-move rule.

>>> import chess
>>> import chess.syzygy
>>>
>>> with chess.syzygy.open_tablebase("data/syzygy/regular") as tablebase:
...     board = chess.Board("8/2K5/4B3/3N4/8/8/4k3/8 b - - 0 1")
...     print(tablebase.probe_wdl(board))
...
-2
Raises:

KeyError (or specifically chess.syzygy.MissingTableError) if the position could not be found in the tablebase. Use get_wdl() if you prefer to get None instead of an exception.

Note that probing corrupted table files is undefined behavior.

probe_dtz(board: Board) int[source]

Probes DTZ tables for DTZ50’’ information with rounding.

Minmaxing the DTZ50’’ values guarantees winning a won position (and drawing a drawn position), because it makes progress keeping the win in hand. However, the lines are not always the most straightforward ways to win. Engines like Stockfish calculate themselves, checking with DTZ, but only play according to DTZ if they can not manage on their own.

Returns a positive value if the side to move is winning, 0 if the position is a draw, and a negative value if the side to move is losing. More precisely:

WDL

DTZ

-2

-100 <= n <= -1

Unconditional loss (assuming 50-move counter is zero), where a zeroing move can be forced in -n plies.

-1

n < -100

Loss, but draw under the 50-move rule. A zeroing move can be forced in -n plies or -n - 100 plies (if a later phase is responsible for the blessed loss).

0

0

Draw.

1

100 < n

Win, but draw under the 50-move rule. A zeroing move can be forced in n plies or n - 100 plies (if a later phase is responsible for the cursed win).

2

1 <= n <= 100

Unconditional win (assuming 50-move counter is zero), where a zeroing move can be forced in n plies.

The return value can be off by one: a return value -n can mean a losing zeroing move in in n + 1 plies and a return value +n can mean a winning zeroing move in n + 1 plies. This implies some primary tablebase lines may waste up to 1 ply. Rounding is never used for endgame phases where it would change the game theoretical outcome.

This means users need to be careful in positions that are nearly drawn under the 50-move rule! Carelessly wasting 1 more ply by not following the tablebase recommendation, for a total of 2 wasted plies, may change the outcome of the game.

>>> import chess
>>> import chess.syzygy
>>>
>>> with chess.syzygy.open_tablebase("data/syzygy/regular") as tablebase:
...     board = chess.Board("8/2K5/4B3/3N4/8/8/4k3/8 b - - 0 1")
...     print(tablebase.probe_dtz(board))
...
-53

Probing is thread-safe when done with different board objects and if board objects are not modified during probing.

Both DTZ and WDL tables are required in order to probe for DTZ.

Raises:

KeyError (or specifically chess.syzygy.MissingTableError) if the position could not be found in the tablebase. Use get_dtz() if you prefer to get None instead of an exception.

Note that probing corrupted table files is undefined behavior.

close() None[source]

Closes all loaded tables.