diff options
Diffstat (limited to 'src/eval.c')
| -rwxr-xr-x | src/eval.c | 209 |
1 files changed, 113 insertions, 96 deletions
@@ -1176,10 +1176,21 @@ Return value: **/ { + // + // bvAttacks no longer carries the pawn bit (pawns write + // pos->bbPawnAttacks[2] directly instead, see + // _PopulatePawnAttackBits) -- OR it back in at its usual bit + // position (PAWN_BIT) so g_SwapTable's indexing below sees the + // same bit shape it always has. + // ULONG uWhite = pos->rgSquare[c|8].bvAttacks[WHITE].uSmall | - pos->rgSquare[c|8].bvAttacks[WHITE].uXray; + pos->rgSquare[c|8].bvAttacks[WHITE].uXray | + ((pos->bbPawnAttacks[WHITE] & COOR_TO_BB(c)) ? + PAWN_BIT : 0); ULONG uBlack = pos->rgSquare[c|8].bvAttacks[BLACK].uSmall | - pos->rgSquare[c|8].bvAttacks[BLACK].uXray; + pos->rgSquare[c|8].bvAttacks[BLACK].uXray | + ((pos->bbPawnAttacks[BLACK] & COOR_TO_BB(c)) ? + PAWN_BIT : 0); ULONG u; PIECE p; CHAR ch; @@ -1763,9 +1774,30 @@ Return value: } -#define PAWN_ATTACK_BLACK_DELTA (+15) -#define PAWN_ATTACK_WHITE_DELTA (-17) - +// board_representation/EVAL.md section 2/0d: bitboard replacement for +// the old per-pawn mailbox delta+IS_ON_BOARD population this function +// used to do. pos->bbPawns[2] already has every pawn location +// (incrementally maintained, chess.h) with zero per-pawn iteration +// needed to query it -- the exact shift-and-mask technique +// generate.c's _GenerateAllPawnMovesBB already uses to bulk-generate a +// whole side's pawn captures (its bbCapLeft/bbCapRight, before being +// masked down to actual enemy-occupied squares) is exactly "every +// square this side's pawns attack" -- reused here verbatim, minus the +// enemy-occupancy mask, since attack-bit population doesn't care what +// (if anything) sits on the attacked square. See that function's +// header comment for the full square-numbering/shift-direction +// derivation (WHITE forward = bb >> 8, BLACK forward = bb << 8, +// diagonals need the *opposite* file excluded to prevent same-row +// wraparound) -- not repeated here. +// +// Unlike the old version, this does NOT write PAWN_BIT into +// rgSquare[c|8].bvAttacks -- pos->bbPawnAttacks[2] (chess.h) is now +// the single source of truth for "does a pawn attack this square", +// read directly by every consumer (UNSAFE_FOR_MINOR's old callers, +// UNSAFE_FOR_ROOK/_QUEEN, _EvalKing's bvAttack/bvDefend). Knight/ +// bishop/rook/queen/king still populate/read the rest of bvAttacks +// (uMinor/uRook/uQueen/uKing) the old way, so _ClearAttackTables(pos) +// still needs to run here first. static void _PopulatePawnAttackBits(IN OUT POSITION *pos) /** @@ -1784,81 +1816,15 @@ Return value: **/ { - ULONG u; - COOR c; - COOR cAttack; - - // - // IDEA: combine clearing and initial population somehow? - // - // r - - - - - - l : only check L- and R- - // r - - - - - - l - // R A A A A A A L - // R A A A A A A L - // R A A A A A A L - // R A A A A A A L - // r - - - - - - l - // r - - - - - - l : only check L+ and R+ _ClearAttackTables(pos); - ASSERT(pos->uPawnCount[BLACK] <= 8); - for (u = 0; - u < pos->uPawnCount[BLACK]; - u++) - { - c = pos->cPawns[BLACK][u]; - ASSERT(IS_ON_BOARD(c)); - ASSERT(pos->rgSquare[c].pPiece); - ASSERT(IS_PAWN(pos->rgSquare[c].pPiece)); - ASSERT(GET_COLOR(pos->rgSquare[c].pPiece) == BLACK); - - // - // IDEA: These IS_ON_BOARD checks can be removed by a lookup table. - // - cAttack = c + PAWN_ATTACK_BLACK_DELTA; - if (IS_ON_BOARD(cAttack)) - { - ASSERT((cAttack + 8) == (cAttack|8)); - ASSERT(!IS_ON_BOARD(cAttack|8)); - pos->rgSquare[cAttack|8].bvAttacks[BLACK].small.uPawn = 1; - } - cAttack += 2; - if (IS_ON_BOARD(cAttack)) - { - ASSERT((cAttack + 8) == (cAttack|8)); - cAttack |= 8; - ASSERT(!IS_ON_BOARD(cAttack)); - pos->rgSquare[cAttack].bvAttacks[BLACK].small.uPawn = 1; - } - } - - ASSERT(pos->uPawnCount[WHITE] <= 8); - for (u = 0; - u < pos->uPawnCount[WHITE]; - u++) - { - c = pos->cPawns[WHITE][u]; - ASSERT(IS_ON_BOARD(c)); - ASSERT(pos->rgSquare[c].pPiece); - ASSERT(IS_PAWN(pos->rgSquare[c].pPiece)); - ASSERT(GET_COLOR(pos->rgSquare[c].pPiece) == WHITE); + pos->bbPawnAttacks[BLACK] = + ((pos->bbPawns[BLACK] & ~BBFILE[0]) << 7) | + ((pos->bbPawns[BLACK] & ~BBFILE[7]) << 9); - cAttack = c + PAWN_ATTACK_WHITE_DELTA; - if (IS_ON_BOARD(cAttack)) - { - ASSERT((cAttack + 8) == (cAttack|8)); - ASSERT(!IS_ON_BOARD(cAttack|8)); - pos->rgSquare[cAttack|8].bvAttacks[WHITE].small.uPawn = 1; - } - cAttack += 2; - if (IS_ON_BOARD(cAttack)) - { - ASSERT((cAttack + 8) == (cAttack|8)); - cAttack |= 8; - ASSERT(!IS_ON_BOARD(cAttack)); - pos->rgSquare[cAttack].bvAttacks[WHITE].small.uPawn = 1; - } - } + pos->bbPawnAttacks[WHITE] = + ((pos->bbPawns[WHITE] & ~BBFILE[0]) >> 9) | + ((pos->bbPawns[WHITE] & ~BBFILE[7]) >> 7); } @@ -2170,8 +2136,16 @@ Return value: // cSquare = c + d1; ASSERT(IS_ON_BOARD(cSquare)); - ASSERT((cSquare + 8) == (cSquare | 8)); - if (pos->rgSquare[cSquare|8].bvAttacks[uColor].uWholeThing) + // + // At this point in Eval()'s sequence (inside _EvalPawns, + // before any other piece type has run this call), pawns + // are the only thing that could possibly have marked an + // attack -- bvAttacks itself no longer carries the pawn + // bit at all (see _PopulatePawnAttackBits), so this reads + // pos->bbPawnAttacks directly instead of the (permanently + // zero, at this point in execution) bvAttacks word. + // + if (pos->bbPawnAttacks[uColor] & COOR_TO_BB(cSquare)) { // // Count pawn duos. See "Pawn Power in Chess" pp 10-16 @@ -2193,7 +2167,7 @@ Return value: (FLIP(uColor) * (9 - RANK(cSquare)))); ASSERT(iDuos[uColor] <= (7 * 8)); } - else if (pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)].uWholeThing) + else if (pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)) { // // Detect backwards pawns. See "Pawn Power in Chess" pp 25-27 @@ -2665,7 +2639,7 @@ Return value: ASSERT(GET_COLOR(pos->rgSquare[cSquare].pPiece) == FLIP(uColor)); ASSERT(pos->bbPawns[FLIP(uColor)] & COOR_TO_BB(cSquare)); i += - (pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)].small.uPawn != 0) * + ((pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)) != 0) * TRANSIENT_PAWN_ON_BISHOP_COLOR[cSquare] / 2; } EVAL_TERM(uColor, @@ -2723,13 +2697,13 @@ Return value: { case BMOB_EMPTY: uCurrentMobility += - !UNSAFE_FOR_MINOR(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]); + !(pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)); fStop = FALSE; break; case BMOB_ENEMY_PAWN: uCurrentMobility += - !UNSAFE_FOR_MINOR(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]); + !(pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)); fStop = TRUE; break; @@ -2824,7 +2798,7 @@ Return value: if (TRUE == _IsSquareSafeFromEnemyPawn(pos, c, bb)) { // Defended (and defending) a friendly pawn. - if (pos->rgSquare[c|8].bvAttacks[uColor].small.uPawn) + if (pos->bbPawnAttacks[uColor] & COOR_TO_BB(c)) { #ifdef DEBUG p = BLACK_PAWN | uColor; @@ -3097,7 +3071,7 @@ Return value: { case NMOB_MOBILE_SQUARE: uMobilitySquares += - !UNSAFE_FOR_MINOR(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]); + !(pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)); break; case NMOB_ENEMY_OTHER: @@ -3406,13 +3380,15 @@ Return value: { case RMOB_EMPTY: uCurrentMobility += - !UNSAFE_FOR_ROOK(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]); + !((pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)) || + UNSAFE_FOR_ROOK(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)])); fStop = FALSE; break; case RMOB_ENEMY_LESS: uCurrentMobility += - !UNSAFE_FOR_ROOK(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]); + !((pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)) || + UNSAFE_FOR_ROOK(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)])); fStop = TRUE; break; @@ -3707,13 +3683,15 @@ Return value: { case QMOB_EMPTY: uTotalMobility += - !UNSAFE_FOR_QUEEN(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]); + !((pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)) || + UNSAFE_FOR_QUEEN(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)])); fStop = FALSE; break; case QMOB_ENEMY_LESS: uTotalMobility += - !UNSAFE_FOR_QUEEN(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]); + !((pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)) || + UNSAFE_FOR_QUEEN(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)])); fStop = TRUE; break; @@ -3943,11 +3921,30 @@ Return value: { p = pos->rgSquare[cSquare].pPiece; - cSquare |= 8; - bvAttack = pos->rgSquare[cSquare].bvAttacks[ufColor].uSmall; - bvXray = pos->rgSquare[cSquare].bvAttacks[ufColor].uXray; - pos->rgSquare[cSquare].bvAttacks[uColor].small.uKing = 1; - bvDefend = pos->rgSquare[cSquare].bvAttacks[uColor].uSmall; + // + // bvAttacks no longer carries the pawn bit (pawns write + // pos->bbPawnAttacks[2] directly instead, see + // _PopulatePawnAttackBits) -- OR it back in here from the + // bitboard, keyed off the real board square (cSquare, + // before the |8 below flips it into the invisible-half + // storage index bvAttacks itself uses). bvDefend's OR-in + // (and the .small.uKing = 1 write) must stay after this + // point, same order as before -- bvDefend is meant to + // include this king's own just-set attack/defend bit on + // the square. + // + bvAttack = pos->rgSquare[cSquare|8].bvAttacks[ufColor].uSmall | + ((pos->bbPawnAttacks[ufColor] & COOR_TO_BB(cSquare)) ? + PAWN_BIT : 0); + { + COOR cRealSquare = cSquare; + cSquare |= 8; + bvXray = pos->rgSquare[cSquare].bvAttacks[ufColor].uXray; + pos->rgSquare[cSquare].bvAttacks[uColor].small.uKing = 1; + bvDefend = pos->rgSquare[cSquare].bvAttacks[uColor].uSmall | + ((pos->bbPawnAttacks[uColor] & COOR_TO_BB(cRealSquare)) ? + PAWN_BIT : 0); + } // // Count squares near the king the enemy queen specifically @@ -4850,8 +4847,28 @@ Return value: // save some time. BEFORE ANY CODE BELOW TOUCHES THE ATTACK // TABLES IT NEEDS TO CLEAR/POPULATE THEM THOUGH!!! // - TIMED_EVAL_CALL(ctx, u64CyclesEvalPawns, - pHash = _EvalPawns(ctx, &fDeferred)); +#ifdef EVAL_TIME + { + UINT64 u64PawnTimer = SystemReadTimeStampCounter(); + pHash = _EvalPawns(ctx, &fDeferred); + { + UINT64 u64Elapsed = SystemReadTimeStampCounter() - u64PawnTimer; + ctx->sCounters.tree.u64CyclesEvalPawns += u64Elapsed; + if (fDeferred) + { + ctx->sCounters.tree.u64CyclesEvalPawnsHit += u64Elapsed; + ctx->sCounters.tree.u64CountEvalPawnsHit++; + } + else + { + ctx->sCounters.tree.u64CyclesEvalPawnsMiss += u64Elapsed; + ctx->sCounters.tree.u64CountEvalPawnsMiss++; + } + } + } +#else + pHash = _EvalPawns(ctx, &fDeferred); +#endif ASSERT(NULL != pHash); ASSERT(IS_VALID_FLAG(fDeferred)); pos->iScore[WHITE] += pHash->iScore[WHITE]; |
