summaryrefslogtreecommitdiff
path: root/src/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval.c')
-rwxr-xr-xsrc/eval.c209
1 files changed, 113 insertions, 96 deletions
diff --git a/src/eval.c b/src/eval.c
index 17793da..35ee663 100755
--- a/src/eval.c
+++ b/src/eval.c
@@ -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];