Board-symmetry transforms and position canonicalization for Dice Chess.
Two positions related by a rules-preserving symmetry have identical win probability, so collapsing them to a single canonical representative lets downstream consumers pool statistics (analytics) and share results across equivalent positions (search transposition tables, Monte-Carlo caches).
This object provides two exact symmetries: color-flip (always legal) and horizontal mirror (a win-probability symmetry only when there are no castling rights — see below). Horizontal shift is intentionally excluded: translation is not an isometry of the bounded 8x8 board (it changes a piece's distance to the edge, and therefore its mobility), so it does not preserve win probability.
A vertical board mirror (rank r rank 9 - r) combined with swapping every piece's colour and the side to move. Because Black's downward pawns become White's upward pawns, the result is a strategically identical position with the side to move relabelled (white-to-move black-to-move). It is an involution: colorFlip(colorFlip(s)) == s.
Canonical representative of a position's symmetry class.
Canonical representative of a position's symmetry class.
First color-flips to a white-to-move position (so a position and its color-flip share a representative). Then, only when there are no castling rights (where the file mirror is a valid win-probability symmetry), it also folds horizontal mirror by choosing whichever of the position and its mirror has the smaller DFEN. The result is deterministic and idempotent: canonical(canonical(s)) == canonical(s).
Stable canonical key for a position's symmetry class: the DFEN of canonical.
Stable canonical key for a position's symmetry class: the DFEN of canonical.
Symmetry-equivalent positions produce the same key. The key retains the half-move/full-move counters and dice pool from the DFEN; callers that need a counter-independent identity (e.g. statistics dedup) should normalise those fields themselves.
Returns the color-flipped position: a vertical mirror combined with a colour and side-to-move swap.
Returns the color-flipped position: a vertical mirror combined with a colour and side-to-move swap.
Castling rights are swapped between colours while keeping their side (White king-side Black king-side). The en-passant target squares are mirrored vertically; their files — and therefore the GameFlags file mask — are unchanged. Dice pool, half-move clock and full-move number are preserved, which makes the transform an exact involution.
Returns the file-mirrored position (a h). A pure spatial reflection: colours and the side to move are unchanged, pieces move to the mirrored file, castling rights swap king-side queen-side, and the en-passant files are mirrored.
Returns the file-mirrored position (a h). A pure spatial reflection: colours and the side to move are unchanged, pieces move to the mirrored file, castling rights swap king-side queen-side, and the en-passant files are mirrored.
This is an involution, but it only preserves win probability when there are no castling rights: the board mirror sends the king from the e-file to the d-file, which is not a legal castling configuration. canonical therefore only folds the mirror when castling rights are absent.