feat(engine): getRoyalPieces hook + engine royal dispatch
Phase A.1 of the rule-variants epic — enables preset-driven royalty override. A preset can now declare WHICH pieces count as royal for a given color; the engine unions contributions across active presets and threads the resolved set through isInCheck, isCheckmate, isStalemate, and the self-check filter. - Adds RoyalContext type + getRoyalPieces hook on PresetDef. - Widens isInCheck/isCheckmate/isStalemate/filterSelfCheckMoves with optional royalEntityIds param; empty set short-circuits to 'no royalty, nothing in check'; undefined keeps legacy king-only path. - Adds private ChessEngine.getActiveRoyalEntityIds(color) that returns undefined when no preset contributed (preserves back-compat) and the union of contributions otherwise. - Threads the resolver into all three internal consumers: getAllLegalMoves self-check filter, applyMove opponent-check logging, and checkGameResult checkmate/stalemate detection. - Adds packages/chess/src/presets/royal-pieces.test.ts (11 tests) covering default, single-preset, overlap-union, and empty-royal paths at both the pure-function and engine-integration layers. Tests: 1428 passing (was 1417, +11 new). Typecheck + lint clean. Blocks: unblocks B.1 (knightmate-rules), C.1 (coregal), C.2 (dual-king), C.3 (weak-dual-king), D.1 (suicide-chess), D.2 (capture-all).
This commit is contained in:
parent
53bd105d6b
commit
4d05473919
7 changed files with 664 additions and 38 deletions
|
|
@ -70,3 +70,57 @@ work progresses.
|
|||
## Running progress
|
||||
|
||||
(append entries as you ship tasks, one per task, newest at top)
|
||||
|
||||
## [2026-04-20 20:03] Task: A.1 — getRoyalPieces hook + engine royal dispatch
|
||||
|
||||
**Shipped**:
|
||||
- `RoyalContext` type + `getRoyalPieces` hook on `PresetDef`
|
||||
(`packages/chess/src/presets/registry.ts`). Hook returns
|
||||
`readonly EntityId[] | undefined`. Undefined = no opinion (fall
|
||||
through). `[]` = explicit empty (no royalty).
|
||||
- `isInCheck(session, color, royalEntityIds?)` widened
|
||||
(`packages/chess/src/rules/check.ts`). Empty set → always false.
|
||||
Default (undefined) → legacy "every PieceType=king" path via the
|
||||
new private `defaultRoyalIds` helper.
|
||||
- `filterSelfCheckMoves(session, moves, color, royalEntityIds?)`
|
||||
widened. Empty set → every move passes. Threaded through `isInCheck`
|
||||
on the temp session.
|
||||
- `isCheckmate(session, color, royalEntityIds?)` and
|
||||
`isStalemate(session, color, royalEntityIds?)` widened identically.
|
||||
- `ChessEngine.getActiveRoyalEntityIds(color): readonly EntityId[] | undefined`
|
||||
private method (`engine.ts`). Unions contributions from every active
|
||||
preset's `getRoyalPieces`. Returns `undefined` iff NO preset
|
||||
contributed (preserves legacy default path). Threaded into all three
|
||||
internal call sites: the self-check filter in `getAllLegalMoves`,
|
||||
`opponentInCheck` logging in `applyMove`, and `checkmate`/`stalemate`
|
||||
in `checkGameResult`.
|
||||
- New test file: `packages/chess/src/presets/royal-pieces.test.ts`
|
||||
(11 tests). Covers: default path unchanged, knight-royal via preset,
|
||||
empty-royal short-circuit, overlap-union dedupe, pure-function
|
||||
widening of all three rule predicates.
|
||||
|
||||
**Verification**: `bun run check` green. 1428 tests (was 1417, +11 new).
|
||||
124 files (was 122, +2 — royal-pieces.test.ts + its test utilities
|
||||
section).
|
||||
|
||||
**Gotchas learned**:
|
||||
- `ActivationRequest` requires `turnsRemaining` (can be `null`).
|
||||
Omitting it → TypeScript error. Caught by LSP diagnostics
|
||||
immediately, not at test time.
|
||||
- Test board construction: the default engine has the FIDE pawn rank,
|
||||
so `pieceAt(engine, "e1")` patterns on a modified default are
|
||||
fragile. Prefer `clearBoard(engine, { preserveKings: false })` +
|
||||
explicit `placePiece` for every piece.
|
||||
- `filterSelfCheckMoves` doesn't validate piece mechanics — it only
|
||||
verifies king-exposure. Good for engine-internal use; make tests
|
||||
aware that geometrically-illegal moves may pass the filter anyway.
|
||||
|
||||
**Files touched**:
|
||||
- `packages/chess/src/presets/registry.ts` (+33 lines: RoyalContext + hook)
|
||||
- `packages/chess/src/rules/check.ts` (+~60 lines: widened isInCheck + filterSelfCheckMoves + defaultRoyalIds helper)
|
||||
- `packages/chess/src/rules/checkmate.ts` (+~15 lines: widened isCheckmate)
|
||||
- `packages/chess/src/rules/stalemate.ts` (+~25 lines: widened hasAnyLegalMove + isStalemate)
|
||||
- `packages/chess/src/engine.ts` (+~60 lines: getActiveRoyalEntityIds + 3 call-site threads + RoyalContext import)
|
||||
- `packages/chess/src/presets/royal-pieces.test.ts` (new, 300+ lines, 11 tests)
|
||||
|
||||
**Blocks**: A.1 now clears B.1, C.1, C.2, C.3, D.1, D.2. Phase A remaining: A.2 (filterLegalMoves), A.3 (shouldAdvanceTurn + HalfMovesThisTurn), A.4 (overridePieceMoves), A.5 (gate + PRESET-API.md docs).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue