docs(preset-api): rule variants gallery + RULES.md cross-refs
Phase F.5 (docs portion) of the rule-variants epic. - PRESET-API.md gains a 'Rule Variants Gallery' section summarizing the 14 new presets grouped by category (King Variants, Objectives, Multi-move, Movement). Flags which are scope-aware. Documents the reusable scope-flip pattern for future asymmetric presets. New section on 'ongoing' two-phase protocol for onCheckGameResult composition. - RULES.md gains a 'Rule Variants Gallery (v2, 2026)' section cross-referencing each of the 14 presets with greenchess.net where applicable. Overview table bumps from 15 rules to 29. Also documents the new 'dual-classic' starting layout. Tests: 1651 passing (docs-only; no test delta). (Full Playwright regression + final commit still to come as part of F.5 once the F.4 e2e spec lands.)
This commit is contained in:
parent
bd20032767
commit
ed2f0cc660
2 changed files with 174 additions and 0 deletions
|
|
@ -369,3 +369,126 @@ This document drives implementation tasks **P3.4 – P3.8**.
|
|||
- If a pawn on d5 promotes and the promoted piece ends on d5, the promoted piece suffers poison (promotion does not grant immunity).
|
||||
- Poison fires exactly once per turn per occupant: a piece cannot take 2 damage for being on a poisoned square for two half-moves, because end-of-turn evaluation is per-player-turn.
|
||||
- Order of resolution: poison damage resolves *before* `king-heals`, so a king that enters a poisoned square while in check will lose HP from poison and not heal (since it is in check), and may be retracted if hp reaches 0.
|
||||
|
||||
---
|
||||
|
||||
## Rule Variants Gallery (v2, 2026)
|
||||
|
||||
The following 14 presets were added in the 2026 rule-variants epic.
|
||||
Their design is cross-referenced against the greenchess.net variant
|
||||
catalogue (category 4):
|
||||
[https://greenchess.net/variants.php?cat=4](https://greenchess.net/variants.php?cat=4).
|
||||
|
||||
Each preset below includes a one-line greenchess cross-reference
|
||||
where applicable.
|
||||
|
||||
| # | ID | Name | Category | greenchess.net |
|
||||
|---|---|---|---|---|
|
||||
| 16 | `knightmate-rules` | Knightmate | King Variants | [Knightmate](https://greenchess.net/variants.php?cat=4) |
|
||||
| 17 | `coregal` | Coregal | King Variants | Coregal — king+queen royal |
|
||||
| 18 | `dual-king` | Dual King | King Variants | Two kings (strong) |
|
||||
| 19 | `weak-dual-king` | Weak Dual King | King Variants | Two kings (weak) |
|
||||
| 20 | `double-move` | Double Move | Multi-move | Both sides play 2 half-moves |
|
||||
| 21 | `monster-rules` | Monster | Multi-move | [Monster Chess](https://greenchess.net/variants.php?cat=4) |
|
||||
| 22 | `first-promotion-wins` | First to Promote Wins | Objectives | Pairs with Pawns-Only layout |
|
||||
| 23 | `suicide-chess` | Suicide Chess | Objectives | Losing Chess / Antichess |
|
||||
| 24 | `capture-all` | Capture All | Objectives | Wipe-out variant |
|
||||
| 25 | `extinction-chess` | Extinction | Objectives | [Extinction Chess](https://greenchess.net/variants.php?cat=4) |
|
||||
| 26 | `berolina-pawns` | Berolina Pawns | Movement Modifier | [Berolina Chess](https://greenchess.net/variants.php?cat=4) |
|
||||
| 27 | `berolina-pawns-2` | Berolina Pawns (Extended) | Movement Modifier | Berolina + sideways captures |
|
||||
| 28 | `bouncing-pieces` | Bouncing Pieces | Board Geometry | Reflect off file edges |
|
||||
| 29 | `bouncing-pieces-2` | Bouncing Pieces (Extended) | Board Geometry | Reflect off all four edges |
|
||||
|
||||
### Knightmate
|
||||
|
||||
**ID**: `knightmate-rules` · **Scope-aware**: no · **Mode**: hook (getRoyalPieces)
|
||||
|
||||
Each side's knights are ROYAL instead of the king. The king is a normal piece with no special status — it can be captured, moved into attacked squares, and is not subject to self-check filtering. Mate the last knight to win. Canonically paired with the `knightmate` starting layout (queen replaced by a royal knight, 3 knights total per side).
|
||||
|
||||
### Coregal
|
||||
|
||||
**ID**: `coregal` · **Scope-aware**: no · **Mode**: hook (getRoyalPieces)
|
||||
|
||||
Both the KING and the QUEEN are royal. Attack or mate on either ends the game. If the queen is captured, the king remains royal (degrades gracefully to standard chess). Pins affect both royals — moving a pinned queen that would expose the king is illegal, and vice versa. Composes naturally with `piece-hp`: both royals take damage independently.
|
||||
|
||||
### Dual King
|
||||
|
||||
**ID**: `dual-king` · **Scope-aware**: no · **Mode**: hook (getRoyalPieces) · **Preferred layout**: `dual-classic`
|
||||
|
||||
Two kings per side. All kings are royal; mating EITHER king ends the game ("strong" variant). Paired with the `dual-classic` layout (queens replaced by a second king on d1/d8).
|
||||
|
||||
### Weak Dual King
|
||||
|
||||
**ID**: `weak-dual-king` · **Scope-aware**: no · **Mode**: hooks (getRoyalPieces + shouldFilterSelfCheck + onCheckGameResult)
|
||||
|
||||
Two kings per side, but losing one is SURVIVABLE. Game ends only when a side has zero kings, or every remaining king is simultaneously mated. Opts out of the self-check filter so "sacrifice" moves (letting one king get captured while the other stays safe) are legal. The `onCheckGameResult` hook declares terminal only on the 0-royal or all-royals-mated conditions.
|
||||
|
||||
### Double Move
|
||||
|
||||
**ID**: `double-move` · **Scope-aware**: no · **Mode**: hook (shouldAdvanceTurn)
|
||||
|
||||
Each side plays TWO half-moves per turn before the flip. Turn order: WW BB WW BB. Checkmate on either half-move ends the game immediately — the attacking side does not "get another half-move". Composes with `piece-hp`, `king-heals`, `first-promotion-wins`.
|
||||
|
||||
### Monster
|
||||
|
||||
**ID**: `monster-rules` · **Scope-aware**: YES · **Mode**: hook (shouldAdvanceTurn)
|
||||
|
||||
Asymmetric multi-move. With `scope: "white"` (canonical Monster pairing), white plays 2 half-moves per turn and black plays 1. With `scope: "black"`, the asymmetry flips. With `scope: "both"`, both sides play 2 (equivalent to `double-move`; prefer that preset for that mode). Paired canonically with the `monster` layout (white king + 4 pawns vs. full black army).
|
||||
|
||||
### First to Promote Wins
|
||||
|
||||
**ID**: `first-promotion-wins` · **Scope-aware**: no · **Mode**: hooks (onBeforeMove + onAfterMove + onCheckGameResult)
|
||||
|
||||
The first player to promote a pawn wins the game immediately. First promotion LOCKS the result; later promotions don't overwrite. Does NOT opt out of the self-check filter (so pinned pawns that would expose the king still can't promote — this is the conservative choice; a permissive follow-up could add that opt-out separately). Paired with the `pawns-only` layout for a race-to-queen variant.
|
||||
|
||||
### Suicide Chess
|
||||
|
||||
**ID**: `suicide-chess` · **Scope-aware**: no · **Mode**: hooks (filterLegalMoves + getRoyalPieces + shouldFilterSelfCheck + onCheckGameResult) · **aka Losing Chess / Antichess**
|
||||
|
||||
Lose all your pieces to WIN. Captures are COMPULSORY: if any capture is legal, the mover must capture. Kings are not royal (empty royal set). The self-check filter is off. Stalemate-wins rule: the side with no legal moves WINS (inverted standard stalemate). The side that reaches 0 pieces first wins.
|
||||
|
||||
### Capture All
|
||||
|
||||
**ID**: `capture-all` · **Scope-aware**: no · **Mode**: hooks (getRoyalPieces + shouldFilterSelfCheck + onCheckGameResult)
|
||||
|
||||
The INVERSE of suicide-chess. Capture every enemy piece to WIN. Captures are NOT compulsory (ordinary legal-move semantics). Kings are not royal. Composes with `piece-hp`: only lethal damage decrements the piece count.
|
||||
|
||||
### Extinction
|
||||
|
||||
**ID**: `extinction-chess` · **Scope-aware**: no · **Mode**: hook (onCheckGameResult) · **Configurable**
|
||||
|
||||
Win by wiping out every enemy piece of a specific TYPE (default: `"pawn"`). Target is configurable via `engine.presetState<{ targetType: PieceType }>("extinction-chess")`. Unlike suicide-chess / capture-all, this preset does NOT opt out of royalty — the king remains royal and FIDE checkmate rules still apply until extinction triggers. Target `"king"` effectively means "capture any king wins" and requires self-check opt-out via another preset to be practically reachable.
|
||||
|
||||
### Berolina Pawns
|
||||
|
||||
**ID**: `berolina-pawns` · **Scope-aware**: YES · **Mode**: hook (overridePieceMoves)
|
||||
|
||||
Pawns push forward DIAGONALLY and capture forward ORTHOGONALLY (inverse of FIDE pawns). Diagonal double-push from home rank, promotions on either push or capture reaching last rank. En-passant NOT implemented (deferred; document in future). Scope chooses which side(s) use the rule: `scope: "white"` only white pawns are berolina, `scope: "black"` only black, `scope: "both"` both sides.
|
||||
|
||||
### Berolina Pawns (Extended)
|
||||
|
||||
**ID**: `berolina-pawns-2` · **Scope-aware**: YES · **Mode**: hook (overridePieceMoves)
|
||||
|
||||
Like `berolina-pawns` but ALSO allows SIDEWAYS captures (adjacent file, same rank). Same scope-flip semantics.
|
||||
|
||||
### Bouncing Pieces
|
||||
|
||||
**ID**: `bouncing-pieces` · **Scope-aware**: no · **Mode**: hook (getExtraMoves)
|
||||
|
||||
Bishop and queen diagonal rays REFLECT off the left (a-file) and right (h-file) edges once, continuing in the reflected direction until they hit a friendly block, capture an enemy, or leave the rank. Queens' orthogonal rays are unchanged. No double-bounce (that's bouncing-pieces-2). Incompatible with `wrap-board` (wrapping geometry is undefined under reflection).
|
||||
|
||||
### Bouncing Pieces (Extended)
|
||||
|
||||
**ID**: `bouncing-pieces-2` · **Scope-aware**: no · **Mode**: hook (getExtraMoves)
|
||||
|
||||
Like `bouncing-pieces` but rays also reflect off TOP (rank 8) and BOTTOM (rank 1) edges. Capped at 2 total reflections per ray to prevent infinite zigzag on empty boards. Incompatible with `bouncing-pieces` and `wrap-board`.
|
||||
|
||||
---
|
||||
|
||||
## New Starting Layouts
|
||||
|
||||
### Dual Classic
|
||||
|
||||
**ID**: `dual-classic` (source: premade) · Added in the 2026 epic.
|
||||
|
||||
Variant of FIDE with queens removed and replaced by a second king per side. White: kings on d1 + e1, rooks/bishops/knights/pawns standard. Black: mirror. Canonical pairing with `dual-king` (strong) or `weak-dual-king`.
|
||||
|
|
|
|||
|
|
@ -541,6 +541,55 @@ For preset tests that exercise hooks, see:
|
|||
|
||||
---
|
||||
|
||||
## Rule Variants Gallery (2026 epic)
|
||||
|
||||
The following 14 presets shipped in the rule-variants epic, mirroring variants from greenchess.net/variants.php?cat=4. All compose with the existing presets via the hook surface documented above — no engine changes beyond the 4 new hooks shipped in Phase A.
|
||||
|
||||
**King Variants** — redefine what counts as "royal":
|
||||
- `knightmate-rules` — Every knight of `color` is royal; kings are ordinary pieces.
|
||||
- `coregal` — King AND queen are royal; mate on either ends the game.
|
||||
- `dual-king` — Multiple kings per side; mate on any one ends the game ("strong").
|
||||
- `weak-dual-king` — Multiple kings per side; mating one is survivable; opts out of self-check filter so "sacrifice" moves on one king are legal.
|
||||
|
||||
**Objectives** — redefine the terminal-state condition:
|
||||
- `first-promotion-wins` — First pawn to promote ends the game. Pairs with `pawns-only` layout.
|
||||
- `suicide-chess` — Lose all pieces to win. Captures compulsory (via `filterLegalMoves`). Empty royal set. Stalemate-wins.
|
||||
- `capture-all` — Inverse of suicide-chess: capture every enemy to win. Captures not compulsory.
|
||||
- `extinction-chess` — Wipe out every enemy of a configurable TARGET TYPE. Target set via `engine.presetState<{ targetType: PieceType }>("extinction-chess")`; default `"pawn"`. King remains royal; default mate rules still apply until extinction triggers.
|
||||
|
||||
**Multi-move** — redefine the turn flip:
|
||||
- `double-move` — Both sides play 2 half-moves per turn.
|
||||
- `monster-rules` — Asymmetric; **scope-aware**. `scope: "white"` → white plays 2, black plays 1 (canonical Monster pairing). `scope: "black"` flips which side gets the double. `scope: "both"` ≡ `double-move`.
|
||||
|
||||
**Movement** — redefine piece-specific move generation:
|
||||
- `berolina-pawns` — **scope-aware**; pawns push diagonally, capture orthogonally. `scope: "white"|"black"|"both"` picks which side(s) use the rule.
|
||||
- `berolina-pawns-2` — Berolina plus SIDEWAYS captures.
|
||||
- `bouncing-pieces` — Bishop/queen diagonals reflect off file edges (a-file, h-file) once.
|
||||
- `bouncing-pieces-2` — Reflects off ALL four edges with a 2-bounce cap.
|
||||
|
||||
### Scope-flip pattern (reusable)
|
||||
|
||||
Two asymmetric presets (`monster-rules`, `berolina-pawns`, `berolina-pawns-2`) implement **scope-flippable** semantics by inspecting their own `scope` live at hook time:
|
||||
|
||||
```ts
|
||||
let scope: "white" | "black" | "both" = "both";
|
||||
for (const entry of engine.activePresets.list()) {
|
||||
if (entry.id === MY_ID) {
|
||||
scope = entry.scope;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Then branch on `scope === "both" || scope === relevantColor`.
|
||||
```
|
||||
|
||||
This makes the activation's `scope` field a first-class rule-authoring knob, not just a duration/lifecycle filter. Any future asymmetric rule that has a "which side does this apply to" question should follow the same pattern.
|
||||
|
||||
### `onCheckGameResult` composition with `"ongoing"`
|
||||
|
||||
The engine implements a two-phase protocol (fixed in commit `7171dfd`): a TERMINAL GameResult from any preset immediately wins; `"ongoing"` sets a soft "suppress defaults" flag and CONTINUES polling; `undefined` means no opinion. This is what lets `piece-hp` (returns `"ongoing"` to suppress FIDE checkmate when HP kings can survive attacks) compose with `first-promotion-wins` / `capture-to-win` / `last-piece-standing` / `extinction-chess` without any preset short-circuiting the others. See `engine.checkGameResult` for the implementation.
|
||||
|
||||
---
|
||||
|
||||
## Post-landing backlog
|
||||
|
||||
Documented but NOT yet available:
|
||||
|
|
@ -549,5 +598,7 @@ Documented but NOT yet available:
|
|||
- Per-preset UI panels (not just overlays) — extension slot for sidebar widgets.
|
||||
- Server-side piece-type manifest echo — when custom types are authored outside the shared `packages/chess`.
|
||||
- Save-state migration — versioning for saves that predate attribute additions.
|
||||
- Berolina en-passant — deferred for v1.
|
||||
- Extinction-chess UI cycling — setting target type via a drawer chip.
|
||||
|
||||
File issues or propose extensions via pull request.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue