summaryrefslogtreecommitdiff
path: root/src/board_representation/EVAL.md
diff options
context:
space:
mode:
Diffstat (limited to 'src/board_representation/EVAL.md')
-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