feat(engine): overridePieceMoves hook
Phase A.4 of the rule-variants epic — adds the 'replace the default move generator for this piece' extension point. First non-undefined wins; later matches emit a dev-mode console.warn. The winning set SKIPS default-generator + transformMoveGenerator + getExtraMoves + en-passant/castling/promotion synthesis; filterMoves still composes on top. - Adds overridePieceMoves hook on PresetDef with full docs covering execution order, skipped downstream steps, filterMoves layering, and collision semantics. - engine.getAllLegalMoves per-piece loop now checks overrides first; override path replaces moves entirely; default path unchanged when every preset returns undefined. - Collision warning is dev-only (suppressed when NODE_ENV=production). First registered preset wins; second's return is ignored but console.warn names both preset ids. - New override-piece-moves.test.ts (7 tests): default knight count baseline, lame-knight single-square override, undefined-declines fallthrough, collision warning fires with both preset ids in the message, production-mode suppression, filterMoves composes on top of overrides, unrelated piece types unaffected. Tests: 1448 passing (was 1441, +7 new). Blocks: unblocks E.1 (berolina-pawns), E.2 (berolina-pawns-2).
This commit is contained in:
parent
f9475e9739
commit
1a11491a15
4 changed files with 488 additions and 61 deletions
|
|
@ -194,3 +194,53 @@ section).
|
|||
- `session.allFacts()` automatically carries the new fact across
|
||||
serialization boundaries (snapshot/restore) without protocol
|
||||
changes — no server-side work needed for the A.3 addition.
|
||||
|
||||
## [2026-04-20 20:17] Task: A.4 — overridePieceMoves hook
|
||||
|
||||
**Shipped**:
|
||||
- `overridePieceMoves` hook on `PresetDef`
|
||||
(`packages/chess/src/presets/registry.ts`). Signature:
|
||||
`(engine, pieceId) => readonly LegalMove[] | undefined`.
|
||||
- `engine.getAllLegalMoves` restructured for per-piece dispatch:
|
||||
1. Poll every scoped preset's `overridePieceMoves`. First
|
||||
non-undefined wins.
|
||||
2. If override wins → replace moves entirely. SKIP: default
|
||||
type-registry generator, `transformMoveGenerator` chain,
|
||||
`getExtraMoves` for this piece, en-passant/castling/promotion
|
||||
synthesis (preset owns those mechanics).
|
||||
3. If no override → unchanged default path (type registry +
|
||||
transforms + en-passant + castling + promotion +
|
||||
`getExtraMoves`).
|
||||
4. `filterMoves` runs REGARDLESS (layering stays useful).
|
||||
5. Collision: second non-undefined return triggers
|
||||
`console.warn` (dev only — suppressed when `NODE_ENV=production`).
|
||||
First winner stands.
|
||||
- New test file: `override-piece-moves.test.ts` (7 tests). Covers:
|
||||
baseline knight count unchanged, lame-knight prototype, undefined-
|
||||
return fallthrough, collision warning fires, production-mode
|
||||
suppression, `filterMoves` composes on top of overrides, unrelated
|
||||
piece types unaffected.
|
||||
|
||||
**Verification**: `bun run check` green. 1448 tests (was 1441, +7).
|
||||
|
||||
**Gotchas**:
|
||||
- `engine.getPieceAt` is private. Test presets need occupancy
|
||||
checks → use `engine.session.allFacts().find(f => f.attr === "Position" && f.value === sq)`.
|
||||
Same friction every future preset test will hit. Flagged for
|
||||
Phase A.5 docs consideration but leaving the private as-is per
|
||||
"don't refactor during features".
|
||||
- Override collisions are a guardrail, not opt-in. The design
|
||||
choice is "warn, don't throw" because the incompatibleWith graph
|
||||
is the authoritative contract — crashing on collision would
|
||||
make it harder to iteratively develop two competing overrides.
|
||||
|
||||
## Phase A status at end of 20:17
|
||||
|
||||
All 4 hooks landed on master:
|
||||
- A.1: 4d05473 — getRoyalPieces + engine royal dispatch
|
||||
- A.2: db8145f — filterLegalMoves
|
||||
- A.3: f9475e9 — shouldAdvanceTurn + HalfMovesThisTurn
|
||||
- A.4: (next commit) — overridePieceMoves
|
||||
|
||||
Remaining in Phase A: A.5 — verification gate + PRESET-API.md
|
||||
hook-ordering doc + phase summary.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue