diff options
| author | Scott Gasch <[email protected]> | 2026-10-07 08:17:51 -0700 |
|---|---|---|
| committer | Scott Gasch <[email protected]> | 2026-10-07 08:17:51 -0700 |
| commit | d14dbe2a50c220b2adac758c3d4f1a1fa67ece0b (patch) | |
| tree | cbf6d9928bcc41ef833b62b70479113f7d419925 /src/movesup.c | |
| parent | 447130db3df87b40d080dc26429d45e9213c19f7 (diff) | |
Speed up eval/move-gen/SEE; remove EvalLookForDanger, overhaul _EvalKing
SPRT-confirmed improvement (1814 games, st 4.0): candidate nps=1498118
vs head=1378448, avg depth 14.30 vs 13.87, ELO=+24.2+/-16.0,
LOWER95=0.5118, LLR=+3.126 crossing the H1 bound.
Most of the diff is non-semantic speed work across eval.c, generate.c,
movesup.c, see.c, probe.c and friends. Two real semantic changes:
removed EvalLookForDanger and overhauled _EvalKing's king-safety scoring.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Diffstat (limited to 'src/movesup.c')
| -rw-r--r-- | src/movesup.c | 275 |
1 files changed, 136 insertions, 139 deletions
diff --git a/src/movesup.c b/src/movesup.c index e39e52a..d3d2a74 100644 --- a/src/movesup.c +++ b/src/movesup.c @@ -385,10 +385,10 @@ Return value: ASSERT(IS_ON_BOARD(cLocation)); ASSERT(!IS_EMPTY(pos->rgSquare[cLocation].pPiece)); ASSERT(0 != (CHECK_VECTOR_WITH_INDEX(iIndex, BLACK) & (1 << QUEEN))); - + iDelta = CHECK_DELTA_WITH_INDEX(iIndex); ASSERT(iDelta != 0); - + for (cBlockIndex = cRemove + iDelta; IS_ON_BOARD(cBlockIndex); cBlockIndex += iDelta) @@ -400,12 +400,12 @@ Return value: { // // Is it an enemy? - // + // if (OPPOSITE_COLORS(xPiece, uColor)) { // // Does it move the right way to attack? - // + // iIndex = (int)cBlockIndex - (int)cLocation; if (0 != (CHECK_VECTOR_WITH_INDEX(iIndex, WHITE) & (1 << (PIECE_TYPE(xPiece))))) @@ -413,26 +413,26 @@ Return value: return(cBlockIndex); } } - + // // Either we found another friendly piece or an enemy piece // that was unable to reach us. Either way we are safe. - // + // return(ILLEGAL_COOR); } } - + // // We fell off the board without seeing another piece. - // + // return(ILLEGAL_COOR); } -COOR -ExposesCheck(POSITION *pos, - COOR cRemove, +COOR +ExposesCheck(POSITION *pos, + COOR cRemove, COOR cLocation) /** @@ -452,7 +452,7 @@ Parameters: Return value: - COOR : the location of an attacker piece or 0x88 (!IS_ON_BOARD) if + COOR : the location of an attacker piece or 0x88 (!IS_ON_BOARD) if the removal of cRemove does not expose check. **/ @@ -461,13 +461,13 @@ Return value: register COOR cBlockIndex; int iIndex; PIECE xPiece; - + ASSERT(IS_ON_BOARD(cRemove)); ASSERT(IS_ON_BOARD(cLocation)); ASSERT(!IS_EMPTY(pos->rgSquare[cLocation].pPiece)); - + iIndex = (int)cLocation - (int)cRemove; - + // // If there is no way for a queen sitting at the square removed to // reach the square we are testing (i.e. the two squares are not @@ -479,11 +479,11 @@ Return value: return(ILLEGAL_COOR); } iDelta = CHECK_DELTA_WITH_INDEX(iIndex); - for (cBlockIndex = cLocation + iDelta; + for (cBlockIndex = cLocation + iDelta; IS_ON_BOARD(cBlockIndex); cBlockIndex += iDelta) { - if (cBlockIndex == cRemove) + if (cBlockIndex == cRemove) { continue; } @@ -492,12 +492,12 @@ Return value: { // // Is it an enemy? - // + // if (OPPOSITE_COLORS(xPiece, pos->rgSquare[cLocation].pPiece)) { // // Does it move the right way to attack? - // + // iIndex = (int)cBlockIndex - (int)cLocation; if (0 != (CHECK_VECTOR_WITH_INDEX(iIndex, GET_COLOR(xPiece)) & (1 << (PIECE_TYPE(xPiece))))) @@ -505,28 +505,28 @@ Return value: return(cBlockIndex); } } - + // // Either we found another friendly piece or an enemy piece // that was unable to reach us. Either way we are safe. - // + // return(ILLEGAL_COOR); } } - + // // We fell off the board without seeing another piece. - // + // return(ILLEGAL_COOR); } -COOR -ExposesCheckEp(POSITION *pos, - COOR cTest, - COOR cIgnore, - COOR cBlock, - COOR cKing) +COOR +ExposesCheckEp(POSITION *pos, + COOR cTest, + COOR cIgnore, + COOR cBlock, + COOR cKing) /** Routine description: @@ -562,13 +562,13 @@ Return value: // reach the square we are testing (i.e. the two squares are not // on the same rank, file, or diagonal) then no problemo. // - if (0 == (CHECK_VECTOR_WITH_INDEX(iIndex, BLACK) & (1 << QUEEN))) + if (0 == (CHECK_VECTOR_WITH_INDEX(iIndex, BLACK) & (1 << QUEEN))) { return(ILLEGAL_COOR); } - + iDelta = CHECK_DELTA_WITH_INDEX(iIndex); - for (cBlockIndex = cKing + iDelta; + for (cBlockIndex = cKing + iDelta; IS_ON_BOARD(cBlockIndex); cBlockIndex += iDelta) { @@ -583,7 +583,7 @@ Return value: { // // Does it move the right way to attack? - // + // iIndex = (int)cBlockIndex - (int)cKing; if (0 != (CHECK_VECTOR_WITH_INDEX(iIndex, GET_COLOR(xPiece)) & (1 << (PIECE_TYPE(xPiece))))) @@ -595,14 +595,14 @@ Return value: // // Either we found another friendly piece or an enemy piece // that was unable to reach us. Either way we are safe. - // + // return(ILLEGAL_COOR); } } - + // // We fell off the board without seeing another piece. - // + // return(ILLEGAL_COOR); } @@ -657,7 +657,7 @@ Return value: return(0 != (g_PawnAttackOriginBB[uSide][cTest] & pos->bbPawns[uSide])); } -FLAG +FLAG FORCEINLINE InCheckBB(IN POSITION *pos, IN ULONG uSide) /** @@ -740,7 +740,7 @@ Return value: { continue; } - + // // These pieces do not slide, we don't need to look for // blockers. If they can get there then there is nothing @@ -775,16 +775,16 @@ Return value: // // Check the locations a pawn could attack cTest from. - // + // cLocation = cTest + iPawnLoc[uSide]; - if (IS_ON_BOARD(cLocation) && + if (IS_ON_BOARD(cLocation) && (pos->rgSquare[cLocation].pPiece == pPawn[uSide])) { return(TRUE); } - + cLocation += 2; - if (IS_ON_BOARD(cLocation) && + if (IS_ON_BOARD(cLocation) && (pos->rgSquare[cLocation].pPiece == pPawn[uSide])) { return(TRUE); @@ -793,7 +793,7 @@ Return value: } -FLAG +FLAG InCheck(POSITION *pos, ULONG uSide) /** @@ -818,7 +818,7 @@ Return value: #endif ASSERT(IS_VALID_COLOR(uSide)); - + cKingLoc = KingPosition(pos, uSide); #ifdef DEBUG pKing = pos->rgSquare[cKingLoc].pPiece; @@ -830,7 +830,7 @@ Return value: } -static FLAG +static FLAG _SanityCheckPawnMove(POSITION *pos, MOVE mv) /** @@ -856,15 +856,15 @@ Return value: // // General sanity checking... - // - if (!IS_ON_BOARD(cFrom) || !IS_ON_BOARD(cTo)) + // + if (!IS_ON_BOARD(cFrom) || !IS_ON_BOARD(cTo)) { return(FALSE); } - + // // Sanity check promotions. - // + // if (mv.pPromoted) { if (GET_COLOR(p) == WHITE) @@ -875,43 +875,43 @@ Return value: { if ((RANK(cTo) != 1) && (RANK(cFrom) != 2)) return(FALSE); } - + if (!IS_KNIGHT(mv.pPromoted) && !IS_BISHOP(mv.pPromoted) && !IS_ROOK(mv.pPromoted) && !IS_QUEEN(mv.pPromoted)) { return(FALSE); - } + } } - + // // Handle capture moves. - // + // if (mv.pCaptured) { // // Must be capturing something - // + // if (IS_SPECIAL_MOVE(mv) && (!mv.pPromoted)) { // // en passant - // + // if (!IS_EMPTY(pos->rgSquare[cTo].pPiece)) return(FALSE); } else { // // normal capture - // + // if (IS_EMPTY(pos->rgSquare[cTo].pPiece)) return(FALSE); if (!OPPOSITE_COLORS(mv.pMoved, mv.pCaptured)) return(FALSE); } // // Must be in the capturing position. - // + // if (WHITE == GET_COLOR(p)) { if (((cFrom - 17) != cTo) && ((cFrom - 15) != cTo)) return(FALSE); @@ -920,27 +920,27 @@ Return value: { if (((cFrom + 17) != cTo) && ((cFrom + 15) != cTo)) return(FALSE); } - - if ((IS_SPECIAL_MOVE(mv)) && + + if ((IS_SPECIAL_MOVE(mv)) && (!mv.pPromoted) && (pos->cEpSquare != cTo)) return(FALSE); return(TRUE); } else { - // + // // If the pawn is not capturing, the TO square better be empty. - // + // if (!IS_EMPTY(pos->rgSquare[cTo].pPiece)) return(FALSE); - - // + + // // A non-capturing pawn can only push forward. One or two squares // based on whether or not its the initial move. // if (WHITE == GET_COLOR(p)) { if (cTo == cFrom - 16) return(TRUE); - if ((cTo == cFrom - 32) && + if ((cTo == cFrom - 32) && (RANK2(cFrom)) && (IS_EMPTY(pos->rgSquare[cFrom - 16].pPiece))) return(TRUE); } @@ -982,42 +982,42 @@ Return value: COOR cAttack; COOR cKing; int iDelta; - + ASSERT(!IS_PAWN(p)); // // Handle castling - // + // if (IS_CASTLE(mv)) { ASSERT(IS_KING(mv.pMoved)); ASSERT(IS_SPECIAL_MOVE(mv)); return(TRUE); } - + // // Make sure the piece moves in the way the move describes. - // + // iIndex = (int)cFrom - (int)cTo; if (0 == (CHECK_VECTOR_WITH_INDEX(iIndex, BLACK) & (1 << pPieceType))) { return(FALSE); } - + // // If we get here the piece can move in the way described by the // move but we still have to check to see if there are any other // pieces in the way if the piece moved is not a king or knight // (pawns handled in their own routine, see above). - // + // if ((pPieceType == QUEEN) || (pPieceType == ROOK) || (pPieceType == BISHOP)) { iDelta = CHECK_DELTA_WITH_INDEX(iIndex); for (cBlock = cFrom + iDelta; - cBlock != cTo; + cBlock != cTo; cBlock += iDelta) { if (!IS_EMPTY(pos->rgSquare[cBlock].pPiece)) @@ -1027,15 +1027,15 @@ Return value: } if (cBlock != cTo) return(FALSE); } - + // // Ok the piece can move the way they asked and there are no other // pieces in the way... but it cannot expose its own king to check // by doing so! // cKing = KingPosition(pos, pos->uToMove); - cAttack = ExposesCheck(pos, - cFrom, + cAttack = ExposesCheck(pos, + cFrom, cKing); if ((ILLEGAL_COOR != cAttack) && (cTo != cAttack)) { @@ -1044,7 +1044,7 @@ Return value: // does expose the king to check and the move does not capture the // checking piece. But it's still ok as long as the TO location // still blocks the checking piece. - // + // iIndex = cAttack - cKing; iDelta = CHECK_DELTA_WITH_INDEX(iIndex); for (cBlock = cAttack + iDelta; @@ -1059,12 +1059,12 @@ Return value: // // Legal! - // + // return(TRUE); } -FLAG +FLAG SanityCheckMove(POSITION *pos, MOVE mv) /** @@ -1084,7 +1084,7 @@ Return value: **/ { register PIECE p = mv.pMoved; - + if (0 == mv.uMove) { return(FALSE); @@ -1106,7 +1106,7 @@ Return value: { return(FALSE); } - + if (!IS_SPECIAL_MOVE(mv)) { if (mv.pCaptured) @@ -1122,7 +1122,7 @@ Return value: return(FALSE); } } - + if (!IS_EMPTY(pos->rgSquare[mv.cTo].pPiece) && !mv.pCaptured) { @@ -1136,7 +1136,7 @@ Return value: return(FALSE); } } - + if (IS_PAWN(p)) { return(_SanityCheckPawnMove(pos, mv)); @@ -1148,7 +1148,7 @@ Return value: } -FLAG +FLAG LooksLikeFile(CHAR c) /** @@ -1198,9 +1198,9 @@ Return value: } return(FALSE); } - -FLAG + +FLAG LooksLikeCoor(char *szData) /** @@ -1220,7 +1220,7 @@ Return value: { char f = szData[0]; char r = szData[1]; - + if (LooksLikeFile(f) && LooksLikeRank(r)) { @@ -1252,7 +1252,7 @@ Return value: static CHAR szStripped[10]; ULONG y; CHAR *p; - + memset(szStripped, 0, sizeof(szStripped)); p = szMove; y = 0; @@ -1289,11 +1289,11 @@ Return value: CHAR *szStripped = StripMove(szData); ULONG u; static CHAR cPieces[] = { 'P', 'N', 'B', 'R', 'Q', 'K', '\0' }; - + // // A (stripped) move must be at least two characters long even in // SAN. - // + // if ((strlen(szStripped) < 2) || (strlen(szStripped) > 7)) { return(NOT_MOVE); @@ -1309,7 +1309,7 @@ Return value: { return(MOVE_SAN); } - + // // COOR COOR (d2d4) // @@ -1318,37 +1318,37 @@ Return value: { return(MOVE_ICS); } - + // // COOR (d4) - // + // if (LooksLikeCoor(szStripped) && strlen(szStripped) == 2) { return(MOVE_SAN); } - + // // RANK COOR - // + // if ((LooksLikeRank(szStripped[0]) || LooksLikeFile(szStripped[0])) && LooksLikeCoor(&szStripped[1])) { return(MOVE_SAN); } - + // // PIECE COOR COOR // PIECE COOR // PIECE FILE COOR // PIECE RANK COOR - // + // for (u = 0; u < ARRAY_LENGTH(cPieces); u++) { if (szStripped[0] == cPieces[u]) // must be uppercase! { - if (LooksLikeCoor(&szStripped[1])) + if (LooksLikeCoor(&szStripped[1])) { return(MOVE_SAN); } @@ -1367,7 +1367,7 @@ Return value: // // (COORD)=(PIECE) - // + // if ((strlen(szStripped) == 4) && LooksLikeCoor(szStripped) && szStripped[2] == '=') @@ -1392,7 +1392,7 @@ Return value: } -void FASTCALL +void FORCEINLINE SelectBestWithHistory(SEARCHER_THREAD_CONTEXT *ctx, ULONG u) /** @@ -1424,7 +1424,7 @@ Return value: MOVE mvLast; ULONG uPrevContKey = 0; FLAG fHaveContinuation = FALSE; - COOR cEnprise; + // COOR cEnprise; ASSERT(ctx->sMoveStack.uBegin[ctx->uPly] <= uEnd); ASSERT(u >= ctx->sMoveStack.uBegin[ctx->uPly]); @@ -1442,7 +1442,7 @@ Return value: // answer than an earlier one. Recomputed every call (2026-09-16: // briefly hoisted to the caller, reverted after a DEBUG-build // ASSERT here caught the mismatch -- see git log). - cEnprise = FindEnprisePiece(ctx, ctx->sPosition.uToMove); + // cEnprise = FindEnprisePiece(ctx, ctx->sPosition.uToMove); // Continuation history: "did a move like this tend to fail high // right after a move like that?", keyed by (previous move, this @@ -1468,16 +1468,14 @@ Return value: if (!IS_CAPTURE_OR_PROMOTION(mv)) { iBestVal += g_HistoryCounters[mv.pMoved][mv.cTo]; - if (TRUE == fHaveContinuation) - { - iBestVal += CONTINUATION_SCALE * - g_ContinuationHistory[(uPrevContKey * CONT_KEY_RANGE) + - MOVE_TO_CONT_KEY(mv)]; - } - if (mv.cFrom == cEnprise) - { - iBestVal += FLEE_BONUS; - } + iBestVal += ( + fHaveContinuation * + CONTINUATION_SCALE * + g_ContinuationHistory[(uPrevContKey * CONT_KEY_RANGE) + MOVE_TO_CONT_KEY(mv)]); + //if (mv.cFrom == cEnprise) + //{ + // iBestVal += FLEE_BONUS; + //} } uLoc = u; @@ -1488,15 +1486,14 @@ Return value: if (!IS_CAPTURE_OR_PROMOTION(mv)) { iVal += g_HistoryCounters[mv.pMoved][mv.cTo]; - if (TRUE == fHaveContinuation) - { - iVal += g_ContinuationHistory[(uPrevContKey * CONT_KEY_RANGE) + - MOVE_TO_CONT_KEY(mv)]; - } - if (mv.cFrom == cEnprise) - { - iVal += FLEE_BONUS; - } + iVal += ( + fHaveContinuation * + CONTINUATION_SCALE * + g_ContinuationHistory[(uPrevContKey * CONT_KEY_RANGE) + MOVE_TO_CONT_KEY(mv)]); +// if (mv.cFrom == cEnprise) +// { +// iVal += FLEE_BONUS; +// } } if (iVal > iBestVal) { @@ -1514,7 +1511,7 @@ Return value: } -void FASTCALL +void FORCEINLINE SelectBestNoHistory(SEARCHER_THREAD_CONTEXT *ctx, ULONG u) /** @@ -1542,11 +1539,11 @@ Return value: ULONG uLoc; SCORE iVal; MOVE_STACK_MOVE_VALUE_FLAGS mvfTemp; - + ASSERT(ctx->sMoveStack.uBegin[ctx->uPly] <= uEnd); ASSERT(u >= ctx->sMoveStack.uBegin[ctx->uPly]); ASSERT(u < uEnd); - + // // Linear search from u..ctx->sMoveStack.uEnd[ctx->uPly] for the // move with the best value. @@ -1571,7 +1568,7 @@ Return value: ctx->sMoveStack.mvf[uLoc] = mvfTemp; } -void FASTCALL +void FASTCALL SelectMoveAtRoot(SEARCHER_THREAD_CONTEXT *ctx, ULONG u) /** @@ -1595,12 +1592,12 @@ Return value: ULONG uLoc = v; SCORE iVal; MOVE_STACK_MOVE_VALUE_FLAGS mvfTemp; - + ASSERT(ctx->sMoveStack.uBegin[ctx->uPly] <= uEnd); ASSERT(u >= ctx->sMoveStack.uBegin[ctx->uPly]); ASSERT(u < uEnd); ASSERT(MOVE_COUNT(ctx, ctx->uPly) >= 1); - + // // Find the first move that we have not already searched. It will // provide our initial iBestVal. @@ -1648,7 +1645,7 @@ static UINT64 g_uPerftNodeCount; static UINT64 g_uPerftTotalNodes; static UINT64 g_uPerftGenerates; -void +void Perft(SEARCHER_THREAD_CONTEXT *ctx, ULONG uDepth) { @@ -1658,16 +1655,16 @@ Perft(SEARCHER_THREAD_CONTEXT *ctx, g_uPerftTotalNodes += 1; ASSERT(uDepth < MAX_PLY_PER_SEARCH); - if (uDepth == 0) + if (uDepth == 0) { g_uPerftNodeCount += 1; return; } - + mv.uMove = 0; g_uPerftGenerates += 1; GenerateMoves(ctx, mv, GENERATE_DONT_SCORE); - + uPly = ctx->uPly; for (u = ctx->sMoveStack.uBegin[uPly]; u < ctx->sMoveStack.uEnd[uPly]; @@ -1688,13 +1685,13 @@ COMMAND(PerftCommand) Routine description: This function implements the 'perft' engine command. I have no - idea what 'perft' means but some people use this command to + idea what 'perft' means but some people use this command to benchmark the speed of the move generator code. Note: the way this is implemented here does nothing whatsoever with the move scoring code (i.e. the SEE) Usage: - + perft <depth> Parameters: @@ -1718,30 +1715,30 @@ Return value: double dBegin, dTime; double dNps; - if (argc < 2) + if (argc < 2) { Trace("Usage: perft <required_depth>\n"); return; } uDepth = atoi(argv[1]); - if (uDepth >= MAX_DEPTH_PER_SEARCH) + if (uDepth >= MAX_DEPTH_PER_SEARCH) { Trace("Error: invalid depth.\n"); return; } InitializeLightweightSearcherContext(pos, &ctx); - + g_uPerftTotalNodes = g_uPerftGenerates = 0ULL; dBegin = SystemTimeStamp(); - for (u = 1; u <= uDepth; u++) + for (u = 1; u <= uDepth; u++) { g_uPerftNodeCount = 0ULL; Perft((SEARCHER_THREAD_CONTEXT *)&ctx, u); Trace("%u. %" COMPILER_LONGLONG_UNSIGNED_FORMAT " node%s, " "%" COMPILER_LONGLONG_UNSIGNED_FORMAT " generate%s.\n", - u, - g_uPerftNodeCount, + u, + g_uPerftNodeCount, (g_uPerftNodeCount > 1) ? "s" : "", g_uPerftGenerates, (g_uPerftGenerates > 1) ? "s" : ""); @@ -1751,8 +1748,8 @@ Return value: dNps /= dTime; Trace("%" COMPILER_LONGLONG_UNSIGNED_FORMAT " total nodes, " "%" COMPILER_LONGLONG_UNSIGNED_FORMAT " total generates " - "in %6.2f seconds.\n", - g_uPerftTotalNodes, + "in %6.2f seconds.\n", + g_uPerftTotalNodes, g_uPerftGenerates, dTime); Trace("That's approx %.0f moves/sec\n", dNps); |
