-
Notifications
You must be signed in to change notification settings - Fork 0
Tablebase
dblike edited this page Jan 20, 2026
·
1 revision
Lookup endgame positions from the Lichess tablebase server.
Namespace: LichessSharp.Api.Contracts
Access: client.Tablebase
Tablebases provide perfect play information for endgame positions. The Lichess tablebase server supports:
- Standard chess: Up to 7-piece positions (Syzygy tablebases)
- Atomic chess: Up to 6-piece positions
- Antichess: Up to 6-piece positions (with DTW for 4-piece)
Look up a position in the standard chess tablebase.
Task<TablebaseResult> LookupAsync(
string fen,
CancellationToken cancellationToken = default)Example:
using var client = new LichessClient();
// King and Rook vs King
var fen = "4k3/8/8/8/8/8/8/R3K3 w Q - 0 1";
var result = await client.Tablebase.LookupAsync(fen);
Console.WriteLine($"Category: {result.Category}");
Console.WriteLine($"DTZ: {result.Dtz}");
Console.WriteLine($"Checkmate: {result.Checkmate}");
Console.WriteLine($"Stalemate: {result.Stalemate}");
Console.WriteLine("\nBest moves:");
foreach (var move in result.Moves?.Take(5) ?? [])
{
Console.WriteLine($" {move.San} ({move.Uci}): {move.Category}, DTZ={move.Dtz}");
}Look up a position in the atomic chess tablebase.
Task<TablebaseResult> LookupAtomicAsync(
string fen,
CancellationToken cancellationToken = default)Example:
using var client = new LichessClient();
// Atomic chess endgame
var fen = "4k3/8/8/8/8/8/4P3/4K3 w - - 0 1";
var result = await client.Tablebase.LookupAtomicAsync(fen);
Console.WriteLine($"Category: {result.Category}");
Console.WriteLine($"Variant win: {result.VariantWin}");
Console.WriteLine($"Variant loss: {result.VariantLoss}");Look up a position in the antichess tablebase.
Task<TablebaseResult> LookupAntichessAsync(
string fen,
CancellationToken cancellationToken = default)Example:
using var client = new LichessClient();
// Antichess endgame (goal is to lose all pieces)
var fen = "8/8/8/8/8/8/p7/K7 w - - 0 1";
var result = await client.Tablebase.LookupAntichessAsync(fen);
Console.WriteLine($"Category: {result.Category}");
Console.WriteLine($"DTW (Depth to Win): {result.Dtw}");
// In antichess, winning means losing all your pieces
foreach (var move in result.Moves ?? [])
{
Console.WriteLine($" {move.San}: {move.Category}, DTW={move.Dtw}");
}| Category | Description |
|---|---|
win |
Side to move can force a win |
loss |
Side to move will lose with best play |
draw |
Position is drawn with best play |
cursed-win |
Win, but 50-move rule could prevent it |
blessed-loss |
Lost, but 50-move rule could save it |
maybe-win |
Might be a win (insufficient tablebase coverage) |
maybe-loss |
Might be a loss (insufficient tablebase coverage) |
unknown |
Position not in tablebase |
DTZ measures plies (half-moves) until the 50-move counter resets:
- Zeroing moves: Pawn moves and captures
- Positive DTZ = winning
- Negative DTZ = losing
-
Dtzis rounded,PreciseDtzis exact when available
| Metric | Description | Availability |
|---|---|---|
| DTZ | Distance to zeroing (plies) | Standard (7pc), Variants (6pc) |
| DTC | Distance to conversion | Standard |
| DTM | Distance to mate | Standard (5pc max) |
| DTW | Distance to win | Antichess (4pc max) |
using var client = new LichessClient();
async Task AnalyzeEndgame(string fen)
{
var result = await client.Tablebase.LookupAsync(fen);
Console.WriteLine($"Position: {fen}\n");
// Game state
if (result.Checkmate)
{
Console.WriteLine("CHECKMATE!");
return;
}
if (result.Stalemate)
{
Console.WriteLine("STALEMATE!");
return;
}
if (result.InsufficientMaterial)
{
Console.WriteLine("INSUFFICIENT MATERIAL - Draw");
return;
}
// Evaluation
Console.WriteLine($"Result: {result.Category}");
if (result.Dtz.HasValue)
Console.WriteLine($"DTZ: {result.Dtz} plies");
if (result.Dtm.HasValue)
Console.WriteLine($"DTM: {result.Dtm} plies (mate in {(result.Dtm + 1) / 2} moves)");
// Best moves
Console.WriteLine("\nMoves (best first):");
foreach (var move in result.Moves ?? [])
{
var info = new List<string>();
info.Add(move.Category);
if (move.Dtz.HasValue)
info.Add($"DTZ={move.Dtz}");
if (move.Dtm.HasValue)
info.Add($"DTM={move.Dtm}");
if (move.Zeroing)
info.Add("zeroing");
if (move.Checkmate)
info.Add("checkmate!");
Console.WriteLine($" {move.San}: {string.Join(", ", info)}");
}
}
// Example positions
await AnalyzeEndgame("8/8/8/8/8/5k2/4p3/4K3 w - - 0 1"); // KvKP
await AnalyzeEndgame("8/8/8/8/8/k7/8/KQ6 w - - 0 1"); // KQvK
await AnalyzeEndgame("8/8/8/4k3/8/8/8/4KR2 w - - 0 1"); // KRvK| Property | Type | Description |
|---|---|---|
| Category | string | Position category (win, loss, draw, etc.) |
| Dtz | int? | Distance to zeroing (plies) |
| PreciseDtz | int? | Exact DTZ if available |
| Dtc | int? | Distance to conversion |
| Dtm | int? | Distance to mate |
| Dtw | int? | Distance to win (antichess) |
| Checkmate | bool | Is checkmate |
| Stalemate | bool | Is stalemate |
| VariantWin | bool | Is variant win |
| VariantLoss | bool | Is variant loss |
| InsufficientMaterial | bool | Insufficient material |
| Moves | IReadOnlyList<TablebaseMove>? | Legal moves, best first |
| Property | Type | Description |
|---|---|---|
| Uci | string | Move in UCI notation |
| San | string | Move in SAN notation |
| Category | string | Category after this move |
| Dtz | int? | DTZ after this move |
| PreciseDtz | int? | Exact DTZ after this move |
| Dtc | int? | DTC after this move |
| Dtm | int? | DTM after this move |
| Dtw | int? | DTW after this move |
| Zeroing | bool | Is zeroing move |
| Conversion | bool | Is conversion move |
| Checkmate | bool | Delivers checkmate |
| Stalemate | bool | Causes stalemate |
| VariantWin | bool | Is variant win |
| VariantLoss | bool | Is variant loss |
| InsufficientMaterial | bool | Leads to insufficient material |
- Analysis API - Cloud evaluations
- Opening Explorer API - Opening statistics