summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/chess.h13
-rwxr-xr-xsrc/eval.c185
2 files changed, 108 insertions, 90 deletions
diff --git a/src/chess.h b/src/chess.h
index 7ff9994..2e9189a 100755
--- a/src/chess.h
+++ b/src/chess.h
@@ -716,6 +716,19 @@ typedef struct _POSITION
// bbRookAttacks/bbQueenAttacks that will retire the rest of it.
BITBOARD bbPawnAttacks[2];
+ // First mover of the bbMinorAttacks pair (knight only for now --
+ // bishop is a separate, later step; see board_representation/
+ // EVAL.md section 2). "Which squares does this side's knight(s)
+ // attack" -- computed via g_KnightAttacksBB[c] and OR'd in per
+ // knight, Eval()-scoped scratch like bbPawnAttacks above, cleared
+ // once per Eval() call in _ClearAttackTables since (unlike
+ // bbPawnAttacks) it's accumulated across multiple pieces via |=,
+ // not assigned wholesale. Bishop still writes its own minor-bit
+ // contribution into the old rgSquare[c|8].bvAttacks structure for
+ // now -- every consumer that needs "any minor's attack," not just
+ // knight's, ORs both sources together until bishop converts too.
+ BITBOARD bbMinorAttacks[2];
+
ULONG uWhiteSqBishopCount[2]; // num bishops on white squares
SCORE iMaterialBalance[2]; // material balance
diff --git a/src/eval.c b/src/eval.c
index 7287caf..10a1327 100755
--- a/src/eval.c
+++ b/src/eval.c
@@ -1152,6 +1152,59 @@ Return value:
}
+//
+// Transitional helper, board_representation/EVAL.md section 2: during
+// the piece-by-piece migration off bvAttacks, knight now writes its
+// attacks into pos->bbMinorAttacks directly while bishop (not
+// converted yet) still writes the old per-square
+// rgSquare[c|8].bvAttacks[color].small.uMinor bit. Every consumer
+// that needs "does any minor (knight or bishop) attack this square"
+// goes through this one function instead of each hand-rolling its own
+// OR of the two sources -- once bishop converts too, this collapses
+// to a plain pos->bbMinorAttacks[color] read and this whole function
+// goes away; it is not meant to be a permanent fixture.
+//
+// DEBUG-only: cross-checked against an independent recomputation
+// (g_KnightAttacksBB / _BishopAttacksBB, both already-trusted
+// primitives used elsewhere in move generation, entirely separate
+// code from either the ray-walk's uBit bookkeeping or the new
+// bitboard population) so a bug in either mechanism fails loudly here
+// instead of silently drifting into a wrong score several plies deep
+// in search -- exactly the failure mode a prior, larger version of
+// this same migration hit and had to be rolled back for.
+//
+static FLAG
+_IsSquareAttackedByMinor(IN POSITION *pos,
+ IN ULONG uColor,
+ IN COOR c)
+{
+ BITBOARD sq = COOR_TO_BB(c);
+ FLAG fResult = ((pos->bbMinorAttacks[uColor] & sq) != 0) ||
+ (pos->rgSquare[c|8].bvAttacks[uColor].small.uMinor != 0);
+#ifdef DEBUG
+ {
+ BITBOARD bbTrueMinorAttacks = 0;
+ ULONG u;
+ for (u = 1; u < pos->uNonPawnCount[uColor][0]; u++)
+ {
+ COOR cPiece = pos->cNonPawns[uColor][u];
+ PIECE p = pos->rgSquare[cPiece].pPiece;
+ if (IS_KNIGHT(p))
+ {
+ bbTrueMinorAttacks |= g_KnightAttacksBB[cPiece];
+ }
+ else if (IS_BISHOP(p))
+ {
+ bbTrueMinorAttacks |= _BishopAttacksBB(cPiece, pos->bbOccupied);
+ }
+ }
+ ASSERT(((bbTrueMinorAttacks & sq) != 0) == (fResult != 0));
+ }
+#endif
+ return fResult;
+}
+
+
static ULONG
_WhoControlsSquareFast(IN POSITION *pos,
IN COOR c)
@@ -1186,11 +1239,13 @@ Return value:
ULONG uWhite = pos->rgSquare[c|8].bvAttacks[WHITE].uSmall |
pos->rgSquare[c|8].bvAttacks[WHITE].uXray |
((pos->bbPawnAttacks[WHITE] & COOR_TO_BB(c)) ?
- PAWN_BIT : 0);
+ PAWN_BIT : 0) |
+ (_IsSquareAttackedByMinor(pos, WHITE, c) ? MINOR_BIT : 0);
ULONG uBlack = pos->rgSquare[c|8].bvAttacks[BLACK].uSmall |
pos->rgSquare[c|8].bvAttacks[BLACK].uXray |
((pos->bbPawnAttacks[BLACK] & COOR_TO_BB(c)) ?
- PAWN_BIT : 0);
+ PAWN_BIT : 0) |
+ (_IsSquareAttackedByMinor(pos, BLACK, c) ? MINOR_BIT : 0);
ULONG u;
PIECE p;
CHAR ch;
@@ -1260,6 +1315,7 @@ static void
_ClearAttackTables(IN OUT POSITION *pos)
{
register COOR c = 8;
+ pos->bbMinorAttacks[WHITE] = pos->bbMinorAttacks[BLACK] = 0;
#if 1
CLEAR_A_SQ; c += 16;
CLEAR_A_SQ; c += 16;
@@ -2840,41 +2896,6 @@ Return value:
**/
{
static const int iPawnStart[2] = { -17, +15 };
- static const UCHAR NMobCaseTable[2][14] =
- {
- {// (black)
- NMOB_MOBILE_SQUARE, // EMPTY_SQUARE (0)
- NMOB_INVALID, // INVALID_PIECE (1)
- NMOB_FRIEND, // BLACK_PAWN (2)
- NMOB_MOBILE_SQUARE, // WHITE_PAWN (3)
- NMOB_FRIEND, // BLACK_KNIGHT (4)
- NMOB_ENEMY_OTHER, // WHITE_KNIGHT (5)
- NMOB_FRIEND, // BLACK_BISHOP (6)
- NMOB_ENEMY_OTHER, // WHITE_BISHOP (7)
- NMOB_FRIEND, // BLACK_ROOK (8)
- NMOB_ENEMY_OTHER, // WHITE_ROOK (9)
- NMOB_FRIEND, // BLACK_QUEEN (10)
- NMOB_ENEMY_OTHER, // WHITE_QUEEN (11)
- NMOB_FRIEND, // BLACK_KING (12)
- NMOB_ENEMY_OTHER, // WHITE_KING (13)
- },
- {// (white)
- NMOB_MOBILE_SQUARE, // EMPTY_SQUARE (0)
- NMOB_INVALID, // INVALID_PIECE (1)
- NMOB_MOBILE_SQUARE, // BLACK_PAWN (2)
- NMOB_FRIEND, // WHITE_PAWN (3)
- NMOB_ENEMY_OTHER, // BLACK_KNIGHT (4)
- NMOB_FRIEND, // WHITE_KNIGHT (5)
- NMOB_ENEMY_OTHER, // BLACK_BISHOP (6)
- NMOB_FRIEND, // WHITE_BISHOP (7)
- NMOB_ENEMY_OTHER, // BLACK_ROOK (8)
- NMOB_FRIEND, // WHITE_ROOK (9)
- NMOB_ENEMY_OTHER, // BLACK_QUEEN (10)
- NMOB_FRIEND, // WHITE_QUEEN (11)
- NMOB_ENEMY_OTHER, // BLACK_KING (12)
- NMOB_FRIEND, // WHITE_KING (13)
- }
- };
static const COOR cKnightAtHome[2][2] =
{
{ B8, G8 }, // BLACK
@@ -2885,7 +2906,6 @@ Return value:
BITBOARD bb;
ULONG uColor;
ULONG uPawnsSupporting;
- ULONG u;
ULONG uMobilitySquares;
SCORE i;
ULONG uDist;
@@ -3045,57 +3065,34 @@ Return value:
//
//
- // Do mobilility and piece relevance. Also update attack tables.
+ // Do mobility and piece relevance. Also update attack tables.
+ //
+ // board_representation/EVAL.md section 1b/2: g_KnightAttacksBB[c]
+ // (generate.c's precomputed table, already used by move
+ // generation) is exactly the old per-square g_iNDeltas walk's
+ // destination set, IS_ON_BOARD baked in at table-build time -- no
+ // per-square branch, no mailbox read, no switch. Knights never
+ // x-ray or have a battery partner, so the old NMobCaseTable's four
+ // cases collapse to two bitboard masks: NMOB_ENEMY_OTHER (any
+ // enemy non-pawn -- count unconditionally) and NMOB_MOBILE_SQUARE
+ // (empty or enemy pawn -- count unless pawn-unsafe). NMOB_FRIEND
+ // needs no term at all, it's just "neither of the above."
//
- uMobilitySquares = 0;
- u = 0;
- ASSERT(g_iNDeltas[u] != 0);
- do
{
- cSquare = c + g_iNDeltas[u];
- if (IS_ON_BOARD(cSquare))
- {
- //
- // Always update the attack bits
- //
- ASSERT((cSquare + 8) == (cSquare | 8));
- pos->rgSquare[cSquare|8].bvAttacks[uColor].small.uMinor = 1;
-
- //
- // See what we hit. Dispatched via switch instead of an
- // indirect call through a function pointer -- same
- // rationale as the bishop ray-walk above.
- //
- p = pos->rgSquare[cSquare].pPiece;
- switch (NMobCaseTable[uColor][p])
- {
- case NMOB_MOBILE_SQUARE:
- uMobilitySquares +=
- !(pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare));
- break;
+ BITBOARD bbAttack = g_KnightAttacksBB[c];
+ BITBOARD bbFriendOcc = _BuildFriendlySideBB(pos, uColor);
+ BITBOARD bbEnemyNonPawnOcc = _BuildFriendlySideBB(pos, FLIP(uColor)) &
+ ~pos->bbPawns[FLIP(uColor)];
+ BITBOARD bbUnsafeForMinor = pos->bbPawnAttacks[FLIP(uColor)];
+ BITBOARD bbMobility;
- case NMOB_ENEMY_OTHER:
- uMobilitySquares += 1;
- break;
-
- case NMOB_FRIEND:
- break;
-
- case NMOB_INVALID:
- default:
- UtilPanic(SHOULD_NOT_GET_HERE,
- NULL, NULL, NULL, NULL,
- __FILE__, __LINE__);
- break;
- }
+ pos->bbMinorAttacks[uColor] |= bbAttack;
- //
- // IDEA: bonus for hitting friendly pawn?
- //
- }
- u++;
+ bbMobility = (bbAttack & bbEnemyNonPawnOcc) |
+ (bbAttack & ~bbFriendOcc & ~bbEnemyNonPawnOcc &
+ ~bbUnsafeForMinor);
+ uMobilitySquares = CountBits(bbMobility);
}
- while(g_iNDeltas[u] != 0);
ASSERT(uMobilitySquares >= 0);
ASSERT(uMobilitySquares <= 8);
EVAL_TERM(uColor,
@@ -3381,14 +3378,14 @@ Return value:
case RMOB_EMPTY:
uCurrentMobility +=
!((pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)) ||
- UNSAFE_FOR_ROOK(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]));
+ _IsSquareAttackedByMinor(pos, FLIP(uColor), cSquare));
fStop = FALSE;
break;
case RMOB_ENEMY_LESS:
uCurrentMobility +=
!((pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)) ||
- UNSAFE_FOR_ROOK(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]));
+ _IsSquareAttackedByMinor(pos, FLIP(uColor), cSquare));
fStop = TRUE;
break;
@@ -3684,14 +3681,18 @@ Return value:
case QMOB_EMPTY:
uTotalMobility +=
!((pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)) ||
- UNSAFE_FOR_QUEEN(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]));
+ _IsSquareAttackedByMinor(pos, FLIP(uColor), cSquare) ||
+ (pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)].uWholeThing &
+ ROOK_BIT));
fStop = FALSE;
break;
case QMOB_ENEMY_LESS:
uTotalMobility +=
!((pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)) ||
- UNSAFE_FOR_QUEEN(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]));
+ _IsSquareAttackedByMinor(pos, FLIP(uColor), cSquare) ||
+ (pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)].uWholeThing &
+ ROOK_BIT));
fStop = TRUE;
break;
@@ -3935,7 +3936,9 @@ Return value:
//
bvAttack = pos->rgSquare[cSquare|8].bvAttacks[ufColor].uSmall |
((pos->bbPawnAttacks[ufColor] & COOR_TO_BB(cSquare)) ?
- PAWN_BIT : 0);
+ PAWN_BIT : 0) |
+ (_IsSquareAttackedByMinor(pos, ufColor, cSquare) ?
+ MINOR_BIT : 0);
{
COOR cRealSquare = cSquare;
cSquare |= 8;
@@ -3943,7 +3946,9 @@ Return value:
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);
+ PAWN_BIT : 0) |
+ (_IsSquareAttackedByMinor(pos, uColor, cRealSquare) ?
+ MINOR_BIT : 0);
}
//