summaryrefslogtreecommitdiff
path: root/src/eval.c
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-09-16 08:02:21 -0700
committerScott Gasch <[email protected]>2026-09-16 08:02:21 -0700
commit966a0ef4da9cf3911eb3da0533179199808717b4 (patch)
treee09363b574215ef0d8996155a5ab24314db2dd69 /src/eval.c
parentb91c8453f3fe21c8ccd3568923d8e39141c9c945 (diff)
Retire cPawns/cNonPawns piece-location lists in favor of bbPawns/bbPieces/cKingSq, and hoist two redundant TotalNonPawnCount POPCNT calls out of per-node hot loops.
POSITION no longer stores cPawns[2][8], cNonPawns[2][16], uPawnCount[2], uNonPawnCount[2][8], or uWhiteSqBishopCount[2] -- every reader now goes through PawnMaterial/TotalNonPawnCount/WhiteSqBishopCount/KingPosition (chess.h), computed from the already-incrementally-maintained bbPawns/ bbPieces/cKingSq bitboards via a single -mpopcnt POPCNT instead of a stored counter. move.c's make/unmake loses the list-swap-on-removal bookkeeping entirely. GNUmakefile now passes -mpopcnt so the popcount builtins actually compile to one instruction instead of clang's ~15-op SWAR fallback. Measured a small but real nps regression from the naive swap (search.c's QSearch move-filter and eval.c's _EvalKing were each recomputing the same TotalNonPawnCount sum on every candidate move / twice per node); hoisted both to a single call per node instead. Net result across a same-code self-play match: ~1541.5 knps candidate vs ~1505.7 knps head_reference. A third hoist (FindEnprisePiece out of SelectBestWithHistory) was tried and reverted -- its cache isn't actually loop-invariant within a node (populated from inside Eval(), which doesn't run before every selection call), caught by a DEBUG-build ASSERT before it landed. Co-Authored-By: Claude Sonnet 5 <[email protected]>
Diffstat (limited to 'src/eval.c')
-rw-r--r--src/eval.c261
1 files changed, 120 insertions, 141 deletions
diff --git a/src/eval.c b/src/eval.c
index d310817..6764349 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -30,57 +30,24 @@ Revision History:
// loop -- O(popcount) iterations plus call overhead. Redirected via
// #define, the same mechanism chess.h already uses for the OTHER
// direction (#ifdef CROUTINES routes CountBits/FirstBit/LastBit to the
-// slow C fallbacks) -- this routes them to fast inline compiler
-// builtins instead, for every existing call site below with no further
-// edits. Gated on !CROUTINES so the CROUTINES debug/comparison build
-// still gets the real (slow, cross-checked) implementations.
-//
-// _FastCoorFromBitBoardRank1ToRank8 also bakes in the wrong-bit-clear
-// fix applied to bitboard.c's real CoorFromBitBoardRank1ToRank8 (that
-// function used to clear the LOWEST set bit via `*pbb &= (*pbb - 1)`
-// regardless of uLastBit, correct only when a single bit was set) --
-// this version clears the bit it actually just reported, via BBSQUARE.
+// slow C fallbacks) -- this routes them to the fast inline
+// FastCountBits/FastCoorFromBitBoardRank8ToRank1/
+// FastCoorFromBitBoardRank1ToRank8 wrappers (chess.h) instead, for
+// every existing call site below with no further edits. Those used to
+// be duplicated here as file-local statics; promoted to chess.h so
+// every other translation unit's bitboard-scan loops (recogn.c,
+// board.c, generate.c, movesup.c, probe.c, testmove.c -- added during
+// the cNonPawns/cPawns/uPawnCount/uNonPawnCount retirement work) get
+// the fast path too, not just eval.c -- confirmed by disassembly that
+// those files were still emitting real callq+PLT relocations to the
+// slow extern versions before this. Gated on !CROUTINES so the
+// CROUTINES debug/comparison build still gets the real (slow,
+// cross-checked) implementations.
//
#ifndef CROUTINES
-static ULONG INLINE
-_FastCountBits(IN BITBOARD bb)
-{
- return (ULONG)__builtin_popcountll(bb);
-}
-
-static COOR INLINE
-_FastCoorFromBitBoardRank8ToRank1(IN OUT BITBOARD *pbb)
-{
- COOR c = ILLEGAL_COOR;
- ULONG uBitIndex;
-
- if (*pbb)
- {
- uBitIndex = (ULONG)__builtin_ctzll(*pbb);
- c = BIT_NUMBER_TO_COOR(uBitIndex);
- *pbb &= (*pbb - 1);
- }
- return c;
-}
-
-static COOR INLINE
-_FastCoorFromBitBoardRank1ToRank8(IN OUT BITBOARD *pbb)
-{
- COOR c = ILLEGAL_COOR;
- ULONG uBitIndex;
-
- if (*pbb)
- {
- uBitIndex = (ULONG)(63 - __builtin_clzll(*pbb));
- c = BIT_NUMBER_TO_COOR(uBitIndex);
- *pbb &= ~BBSQUARE[uBitIndex];
- }
- return c;
-}
-
-#define CountBits _FastCountBits
-#define CoorFromBitBoardRank8ToRank1 _FastCoorFromBitBoardRank8ToRank1
-#define CoorFromBitBoardRank1ToRank8 _FastCoorFromBitBoardRank1ToRank8
+#define CountBits FastCountBits
+#define CoorFromBitBoardRank8ToRank1 FastCoorFromBitBoardRank8ToRank1
+#define CoorFromBitBoardRank1ToRank8 FastCoorFromBitBoardRank1ToRank8
#endif // !CROUTINES
@@ -1762,7 +1729,7 @@ Return value:
// CANDIDATE_PASSER_BY_RANK value (an exact duplicate of the
// term just added above, not a different angle on it), now a
// fractional modifier.
- if (pos->uNonPawnCount[xColor][0] == 1)
+ if (TotalNonPawnCount(pos, xColor) == 1)
{
EVAL_TERM(uColor,
PAWN,
@@ -1809,7 +1776,7 @@ Return value:
ASSERT(IS_VALID_COLOR(uColor));
if (pHash->bbPasserLocations[uColor])
{
- ASSERT(pos->uPawnCount[uColor] > 0);
+ ASSERT(FastCountBits(pos->bbPawns[uColor]) > 0);
pFriend = BLACK_PAWN | uColor;
cLeftmostPasser = cRightmostPasser = ILLEGAL_COOR;
// Leftmost/rightmost is just a min/max over FILE(c) -- no
@@ -2068,7 +2035,6 @@ Return value:
FOREACH_COLOR(uColor)
{
ASSERT(IS_VALID_COLOR(uColor));
- ASSERT(CountBits(pos->bbPawns[uColor]) == pos->uPawnCount[uColor]);
for (u = A; u <= H; u++)
{
@@ -2133,15 +2099,14 @@ Return value:
FOREACH_COLOR(uColor)
{
ASSERT(IS_VALID_COLOR(uColor));
- ASSERT(pos->uPawnCount[uColor] <= 8);
ASSERT(CountBits(pos->bbPawns[uColor]) <= 8);
d1 = 16 * g_iAhead[uColor];
- for (u = 0;
- u < pos->uPawnCount[uColor];
- u++)
{
- c = pos->cPawns[uColor][u];
+ BITBOARD bbPawnsToWalk = pos->bbPawns[uColor];
+
+ while (IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bbPawnsToWalk)))
+ {
ASSERT(IS_ON_BOARD(c));
ASSERT(IS_PAWN(pos->rgSquare[c].pPiece));
ASSERT((1 < RANK(c)) && (RANK(c) < 8));
@@ -2382,6 +2347,7 @@ Return value:
// Handle passers / candidate passers
//
_EvaluateCandidatePasser(pos, pHash, c);
+ }
}
}
@@ -2415,7 +2381,7 @@ Return value:
//
ASSERT((uDoubled[WHITE] >= 0) && (uDoubled[WHITE] <= 8));
ASSERT((uDoubled[BLACK] >= 0) && (uDoubled[BLACK] <= 8));
- u = pos->uNonPawnCount[BLACK][ROOK] + pos->uNonPawnCount[BLACK][QUEEN] * 2;
+ u = FastCountBits(pos->bbPieces[BLACK][ROOK]) + FastCountBits(pos->bbPieces[BLACK][QUEEN]) * 2;
u = MINU(u, 3);
EVAL_TERM(BLACK,
PAWN,
@@ -2423,7 +2389,7 @@ Return value:
pHash->iScore[BLACK],
DOUBLED_PAWN_PENALTY_BY_COUNT[u][uDoubled[BLACK]],
"exponential doubled");
- u = pos->uNonPawnCount[WHITE][ROOK] + pos->uNonPawnCount[WHITE][QUEEN] * 2;
+ u = FastCountBits(pos->bbPieces[WHITE][ROOK]) + FastCountBits(pos->bbPieces[WHITE][QUEEN]) * 2;
u = MINU(u, 3);
EVAL_TERM(WHITE,
PAWN,
@@ -2494,10 +2460,9 @@ Return value:
return 0;
}
- cKing = pos->cNonPawns[uColor][0];
+ cKing = KingPosition(pos, uColor);
uCounter = KING_INITIAL_COUNTER_BY_LOCATION[uColor][cKing] >> 1;
ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
- ASSERT(pos->rgSquare[cKing].uIndex == 0);
ASSERT(IS_ON_BOARD(cKing));
ASSERT(GET_COLOR(pos->rgSquare[cKing].pPiece) == uColor);
@@ -2638,7 +2603,7 @@ Return value:
// scaled by the same filestormopenfile-derived factor.
static SCORE KING_FILE_EDGE_KICKER = -5;
ULONG ufColor = FLIP(uColor);
- COOR c = pos->cNonPawns[uColor][0];
+ COOR c = KingPosition(pos, uColor);
SCORE iScore = 0;
COOR cFileSq, cSquare;
ULONG u, v;
@@ -2723,7 +2688,7 @@ Routine description:
+4, +2, +0
};
ULONG ufColor = FLIP(uColor);
- COOR c = pos->cNonPawns[uColor][0];
+ COOR c = KingPosition(pos, uColor);
COOR cFileSq, cSquare;
ULONG u, v;
BITBOARD bb;
@@ -2815,8 +2780,8 @@ Return value:
**/
{
UINT64 u64Key = pos->u64PawnSig ^
- g_u64SigSeeds[pos->cNonPawns[WHITE][0]][KING][WHITE] ^
- g_u64SigSeeds[pos->cNonPawns[BLACK][0]][KING][BLACK];
+ g_u64SigSeeds[KingPosition(pos, WHITE)][KING][WHITE] ^
+ g_u64SigSeeds[KingPosition(pos, BLACK)][KING][BLACK];
ULONG uSlot = (ULONG)u64Key & (KING_SAFETY_HASH_TABLE_SIZE - 1);
KING_SAFETY_HASH_ENTRY *pEntry = &ctx->rgKingSafetyHash[uSlot];
#ifdef PERF_COUNTERS
@@ -3706,14 +3671,13 @@ Return value:
// count, no x-ray -- simply excluded by the friendly-occupied
// mask, nothing else needed.
//
- pos->bb = bbPc;
{
BITBOARD bbAttack = _BishopAttacksBB(c, pos->bbOccupied);
BITBOARD bbEnemySame = pos->bbPieces[xColor][BISHOP] |
pos->bbPieces[xColor][KNIGHT];
BITBOARD bbEnemyGEContinue = pos->bbPieces[xColor][ROOK] |
pos->bbPieces[xColor][QUEEN] |
- COOR_TO_BB(pos->cNonPawns[xColor][0]);
+ COOR_TO_BB(KingPosition(pos, xColor));
BITBOARD bbFriendBQ = pos->bbPieces[uColor][BISHOP] |
pos->bbPieces[uColor][QUEEN];
BITBOARD bbUnsafeForMinor = pos->bbPawnAttacks[xColor];
@@ -3813,7 +3777,7 @@ Return value:
((IS_ON_BOARD(c + 15 * g_iBehind[uColor])) &&
(pos->rgSquare[c + 15 * g_iBehind[uColor]].pPiece==p))));
#endif
- u = DISTANCE(c, pos->cNonPawns[xColor][0]);
+ u = DISTANCE(c, KingPosition(pos, xColor));
i = BISHOP_UNASSAILABLE_BY_DIST_FROM_EKING[u];
EVAL_TERM(uColor,
BISHOP,
@@ -3893,7 +3857,7 @@ Return value:
// if so give bonus for outposted knight which increases the
// closer it is to the enemy king and the more pawns it has
// supporting it.
- uDist = DISTANCE(c, pos->cNonPawns[xColor][0]);
+ uDist = DISTANCE(c, KingPosition(pos, xColor));
ASSERT((uDist > 0) && (uDist <= 8));
bb = pos->bbPawns[xColor] &
(~pHash->bbStationaryPawns[xColor]);
@@ -3926,7 +3890,7 @@ Return value:
{
if (IS_SQUARE_WHITE(c))
{
- if (pos->uWhiteSqBishopCount[xColor])
+ if (WhiteSqBishopCount(pos, xColor))
{
EVAL_TERM(uColor,
KNIGHT,
@@ -3938,8 +3902,8 @@ Return value:
}
else
{
- if (pos->uNonPawnCount[xColor][BISHOP] -
- pos->uWhiteSqBishopCount[xColor])
+ if (FastCountBits(pos->bbPieces[xColor][BISHOP]) -
+ WhiteSqBishopCount(pos, xColor))
{
EVAL_TERM(uColor,
KNIGHT,
@@ -4111,8 +4075,8 @@ Return value:
ROOK,
c,
pos->iScore[uColor],
- ROOK_VALUE_AS_PAWNS_COME_OFF[pos->uPawnCount[uColor] +
- pos->uPawnCount[FLIP(uColor)]],
+ ROOK_VALUE_AS_PAWNS_COME_OFF[FastCountBits(pos->bbPawns[uColor]) +
+ FastCountBits(pos->bbPawns[FLIP(uColor)])],
"increase in value/pawns");
//
@@ -4145,7 +4109,7 @@ Return value:
BITBOARD bbEnemyOcc = _BuildFriendlySideBB(pos, FLIP(uColor));
BITBOARD bbEnemySame = pos->bbPieces[FLIP(uColor)][ROOK];
BITBOARD bbEnemyGEContinue = pos->bbPieces[FLIP(uColor)][QUEEN] |
- COOR_TO_BB(pos->cNonPawns[FLIP(uColor)][0]);
+ COOR_TO_BB(KingPosition(pos, FLIP(uColor)));
BITBOARD bbFriendRQ = pos->bbPieces[uColor][ROOK] |
pos->bbPieces[uColor][QUEEN];
BITBOARD bbUnsafeForRook = pos->bbPawnAttacks[FLIP(uColor)] |
@@ -4274,7 +4238,7 @@ Return value:
ASSERT(IS_ON_BOARD(c));
if ((c & 0xF0) == BACK_RANK_MASK[uColor])
{
- cSquare = pos->cNonPawns[uColor][0];
+ cSquare = KingPosition(pos, uColor);
ASSERT(IS_ON_BOARD(cSquare));
if ((cSquare & 0xF0) == BACK_RANK_MASK[uColor])
{
@@ -4323,7 +4287,7 @@ Return value:
ASSERT(p && IS_QUEEN(p));
uColor = GET_COLOR(p);
ASSERT(IS_VALID_COLOR(uColor));
- cKing = pos->cNonPawns[FLIP(uColor)][0];
+ cKing = KingPosition(pos, FLIP(uColor));
ASSERT(IS_ON_BOARD(cKing));
ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
@@ -4444,7 +4408,8 @@ static void
_EvalKing(IN OUT POSITION *pos,
IN const COOR c,
IN const PAWN_HASH_ENTRY *pHash,
- IN SEARCHER_THREAD_CONTEXT *ctx)
+ IN SEARCHER_THREAD_CONTEXT *ctx,
+ IN const ULONG uTotalNonPawnsBothSides)
/**
Routine description:
@@ -4454,6 +4419,12 @@ Parameters:
POSITION *pos,
COOR c,
PAWN_HASH_ENTRY *pHash,
+ ULONG uTotalNonPawnsBothSides : TotalNonPawnCount(pos, WHITE) +
+ TotalNonPawnCount(pos, BLACK), hoisted up to Eval() (chess.h's
+ TotalNonPawnCount is a POPCNT now, not a stored field -- see
+ its comment) since this function runs twice per Eval() call
+ (once per king) and used to recompute the identical sum both
+ times.
Return value:
@@ -4834,7 +4805,7 @@ Return value:
//
// Special code for kings in the endgame
//
- u = pos->uNonPawnCount[WHITE][0] + pos->uNonPawnCount[BLACK][0];
+ u = uTotalNonPawnsBothSides;
if (u < 8)
{
// Encourage kings to come to the center when safe.
@@ -4880,8 +4851,8 @@ Return value:
bb = (pos->bbPawns[WHITE] | pos->bbPawns[BLACK]);
while(IS_ON_BOARD(cSquare = CoorFromBitBoardRank8ToRank1(&bb)))
{
- i += (DISTANCE(cSquare, pos->cNonPawns[BLACK][0]) -
- DISTANCE(cSquare, pos->cNonPawns[WHITE][0]));
+ i += (DISTANCE(cSquare, KingPosition(pos, BLACK)) -
+ DISTANCE(cSquare, KingPosition(pos, WHITE)));
}
EVAL_TERM(WHITE,
KING,
@@ -4933,8 +4904,8 @@ Return value:
{
return(FALSE);
}
- ASSERT((pos->uNonPawnCount[WHITE][0] == 1) ||
- (pos->uNonPawnCount[BLACK][0] == 1))
+ ASSERT((TotalNonPawnCount(pos, WHITE) == 1) ||
+ (TotalNonPawnCount(pos, BLACK) == 1))
// Both deferred past the no-passer early return above -- no need to
// pay for this on the common case (most positions have no passer at
@@ -4943,13 +4914,13 @@ Return value:
// the pre-lazy-exit segment whenever that's true).
uRacerDist[BLACK] = 99;
uRacerDist[WHITE] = 99;
- fDontCountMeOut[BLACK] = ((RANK(pos->cNonPawns[BLACK][0]) <= 3) &&
- (pos->uPawnCount[BLACK] != 0));
- fDontCountMeOut[WHITE] = ((RANK(pos->cNonPawns[WHITE][0]) >= 6) &&
- (pos->uPawnCount[WHITE] != 0));
+ fDontCountMeOut[BLACK] = ((RANK(KingPosition(pos, BLACK)) <= 3) &&
+ (pos->bbPawns[BLACK] != 0));
+ fDontCountMeOut[WHITE] = ((RANK(KingPosition(pos, WHITE)) >= 6) &&
+ (pos->bbPawns[WHITE] != 0));
FOREACH_COLOR(uColor)
{
- if (pos->uNonPawnCount[FLIP(uColor)][0] == 1)
+ if (TotalNonPawnCount(pos, FLIP(uColor)) == 1)
{
d1 = 16 * g_iAhead[uColor];
ASSERT((d1 * 2) == (32 * g_iAhead[uColor]));
@@ -4960,7 +4931,7 @@ Return value:
{
// If the enemy king can take this passer and is
// on the move, all bets are off!
- cKing = pos->cNonPawns[FLIP(uColor)][0];
+ cKing = KingPosition(pos, FLIP(uColor));
ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
ASSERT(GET_COLOR(pos->rgSquare[cKing].pPiece) != uColor);
if (pos->uToMove == FLIP(uColor) &&
@@ -4994,7 +4965,7 @@ Return value:
uPawnDist);
}
- cKing = pos->cNonPawns[uColor][0];
+ cKing = KingPosition(pos, uColor);
ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
ASSERT(GET_COLOR(pos->rgSquare[cKing].pPiece) == uColor);
@@ -5132,22 +5103,22 @@ Return value:
//
// Consider distance from friend king / enemy king
//
- i = (8 - DISTANCE(c, pos->cNonPawns[uColor][0]));
+ i = (8 - DISTANCE(c, KingPosition(pos, uColor)));
if (((uColor == WHITE) &&
- ((pos->cNonPawns[BLACK][0] >> 4) <= (c >> 4))) ||
+ ((KingPosition(pos, BLACK) >> 4) <= (c >> 4))) ||
((uColor == BLACK) &&
- ((pos->cNonPawns[WHITE][0] >> 4) >= (c >> 4)))) {
+ ((KingPosition(pos, WHITE) >> 4) >= (c >> 4)))) {
//
// The enemy king is ahead of the passer
//
- i += FILE_DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]) * 4;
+ i += FILE_DISTANCE(c, KingPosition(pos, FLIP(uColor))) * 4;
}
else
{
//
// The enemy king is behind the passer
//
- i += 10 + DISTANCE(c, pos->cNonPawns[FLIP(uColor)][0]) * 4;
+ i += 10 + DISTANCE(c, KingPosition(pos, FLIP(uColor))) * 4;
}
i *= PASSER_MATERIAL_UP_SCALER[pos->uArmyScaler[FLIP(uColor)]];
i /= 8;
@@ -5162,8 +5133,8 @@ Return value:
// If a side is a piece down then the other side's passers
// are even more dangerous.
//
- if (pos->uNonPawnCount[uColor][0] >
- pos->uNonPawnCount[FLIP(uColor)][0])
+ if (TotalNonPawnCount(pos, uColor) >
+ TotalNonPawnCount(pos, FLIP(uColor)))
{
i = (PASSER_BY_RANK[uColor][RANK(c)] / 2);
EVAL_TERM(uColor,
@@ -5246,8 +5217,8 @@ Return value:
// engine will not like positions like KNB vs KRP - the side with
// the pawn has the winning chances.
//
- ULONG uAheadPawnCount = pos->uPawnCount[uAhead];
- ULONG uInverseBehindPieceCount = 9 - MINU(9, pos->uNonPawnCount[uBehind][0]);
+ ULONG uAheadPawnCount = FastCountBits(pos->bbPawns[uAhead]);
+ ULONG uInverseBehindPieceCount = 9 - MINU(9, TotalNonPawnCount(pos, uBehind));
EVAL_TERM(uAhead,
0,
ILLEGAL_COOR,
@@ -5299,18 +5270,16 @@ Return value:
**/
{
COOR c;
- ULONG u;
+ BITBOARD bbNonKingPieces;
POSITION *pos = &ctx->sPosition;
ULONG uSide = pos->uToMove;
#ifdef DEBUG
PIECE p;
#endif
- for (u = 1;
- u < pos->uNonPawnCount[uSide][0];
- u++)
+ bbNonKingPieces = NON_KING_PIECES_BB(pos, uSide);
+ while (IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bbNonKingPieces)))
{
- c = pos->cNonPawns[uSide][u];
#ifdef DEBUG
ASSERT(IS_ON_BOARD(c));
p = pos->rgSquare[c].pPiece;
@@ -5436,9 +5405,9 @@ Return value:
ULONG uColor;
FOREACH_COLOR(uColor)
{
- ULONG uBishopCount = pos->uNonPawnCount[uColor][BISHOP];
+ ULONG uBishopCount = FastCountBits(pos->bbPieces[uColor][BISHOP]);
ASSERT(uBishopCount <= 10);
- ULONG uWhiteSqBishopCount = pos->uWhiteSqBishopCount[uColor];
+ ULONG uWhiteSqBishopCount = WhiteSqBishopCount(pos, uColor);
ASSERT(uWhiteSqBishopCount <= 10);
FLAG fPair = ((uBishopCount > 1) &
(uWhiteSqBishopCount != 0) &
@@ -5501,7 +5470,7 @@ Return value:
// A pawn always gives some winning chances (it can always try to
// queen with support) -- nothing below applies.
//
- if (pos->uPawnCount[uSide] > 0)
+ if (FastCountBits(pos->bbPawns[uSide]) > 0)
{
return(TRUE);
}
@@ -5511,9 +5480,9 @@ Return value:
// never enough material to force mate (K+N or K+B vs anything is
// never a forced win on material alone).
//
- if ((2 == pos->uNonPawnCount[uSide][0]) &&
- (1 == (pos->uNonPawnCount[uSide][KNIGHT] +
- pos->uNonPawnCount[uSide][BISHOP])))
+ if ((2 == TotalNonPawnCount(pos, uSide)) &&
+ (1 == (FastCountBits(pos->bbPieces[uSide][KNIGHT]) +
+ FastCountBits(pos->bbPieces[uSide][BISHOP]))))
{
return(FALSE);
}
@@ -5524,16 +5493,16 @@ Return value:
// force a win either -- e.g. KRB vs KR can be held by the
// defender with correct play.
//
- iMajorDiff = (INT)(pos->uNonPawnCount[uSide][ROOK] +
- 2 * pos->uNonPawnCount[uSide][QUEEN]) -
- (INT)(pos->uNonPawnCount[uEnemy][ROOK] +
- 2 * pos->uNonPawnCount[uEnemy][QUEEN]);
+ iMajorDiff = (INT)(FastCountBits(pos->bbPieces[uSide][ROOK]) +
+ 2 * FastCountBits(pos->bbPieces[uSide][QUEEN])) -
+ (INT)(FastCountBits(pos->bbPieces[uEnemy][ROOK]) +
+ 2 * FastCountBits(pos->bbPieces[uEnemy][QUEEN]));
if ((1 == iMajorDiff) || (-1 == iMajorDiff))
{
- iMinorDiff = (INT)(pos->uNonPawnCount[uEnemy][KNIGHT] +
- pos->uNonPawnCount[uEnemy][BISHOP]) -
- (INT)(pos->uNonPawnCount[uSide][KNIGHT] +
- pos->uNonPawnCount[uSide][BISHOP]);
+ iMinorDiff = (INT)(FastCountBits(pos->bbPieces[uEnemy][KNIGHT]) +
+ FastCountBits(pos->bbPieces[uEnemy][BISHOP])) -
+ (INT)(FastCountBits(pos->bbPieces[uSide][KNIGHT]) +
+ FastCountBits(pos->bbPieces[uSide][BISHOP]));
if (iMajorDiff == iMinorDiff)
{
return(FALSE);
@@ -5548,12 +5517,12 @@ Return value:
// excluded, since that has one bishop, not zero) -- both are
// genuine, if sometimes technique-heavy, forced wins.
//
- if ((2 == pos->uNonPawnCount[uSide][KNIGHT]) &&
- (0 == pos->uNonPawnCount[uSide][BISHOP]) &&
- (0 == pos->uNonPawnCount[uSide][ROOK]) &&
- (0 == pos->uNonPawnCount[uSide][QUEEN]) &&
- (1 == pos->uNonPawnCount[uEnemy][0]) &&
- (0 == pos->uPawnCount[uEnemy]))
+ if ((2 == FastCountBits(pos->bbPieces[uSide][KNIGHT])) &&
+ (0 == FastCountBits(pos->bbPieces[uSide][BISHOP])) &&
+ (0 == FastCountBits(pos->bbPieces[uSide][ROOK])) &&
+ (0 == FastCountBits(pos->bbPieces[uSide][QUEEN])) &&
+ (1 == TotalNonPawnCount(pos, uEnemy)) &&
+ (0 == FastCountBits(pos->bbPawns[uEnemy])))
{
return(FALSE);
}
@@ -5603,11 +5572,11 @@ EvalLookForDrawishSituations(POSITION *pos,
}
// If this is a BOOC endgame, push towards draw score too.
- if ((pos->uNonPawnCount[WHITE][0] == 2) &&
- (pos->uNonPawnCount[BLACK][0] == 2) &&
- (pos->uNonPawnCount[WHITE][BISHOP] == 1) &&
- (pos->uNonPawnCount[BLACK][BISHOP] == 1) &&
- (pos->uWhiteSqBishopCount[WHITE] != pos->uWhiteSqBishopCount[BLACK])) {
+ if ((TotalNonPawnCount(pos, WHITE) == 2) &&
+ (TotalNonPawnCount(pos, BLACK) == 2) &&
+ (FastCountBits(pos->bbPieces[WHITE][BISHOP]) == 1) &&
+ (FastCountBits(pos->bbPieces[BLACK][BISHOP]) == 1) &&
+ (WhiteSqBishopCount(pos, WHITE) != WhiteSqBishopCount(pos, BLACK))) {
*piScoreForSideToMove = g_iDrawScore[uColor] +
((*piScoreForSideToMove - g_iDrawScore[uColor]) / 4);
}
@@ -5703,9 +5672,9 @@ Return value:
UINT64 u64MaterialSetupTimer = SystemReadTimeStampCounter();
#endif
pos->iScore[uColor] =
- (pos->uPawnMaterial[uColor] + pos->uNonPawnMaterial[uColor]);
+ (PawnMaterial(pos, uColor) + pos->uNonPawnMaterial[uColor]);
pos->iScore[xColor] =
- (pos->uPawnMaterial[xColor] + pos->uNonPawnMaterial[xColor]);
+ (PawnMaterial(pos, xColor) + pos->uNonPawnMaterial[xColor]);
#ifdef EVAL_DUMP
EvalTraceClear();
Trace("Material:\n%d\t\t%d\n", pos->iScore[WHITE], pos->iScore[BLACK]);
@@ -5887,8 +5856,8 @@ Return value:
// Look for won passers races. Note: This code cannot trust the
// state of the attack tables yet!
//
- if ((pos->uNonPawnCount[WHITE][0] == 1) ||
- (pos->uNonPawnCount[BLACK][0] == 1))
+ if ((TotalNonPawnCount(pos, WHITE) == 1) ||
+ (TotalNonPawnCount(pos, BLACK) == 1))
{
(void)_EvalPasserRacesAgainstLoneKings(pos, pHash);
#ifdef EVAL_DUMP
@@ -6146,7 +6115,7 @@ Return value:
//
// This is a "position is closed|open" number.
//
- pos->uClosedScaler = (pos->uPawnCount[WHITE] + pos->uPawnCount[BLACK]) -
+ pos->uClosedScaler = (FastCountBits(pos->bbPawns[WHITE]) + FastCountBits(pos->bbPawns[BLACK])) -
(pHash->uNumUnmovedPawns[WHITE] + pHash->uNumUnmovedPawns[BLACK]) +
(pHash->uNumRammedPawns);
ASSERT(pos->uClosedScaler >= 0);
@@ -6305,8 +6274,15 @@ Return value:
#endif
}
- // Evaluate the two kings last.
- c = pos->cNonPawns[uColor][0];
+ // Evaluate the two kings last. Compute both sides' non-pawn count
+ // once here rather than in _EvalKing itself -- it's called twice
+ // below (once per king) and used to recompute the identical
+ // TotalNonPawnCount(WHITE)+TotalNonPawnCount(BLACK) sum both times.
+ {
+ ULONG uTotalNonPawnsBothSides =
+ TotalNonPawnCount(pos, WHITE) + TotalNonPawnCount(pos, BLACK);
+
+ c = KingPosition(pos, uColor);
#ifdef DEBUG
ASSERT(IS_ON_BOARD(c));
{
@@ -6316,13 +6292,14 @@ Return value:
ASSERT(IS_KING(pDebugKing));
}
#endif
- TIMED_EVAL_CALL(ctx, u64CyclesEvalKing, _EvalKing(pos, c, pHash, ctx));
+ TIMED_EVAL_CALL(ctx, u64CyclesEvalKing,
+ _EvalKing(pos, c, pHash, ctx, uTotalNonPawnsBothSides));
#ifdef EVAL_DUMP
Trace("After our K at %s:\n%d\t\t%d\n",
CoorToString(c), pos->iScore[WHITE], pos->iScore[BLACK]);
#endif
- c = pos->cNonPawns[xColor][0];
+ c = KingPosition(pos, xColor);
#ifdef DEBUG
ASSERT(IS_ON_BOARD(c));
{
@@ -6332,7 +6309,9 @@ Return value:
ASSERT(IS_KING(pDebugKing));
}
#endif
- TIMED_EVAL_CALL(ctx, u64CyclesEvalKing, _EvalKing(pos, c, pHash, ctx));
+ TIMED_EVAL_CALL(ctx, u64CyclesEvalKing,
+ _EvalKing(pos, c, pHash, ctx, uTotalNonPawnsBothSides));
+ }
#ifdef EVAL_DUMP
Trace("After enemy K at %s:\n%d\t\t%d\n",
CoorToString(c), pos->iScore[WHITE], pos->iScore[BLACK]);
@@ -6432,11 +6411,11 @@ Return value:
{
(*piPositional)[WHITE] =
MAX(pos->iScore[WHITE] -
- (SCORE)(pos->uPawnMaterial[WHITE] + pos->uNonPawnMaterial[WHITE]),
+ (SCORE)(PawnMaterial(pos, WHITE) + pos->uNonPawnMaterial[WHITE]),
-(FUTILITY_BASE_MARGIN_FULL / 2));
(*piPositional)[BLACK] =
MAX(pos->iScore[BLACK] -
- (SCORE)(pos->uPawnMaterial[BLACK] + pos->uNonPawnMaterial[BLACK]),
+ (SCORE)(PawnMaterial(pos, BLACK) + pos->uNonPawnMaterial[BLACK]),
-(FUTILITY_BASE_MARGIN_FULL / 2));
ctx->sPlyInfo[ctx->uPly].uLastPositionalSource = EVAL_POSITIONAL_SOURCE_FULL;
}