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
|
|
@ -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