summaryrefslogtreecommitdiff
path: root/src/board_representation
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-09-05 00:19:59 -0700
committerScott Gasch <[email protected]>2026-09-05 00:19:59 -0700
commit2ce3570dc6aa67f82dd6f02fc4e518be3e33aabf (patch)
tree111f28a4b9587be62e3252aebc4c64b7d8350f4f /src/board_representation
parent5883f5a64f4f464b877b7637b8e13c25f7d208fc (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.md51
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