King + Rook vs King, exactly solved -- all 399,112 legal positions.
Not a chess engine and not a heuristic evaluator: every legal (white king, white rook, black king, side-to-move) state in this endgame was labeled exactly once, ahead of time, by retrograde analysis working backward from every checkmate, stalemate, and capture-the-rook terminal position. What loads below is that computation's output -- move any piece and the verdict updates from a real, exhaustive lookup, not a live search.
This is the same algorithm family as the Zermelo backward-induction, WIN/LOSE-by-distance labeling we used for the Althofer Prize 3 game on Challenges -- applied here to a chess endgame instead of a number-theory game. Independently verified against a from-scratch Python re-implementation (identical counts both times) and against the textbook fact that every won KRK position is mated in at most 16 full moves with best play: this table's own maximum is exactly 32 ply, 16 full moves, reproduced from scratch rather than assumed.
Board and controls
Loading the tablebase...
Click a piece (white king, white rook, or black king), then click any empty square to move it there -- any arrangement is allowed, including illegal ones, which are labeled as such rather than silently corrected. Toggle whose move it is, or press "Random legal position" to jump straight to a labeled state. "Play optimal line" then animates both sides playing the table's own best move at every ply until checkmate, a draw, or the rook gets captured -- and brings out the two kodama mascots flanking the board, one lit up for whoever's actually on the move.
native_decide — compiled evaluator, trusted beyond the kernelComputed live from the loaded table, not a static image.
?
Math: a finite two-player game with perfect information and no chance has a value at every position (Zermelo, 1913) -- computable exactly by retrograde analysis: label every immediate checkmate/stalemate/capture-the-rook terminal state, then repeatedly extend the labeling one ply further back (a position is a forced win if some move reaches a labeled loss for the opponent; a forced loss if every move reaches a labeled win for the opponent) until nothing changes. That is literally the recursion this table was generated with, and the same recursion (with WIN/LOSE instead of WIN/DRAW/LOSS) underlies the Althofer Prize 3 result on Challenges. Castling and en passant are out of scope by the same convention every published chess tablebase uses (Nalimov, Syzygy, Gaviota, this one alike): positions are indexed by piece placement and side to move only, castling rights treated as already forfeited -- not an oversight, the standard the whole field works under. Machine-checked, not just cross-run: five theorems in Lean 4, decided over all 262,144 (king, rook, king) square triples (64³, legal or not), state both halves of that recursion for this exact table -- every decided position really does have a real, legal move witnessing progress toward its recorded outcome (existence), and no legal move for either side ever does strictly better than the distance already recorded (optimality). What that does and does not buy, exactly: those five are closed with native_decide, which runs the decision procedure through Lean's compiled evaluator and then asserts the result -- it does not re-check it in the kernel. #print axioms says so out loud: each one depends on propext, Classical.choice, Quot.sound plus a generated native_decide axiom of its own. So the trusted base here is Lean's compiler and runtime, not just its kernel -- strictly weaker than a kernel-checked proof, and stated that way here rather than rounded up. The full write-up, including the two exact QGD move-order results, is published at doi:10.5281/zenodo.21797908, which quotes the five theorem statements verbatim. The table those theorems are about is not a private artifact either: it is the exact 524,288 bytes this page just fetched, and the SHA-384 above is the one the paper cites. One real bug surfaced while building the proof, in this page's own move-generation code: a rook move could target White's own king's square without being filtered out. Harmless here in practice (a lookup would simply never favor a target with no table entry), but fixed once found rather than left to that coincidence. Dev: the table is 524,288 bytes (one byte per (king, rook, king, side-to-move) index), generated once by a Node script, independently cross-checked against a from-scratch Python re-implementation, and fetched here with a client-side SHA-384 integrity check against the exact bytes generated -- fetch() doesn't get the browser's native Subresource Integrity the way a <script> tag does, so this page does that check itself in JS instead of skipping it.
A genuine acknowledgment — Dr Dan Rust
There would be no chess on this site without the work of Dr Dan Rust (Senior Lecturer in Applied Mathematics, School of Mathematics & Statistics, The Open University). The founder followed his work out of plain curiosity — a fan — and it is what set off the interest in treating a game on a board as an exact, fully-solved combinatorial object rather than something you play by feel. The particular spark was “Queen reflections: a modification of Wythoff Nim”; the real idea, and the elegance, are his. His work is collected under ORCID 0000-0002-6467-4050.
To be exact about what this is and is not, because credit given carelessly can misrepresent the person receiving it: this is an acknowledgment of inspiration, not a collaboration and not an endorsement. Dr Rust has no involvement in this site and has not reviewed it. The King + Rook vs King tablebase above is our own exact retrograde analysis — a different problem from his combinatorial-game results — and any error on this page is entirely ours, not his. The credit is for the spark that made a curious person go and build something.