diff options
| author | Scott Gasch <[email protected]> | 2026-09-05 00:19:59 -0700 |
|---|---|---|
| committer | Scott Gasch <[email protected]> | 2026-09-05 00:19:59 -0700 |
| commit | 2ce3570dc6aa67f82dd6f02fc4e518be3e33aabf (patch) | |
| tree | 111f28a4b9587be62e3252aebc4c64b7d8350f4f /src/board_representation | |
| parent | 5883f5a64f4f464b877b7637b8e13c25f7d208fc (diff) | |
Maintain pos->bbOccupied incrementally, dedupe its two from-scratch builders
chess.h: add POSITION::bbOccupied (full-board occupancy, both colors,
every piece including kings), maintained incrementally alongside
bbPieces/bbPawns rather than rebuilt on demand -- resolves the open
question in EVAL.md section 0 about whether this is worth doing given
both generate.c and the planned eval.c mobility rewrite need it.
move.c: SlidePiece/SlidePawn/LiftPiece/PlacePiece and their
WithoutSigs variants now maintain bbOccupied at the same choke points
that already maintain bbPieces/bbPawns -- unconditionally, since
occupancy doesn't care about piece type or color. Kings only ever
move through SlidePiece/SlidePieceWithoutSigs (never Lift/Place), so
no separate king-specific update site was needed.
fen.c: populate bbOccupied when parsing a FEN.
board.c: VerifyPositionConsistency cross-checks pos->bbOccupied
against a from-scratch rebuild, same pattern already used for
bbPieces/bbPawns.
generate.c/movesup.c/see.c: replace call sites that rebuilt full
occupancy via _BuildFullOccupiedBB/_BuildOccupiedBB with direct reads
of pos->bbOccupied; delete see.c's _BuildOccupiedBB, which was a
byte-for-byte duplicate of generate.c's _BuildFullOccupiedBB (kept
only as the from-scratch ground truth for the new consistency check
and testgenerate.c's benchmark harness).
testsup.c: GenerateRandomLegalPosition builds POSITIONs by poking
rgSquare/bbPieces/bbPawns directly, bypassing both move.c and fen.c --
a third construction path the above missed. It never set bbOccupied,
so the new VerifyPositionConsistency check failed on every generated
position, and since generation retries until a position verifies, the
self-test suite spun forever (100% CPU, no progress) instead of
crashing outright. Fixed by setting bbOccupied at all four placement
sites (both kings, pawn, non-pawn piece). Full self-test suite and
precommit_check.sh verified clean afterward.
board_representation/EVAL.md: record the bbOccupied decision and
rationale, resolving section 0's open question.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01P6g6iF6mD1Hau6nCZCzwYj
Diffstat (limited to 'src/board_representation')
| -rw-r--r-- | src/board_representation/EVAL.md | 51 |
1 files changed, 47 insertions, 4 deletions
diff --git a/src/board_representation/EVAL.md b/src/board_representation/EVAL.md index 34fb9c3..697ea38 100644 --- a/src/board_representation/EVAL.md +++ b/src/board_representation/EVAL.md @@ -31,10 +31,53 @@ Two things changed since the first draft: attack that number directly, not as a speculative "bitboards are modern, let's use them" exercise. -Open question: both move gen (generate.c) and eval (eval.c) need a -bbOccupied. Is this worth maintaining incrementally (in -MakeMove/LiftPiece/SlidePiece/etc...) so that it will always be on -POSITION and up-to-date? +**Resolved 2026-09-05 (was an open question): yes, move `bbOccupied` +onto `POSITION`, incrementally maintained.** Investigated by reading +`move.c` end to end for how `bbPieces[2][8]`/`bbPawns[2]` -- the +precedent for exactly this kind of incrementally-maintained bitboard +-- actually get updated: + +- Every mutation funnels through a small, fixed set of primitives + (`SlidePiece`, `SlidePawn`, `LiftPiece`, `PlacePiece`, and their + `WithoutSigs` variants) -- `MakeMove`/`UnmakeMove` never touch these + bitboards directly. `bbOccupied` would touch the identical choke + points, not a new set of call sites. +- It's actually *simpler* to maintain than `bbPieces`/`bbPawns`: + those are keyed by piece type and color (an array lookup before the + OR/AND), but occupancy doesn't care what's on a square or whose it + is -- one unconditional clear-from-bit/set-to-bit pair per primitive, + no branch, and it uniformly covers kings too (which today have no + bitboard at all, only the `cNonPawns[.][0]` mailbox slot). +- **Currently it lives on `MOVE_STACK`** (`chess.h`'s `bbOccupied` + field), rebuilt on demand via `_BuildFullOccupiedBB(pos)` + (`generate.c`) -- itself already cheap (11 ORs of `bbPieces`/ + `bbPawns`/king squares, no mailbox scan, per that function's own + comment) -- but called fresh at many independent sites: several in + `generate.c`, four in `movesup.c`, one in `see.c`. Worse, the exact + same 11-OR logic is duplicated verbatim as `_BuildOccupiedBB` + (static, `see.c`) and `_BuildFullOccupiedBB` (non-static, + `generate.c`) -- same function, two names, two files. +- Moving it to `POSITION`, incrementally maintained, means every one + of those call sites (plus this plan's own future `eval.c` mobility + rewrite, which needs the same value for + `_RookAttacksBB`/`_BishopAttacksBB(c, bbOccupied)`) reads one + already-current field instead of independently re-deriving it -- + and dedupes the two identical builder functions into one. +- **Verification is close to free**: `generate.c` already has + `ASSERT(pStack->bbOccupied == _BuildFullOccupiedBB(pos))` at three + call sites, cross-checking the `MOVE_STACK`-cached copy against a + from-scratch rebuild today. The identical assert, repointed at + `pos->bbOccupied`, becomes the DEBUG-build safety net for the + incremental version -- the same pattern that already validated + `bbPieces`/`bbPawns` when they were added. +- **Scoped as standalone, low-risk work, not gated on the rest of + this plan**: move generation benefits from it immediately regardless + of `Eval()`'s progress, so it's worth landing (add the field, touch + the handful of `move.c` primitives, dedupe the two builder + functions, repoint the existing assert, run + `debug_smoke_test.sh`/`precommit_check.sh`) on its own, ahead of or + alongside section 4's toggle work -- not bundled into any single + piece type's toggle. **The movegen project's own findings are the load-bearing precedent here, and they cut both ways -- worth stating plainly before |
