diff options
| author | Scott Gasch <[email protected]> | 2026-09-16 08:02:21 -0700 |
|---|---|---|
| committer | Scott Gasch <[email protected]> | 2026-09-16 08:02:21 -0700 |
| commit | 966a0ef4da9cf3911eb3da0533179199808717b4 (patch) | |
| tree | e09363b574215ef0d8996155a5ab24314db2dd69 /src/eval.c | |
| parent | b91c8453f3fe21c8ccd3568923d8e39141c9c945 (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.c | 261 |
1 files changed, 120 insertions, 141 deletions
@@ -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; } |
