/* Protector -- a UCI chess engine Copyright (C) 2009-2010 Raimund Heid (Raimund_Heid@yahoo.com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "position.h" #include "fen.h" #include "io.h" #define dumpPos dumpPosition(position); #define KNIGHT_VS_PASSED_WING_PAWNS #define BISHOP_BLOCKERS #define OUTPOST_SQUARE_BONUS #define PINNED_KNIGHT_BONUS #define MALUS_PASSED_PAWN_LACK_OF_SUPPORT #define MALUS_ROOK_BLOCKING_PASSER #define BONUS_SPACE_ATTACKS #define MALUS_QUEEN_DEFENDER_DISTANCE #define MALUS_BLOCKABLE_PASSERS #define BONUS_HIDDEN_PASSER #define BONUS_WINNING_PASSER #define BONUS_EXCHANGE_UP #include "evaluation.h" /* #define BONUS_TARGETS #define CALCULATE_TARGETS #define MALUS_OFFSIDE_KING #define BONUS_CONNECTED_DISTANT_PASSERS */ /* -------------------------------------------------------------------------- */ const int PAWN_MALUS_DOUBLED_OPENING = 10; const int PAWN_MALUS_DOUBLED_ENDGAME = 20; const int PAWN_MALUS_ISOLATED_OPENING = 10; const int PAWN_MALUS_ISOLATED_ON_OPEN_FILE = 20; const int PAWN_MALUS_ISOLATED_ENDGAME = 20; const int PAWN_MALUS_ISOLATED_FIXED_OPENING = 6; const int PAWN_MALUS_ISOLATED_FIXED_ENDGAME = 6; const int PAWN_MALUS_BACKWARD_OPENING = 8; const int PAWN_MALUS_BACKWARD_ON_OPEN_FILE = 16; const int PAWN_MALUS_BACKWARD_ENDGAME = 10; const int PAWN_MALUS_BACKWARD_FIXED_OPENING = 4; const int PAWN_MALUS_BACKWARD_FIXED_ENDGAME = 4; const int PAWN_CANDIDATE_OPENING_MIN = 5; const int PAWN_CANDIDATE_OPENING_MAX = 55; const int PAWN_CANDIDATE_ENDGAME_MIN = 10; const int PAWN_CANDIDATE_ENDGAME_MAX = 110; const int PASSED_PAWN_BONUS_OPENING_MIN = 10; const int PASSED_PAWN_BONUS_OPENING_MAX = 70; const int PASSED_PAWN_BONUS_ENDGAME_MIN = 20; const int PASSED_PAWN_BONUS_ENDGAME_MAX = 140; const int PASSED_PAWN_BONUS_UNSTOPPABLE = 800; const int PASSED_PAWN_BONUS_NOT_BLOCKED = 60; const int PASSED_PAWN_MALUS_BLOCKED = 30; const int PASSED_PAWN_MALUS_LACK_OF_SUPPORT = 30; const int PASSED_PAWN_BONUS_CONNECTED_DISTANT = 40; const int PASSED_PAWN_BONUS_CONNECTED_DISTANT_DUO = 10; const int PASSED_PAWN_ATTACKERDIST_WEIGHT = 5; const int PASSED_PAWN_DEFENDERDIST_WEIGHT = 20; const int KNIGHT_BONUS_ATTACK = 20; const int KNIGHT_MALUS_VS_BOTH_WINGS = 10; const int KNIGHT_MALUS_VS_OUTSIDE_PASSED = 15; const int BISHOP_MALUS_BLOCKER[3] = { 0, 8, 20 }; const int BISHOP_BONUS_ATTACK = 20; const int BISHOP_MALUS_BLOCKED = 50; const int BISHOP_MALUS_TRAPPED = 100; const int BISHOP_BONUS_PINNING_KNIGHT_OPENING = 15; const int BISHOP_BONUS_PINNING_KNIGHT_ENDGAME = 10; const int ROOK_BONUS_ON_SEMIOPEN_FILE = 10; const int ROOK_BONUS_ON_OPEN_FILE = 20; const int ROOK_MALUS_BLOCKED = 48; const int ROOK_MALUS_SQUEEZED = 12; const int ROOK_BONUS_KING_FILE = 20; const int ROOK_BONUS_LATERAL_KING_FILE = 10; const int ROOK_BONUS_ON_SEVENTH_RANK_OPENING = 20; const int ROOK_BONUS_ON_SEVENTH_RANK_ENDGAME = 40; const int ROOK_BONUS_ATTACK = 40; const int ROOK_MALUS_BLOCKING_PASSER = 90; const int QUEEN_BONUS_ON_SEVENTH_RANK_OPENING = 10; const int QUEEN_BONUS_ON_SEVENTH_RANK_ENDGAME = 20; const int QUEEN_BONUS_ATTACK = 80; #ifdef BONUS_SPACE_ATTACKS const int KING_MALUS_PAWN_ATTACK[8] = { 0, 0, 30, 20, 10, 0, 0, 0 }; #else const int KING_MALUS_PAWN_ATTACK[8] = { 0, 0, 60, 30, 10, 0, 0, 0 }; #endif const int KING_ATTACK_WEIGHT[17] = { 0, 0, 128, 192, 224, 240, 248, 252, 254, 255, 256, 256, 256, 256, 256, 256, 256 }; const int KING_MALUS_TRAPPED_OPENING = 20; const int KING_MALUS_TRAPPED_ENDGAME = 20; static const int SPACE_BONUS_WEIGHT[16] = { 0, 2, 5, 8, 11, 14, 17, 20, 20, 20, 20, 20, 20, 20, 20, 20 }; const int BONUS_TARGET_OPENING = 3; const int BONUS_TARGET_ENDGAME = 3; const int STD_BONUS_COUNT = 2; /* -------------------------------------------------------------------------- */ #define PAWN_PHASE 0 #define KNIGHT_PHASE 1 #define BISHOP_PHASE 1 #define ROOK_PHASE 2 #define QUEEN_PHASE 4 const int PHASE_MAX = 16 * PAWN_PHASE + 4 * KNIGHT_PHASE + 4 * BISHOP_PHASE + 4 * ROOK_PHASE + 2 * QUEEN_PHASE; #define NUM_EXPO_FACTORS 128 int centerDistance[_64_], centerTaxiDistance[_64_]; int attackPoints[16]; Bitboard weakOutpostSquareCandidates[2]; Bitboard butterflySquares[_64_]; Bitboard lateralSquares[_64_]; Bitboard companionFiles[_64_]; Bitboard passedPawnRectangle[2][_64_]; Bitboard passedPawnCorridor[2][_64_]; int passedPawnDefenderMalus[2][2][_64_][_64_]; Bitboard candidateDefenders[2][_64_]; Bitboard candidateSupporters[2][_64_]; Bitboard rookTraps[2]; Bitboard rookBlockers[_64_]; Bitboard centralFiles; Bitboard kingRealm[2][_64_][_64_]; Bitboard attackingRealm[2]; KingAttacks kingAttacks[_64_]; UINT64 numEvals = 0, sumDiff = 0, sumDiffSquare = 0; int expoFactor[NUM_EXPO_FACTORS]; int expoValue[NUM_EXPO_FACTORS]; void dumpEvalStats() { logReport("numEvals: %llu sumDiff: %llu sumDiffSquare: %llu", numEvals, sumDiff, sumDiffSquare); } INLINE static int quad(int y_min, int y_max, int rank) { const int bonusPerRank[8] = { 0, 0, 0, 26, 77, 154, 256, 0 }; return y_min + ((y_max - y_min) * bonusPerRank[rank] + 128) / 256; } INLINE static bool oppositeColoredBishops(const Position * position) { if (getPieceCount(position, WHITE_BISHOP) == 1 && getPieceCount(position, BLACK_BISHOP) == 1) { const Bitboard bishops = position->piecesOfType[WHITE_BISHOP] | position->piecesOfType[BLACK_BISHOP]; return (bool) ((lightSquares & bishops) != EMPTY_BITBOARD && (darkSquares & bishops) != EMPTY_BITBOARD); } else { return FALSE; } } INLINE static bool squareIsPawnSafe(const EvaluationBase * base, const Color color, const Square square) { return testSquare(base->pawnAttackableSquares[opponent(color)], square) == FALSE; } INLINE static bool hasAttackingBishop(const Position * position, const Color attackingColor, const Square square) { const Bitboard attackers = ((lightSquares & minValue[square]) != EMPTY_BITBOARD ? lightSquares : darkSquares); return (bool) ((attackers & position->piecesOfType[BISHOP | attackingColor]) != EMPTY_BITBOARD); } INLINE static bool pieceIsPinnedByBishop(const Position * position, const Square pinnedPiece, const Square pinningPiece, const Bitboard targets) { return (bool) ((getDiaSquaresBehind(position, pinnedPiece, pinningPiece) & targets) != EMPTY_BITBOARD); } INLINE static bool pieceIsPinnedByRook(const Position * position, const Square pinnedPiece, const Square pinningPiece, const Bitboard targets) { return (bool) ((getOrthoSquaresBehind(position, pinnedPiece, pinningPiece) & targets) != EMPTY_BITBOARD); } INLINE static void getPawnInfo(const Position * position, EvaluationBase * base) { Bitboard white = position->piecesOfType[WHITE_PAWN]; Bitboard black = position->piecesOfType[BLACK_PAWN]; Bitboard whiteLateralSquares, blackLateralSquares; Bitboard whiteSwamp, blackSwamp; Bitboard pawnAttackableSquaresWhite, pawnAttackableSquaresBlack; register Bitboard tmp1, tmp2; /* Calculate upward and downward realms */ tmp1 = (white << 8) | (white << 16) | (white << 24); tmp1 |= (tmp1 << 24); tmp2 = (white >> 8) | (white >> 16) | (white >> 24); tmp2 |= (tmp2 >> 24); base->doubledPawns[WHITE] = white & tmp2; base->upwardRealm[WHITE] = (tmp1 = tmp1 | white); pawnAttackableSquaresWhite = ((tmp1 & nonA) << 7) | ((tmp1 & nonH) << 9); base->downwardRealm[WHITE] = tmp2; /* Calculate upward and downward realms */ tmp1 = (black >> 8) | (black >> 16) | (black >> 24); tmp1 |= (tmp1 >> 24); tmp2 = (black << 8) | (black << 16) | (black << 24); tmp2 |= (tmp2 << 24); base->doubledPawns[BLACK] = black & tmp2; base->upwardRealm[BLACK] = (tmp1 = tmp1 | black); pawnAttackableSquaresBlack = ((tmp1 & nonA) >> 9) | ((tmp1 & nonH) >> 7); base->downwardRealm[BLACK] = tmp2; /* Calculate the squares protected by a pawn */ whiteLateralSquares = ((white & nonA) >> 1) | ((white & nonH) << 1); base->pawnProtectedSquares[WHITE] = whiteLateralSquares << 8; blackLateralSquares = ((black & nonA) >> 1) | ((black & nonH) << 1); base->pawnProtectedSquares[BLACK] = blackLateralSquares >> 8; /* Identify the passed pawns */ whiteSwamp = base->downwardRealm[BLACK] | base->upwardRealm[WHITE] | pawnAttackableSquaresWhite; blackSwamp = base->downwardRealm[WHITE] | base->upwardRealm[BLACK] | pawnAttackableSquaresBlack; base->passedPawns[WHITE] = white & ~blackSwamp; base->passedPawns[BLACK] = black & ~whiteSwamp; /* Calculate the weak pawns */ tmp2 = ~(white | black | base->pawnProtectedSquares[BLACK]); tmp1 = (whiteLateralSquares & tmp2) >> 8; tmp1 |= (tmp1 & squaresOfRank[RANK_3] & tmp2) >> 8; base->weakPawns[WHITE] = (white & ~(pawnAttackableSquaresWhite | whiteLateralSquares | tmp1)); tmp2 = ~(white | black | base->pawnProtectedSquares[WHITE]); tmp1 = (blackLateralSquares & tmp2) << 8; tmp1 |= (tmp1 & squaresOfRank[RANK_6] & tmp2) << 8; base->weakPawns[BLACK] = (black & ~(pawnAttackableSquaresBlack | blackLateralSquares | tmp1)); base->weakOutpostSquares[WHITE] = base->upwardRealm[WHITE] & ~(pawnAttackableSquaresWhite | base->downwardRealm[BLACK] | white | black) & weakOutpostSquareCandidates[WHITE]; base->weakOutpostSquares[BLACK] = base->upwardRealm[BLACK] & ~(pawnAttackableSquaresBlack | base->downwardRealm[WHITE] | white | black) & weakOutpostSquareCandidates[BLACK]; /* Calculate the candidates */ base->candidatePawns[WHITE] = white & ~base->passedPawns[WHITE] & (pawnAttackableSquaresWhite | whiteLateralSquares) & ~(base->upwardRealm[BLACK] | base->downwardRealm[WHITE]); base->candidatePawns[BLACK] = black & ~base->passedPawns[BLACK] & (pawnAttackableSquaresBlack | blackLateralSquares) & ~(base->upwardRealm[WHITE] | base->downwardRealm[BLACK]); #ifdef BONUS_HIDDEN_PASSER /* Calculate the hidden candidates */ base->hiddenCandidatePawns[WHITE] = white & (black >> 8) & ~pawnAttackableSquaresBlack & ~(blackLateralSquares) & (squaresOfRank[RANK_5] | squaresOfRank[RANK_6]) & base->pawnProtectedSquares[WHITE]; base->hiddenCandidatePawns[BLACK] = black & (white << 8) & ~pawnAttackableSquaresWhite & ~(whiteLateralSquares) & (squaresOfRank[RANK_4] | squaresOfRank[RANK_3]) & base->pawnProtectedSquares[BLACK]; #endif tmp1 = black & base->pawnProtectedSquares[BLACK]; tmp2 = ((tmp1 & nonA) >> 9) & ((tmp1 & nonH) >> 7); tmp2 &= ~pawnAttackableSquaresWhite; tmp1 = tmp2 | (tmp2 >> 8); base->fixedPawns[WHITE] = tmp1 | (tmp1 >> 16) | (tmp1 >> 32); tmp1 = white & base->pawnProtectedSquares[WHITE]; tmp2 = ((tmp1 & nonA) << 7) & ((tmp1 & nonH) << 9); tmp2 &= ~pawnAttackableSquaresBlack; tmp1 = tmp2 | (tmp2 << 8); base->fixedPawns[BLACK] = tmp1 | (tmp1 << 16) | (tmp1 << 32); #ifdef BONUS_HIDDEN_PASSER base->hasPassersOrCandidates[WHITE] = (bool) (base->passedPawns[WHITE] != EMPTY_BITBOARD || base->candidatePawns[WHITE] != EMPTY_BITBOARD || base->hiddenCandidatePawns[WHITE] != EMPTY_BITBOARD); base->hasPassersOrCandidates[BLACK] = (bool) (base->passedPawns[BLACK] != EMPTY_BITBOARD || base->candidatePawns[BLACK] != EMPTY_BITBOARD || base->hiddenCandidatePawns[BLACK] != EMPTY_BITBOARD); #endif tmp1 = (white << 8) & ~(white | black); tmp2 = white | (tmp1 & ~base->pawnProtectedSquares[BLACK]); tmp2 |= tmp1 & base->pawnProtectedSquares[WHITE]; tmp1 &= squaresOfRank[RANK_3] & ~base->pawnProtectedSquares[BLACK]; tmp1 = (tmp1 << 8) & ~(white | black); tmp2 |= tmp1 & ~base->pawnProtectedSquares[BLACK]; tmp2 |= tmp1 & base->pawnProtectedSquares[WHITE]; base->pawnAttackableSquares[WHITE] = ((tmp2 & nonA) << 7) | ((tmp2 & nonH) << 9); /*dumpBitboard(base->pawnAttackableSquares[WHITE], "pawnAttackable white"); dumpPosition(position); */ tmp1 = (black >> 8) & ~(white | black); tmp2 = black | (tmp1 & ~base->pawnProtectedSquares[WHITE]); tmp2 |= tmp1 & base->pawnProtectedSquares[BLACK]; tmp1 &= squaresOfRank[RANK_6] & ~base->pawnProtectedSquares[WHITE]; tmp1 = (tmp1 >> 8) & ~(white | black); tmp2 |= tmp1 & ~base->pawnProtectedSquares[WHITE]; tmp2 |= tmp1 & base->pawnProtectedSquares[BLACK]; base->pawnAttackableSquares[BLACK] = ((tmp2 & nonA) >> 9) | ((tmp2 & nonH) >> 7); } bool pawnIsPassed(const Position * position, const Square pawnSquare, const Color pawnColor) { const Color defenderColor = opponent(pawnColor); const Bitboard blockers = position->piecesOfType[PAWN | defenderColor] & (candidateDefenders[pawnColor][pawnSquare] | passedPawnCorridor[pawnColor][pawnSquare]); return (bool) (blockers == EMPTY_BITBOARD); } static int getPassedPawnDefenderMalus(const Color pawnColor, const Color activeColor, const Square passedPawnSquare, const Square defenderSquare) { const int pawnDirection = (pawnColor == WHITE ? 8 : -8); const Square stopSquare = (Square) (passedPawnSquare + pawnDirection); const Square rectangleSquare = (pawnColor == activeColor ? passedPawnSquare : (Square) (passedPawnSquare - pawnDirection)); const bool kingInRectangle = testSquare(passedPawnRectangle[pawnColor][rectangleSquare], defenderSquare); const int defenderDistWeight = (kingInRectangle ? (2 * PASSED_PAWN_DEFENDERDIST_WEIGHT) / 3 : PASSED_PAWN_DEFENDERDIST_WEIGHT); return distance(stopSquare, defenderSquare) * defenderDistWeight; } INLINE bool passerWalks(const Position * position, const Square passerSquare, const Color passerColor) { const Square attackerKingSquare = position->king[passerColor]; const Square defenderKingSquare = position->king[opponent(passerColor)]; const int attackerDistance = distance(attackerKingSquare, passerSquare); const Rank kingRank = colorRank(passerColor, attackerKingSquare); const File passerFile = file(passerSquare); if (passerFile >= FILE_B && passerFile <= FILE_G) { if ((kingRank == RANK_6 || kingRank == RANK_7) && kingRank > colorRank(passerColor, passerSquare) && abs(file(attackerKingSquare) - passerFile) <= 1 && attackerDistance <= 2) { if (position->activeColor == passerColor || attackerDistance == 1 || distance(defenderKingSquare, passerSquare) > 1) { return TRUE; } } /* if (kingRank == colorRank(passerColor, passerSquare) + 2 && abs(file(attackerKingSquare) - passerFile) <= 1 && attackerDistance <= 2) { if (position->activeColor == passerColor || attackerDistance == 1 || distance(defenderKingSquare, passerSquare) > 1) { return TRUE; } } */ } else if ((kingRank == RANK_7 || kingRank == RANK_8) && abs(file(attackerKingSquare) - passerFile) == 1 && attackerDistance <= 2) { if (position->activeColor == passerColor || attackerDistance == 1 || distance(defenderKingSquare, passerSquare) > 1) { return TRUE; } } return FALSE; } INLINE static void evaluatePassedPawns(Position * position, EvaluationBase * base) { Square square; Bitboard pieces = base->passedPawns[WHITE] | base->passedPawns[BLACK]; ITERATE_BITBOARD(&pieces, square) { const Piece currentPiece = position->piece[square]; const Color pawnColor = pieceColor(currentPiece); const Color oppColor = opponent(pawnColor); const Rank pawnRank = colorRank(pawnColor, square); const int pawnDirection = (pawnColor == WHITE ? 8 : -8); const Square stopSquare = (Square) (square + pawnDirection); const int numDefenders = position->numberOfPieces[oppColor] - position->numberOfPawns[oppColor]; int delta = PASSED_PAWN_BONUS_ENDGAME_MAX - PASSED_PAWN_BONUS_ENDGAME_MIN; bool blocked = TRUE; const bool hasSupportingBishop = hasAttackingBishop(position, pawnColor, stopSquare); const bool oppHasBlockingBishop = hasAttackingBishop(position, oppColor, stopSquare); base->openingPoints[pawnColor] += quad(PASSED_PAWN_BONUS_OPENING_MIN, PASSED_PAWN_BONUS_OPENING_MAX, pawnRank); if (numDefenders == 1) { const int kingDistance = distance(square, position->king[pawnColor]); const Square rectangleSquare = (pawnColor == position->activeColor ? square : (Square) (square - pawnDirection)); const bool kingInRectangle = testSquare(passedPawnRectangle[pawnColor][rectangleSquare], position->king[oppColor]); if ((kingInRectangle == FALSE && (passedPawnCorridor[pawnColor][square] & position->piecesOfColor[pawnColor]) == EMPTY_BITBOARD)) { delta += PASSED_PAWN_BONUS_UNSTOPPABLE; } else if (kingDistance == 1) { const File pawnFile = file(square); const File kingFile = file(position->king[pawnColor]); const Square promotionSquare = (pawnColor == WHITE ? getSquare(pawnFile, RANK_8) : getSquare(pawnFile, RANK_1)); const bool clearPath = (bool) (kingFile != pawnFile || (kingFile != FILE_A && kingFile != FILE_H)); if (clearPath && distance(promotionSquare, position->king[pawnColor]) <= 1) { delta += PASSED_PAWN_BONUS_UNSTOPPABLE; } } #ifdef BONUS_WINNING_PASSER if (delta < PASSED_PAWN_BONUS_UNSTOPPABLE && base->hasPassersOrCandidates[oppColor] == FALSE && passerWalks(position, square, pawnColor)) { delta += PASSED_PAWN_BONUS_UNSTOPPABLE; } #endif } if (position->piece[stopSquare] == NO_PIECE && delta < PASSED_PAWN_BONUS_UNSTOPPABLE) { const Piece newPiece = (pawnRank == RANK_7 ? WHITE_QUEEN : NO_PIECE); const Move move = getPackedMove(square, stopSquare, newPiece); int exValue = seeMove(position, move); #ifndef NDEBUG { Move flippedMove = getPackedMove(getFlippedSquare(square), getFlippedSquare (stopSquare), newPiece); Position flippedPosition = *position; flipPosition(&flippedPosition); initializePosition(&flippedPosition); if (seeMove(&flippedPosition, flippedMove) != exValue) { exValue = -100; } } #endif if (exValue >= 0) { delta += PASSED_PAWN_BONUS_NOT_BLOCKED; blocked = FALSE; } } delta -= distance(stopSquare, position->king[pawnColor]) * PASSED_PAWN_ATTACKERDIST_WEIGHT; delta += passedPawnDefenderMalus[pawnColor] [position->activeColor][square][position->king[oppColor]]; base->endgamePoints[pawnColor] += PASSED_PAWN_BONUS_ENDGAME_MIN; #ifdef MALUS_PASSED_PAWN_LACK_OF_SUPPORT if (numberOfNonPawnPieces(position, pawnColor) <= numberOfNonPawnPieces(position, oppColor) && ((hasOrthoPieces(position, oppColor) && hasOrthoPieces(position, pawnColor) == FALSE) || (numberOfNonPawnPieces(position, pawnColor) < numberOfNonPawnPieces(position, oppColor)))) { delta -= 10; } #endif #ifdef BONUS_CONNECTED_DISTANT_PASSERS if (testSquare(passedPawnRectangle[pawnColor][square], position->king[oppColor]) == FALSE) { const File pawnFile = file(square); const int fileDiff = pawnFile - file(position->king[oppColor]); const Bitboard dangerousCompanionFiles = (fileDiff > 0 ? squaresOfFileRange[pawnFile][FILE_H] : squaresOfFileRange[FILE_A][pawnFile]); const Bitboard dangerousCompanions = base->passedPawns[pawnColor] & butterflySquares[square] & dangerousCompanionFiles; if (dangerousCompanions != EMPTY_BITBOARD) { delta += PASSED_PAWN_BONUS_CONNECTED_DISTANT; } } #endif #ifdef MALUS_BLOCKABLE_PASSERS if (numberOfNonPawnPieces(position, pawnColor) <= numberOfNonPawnPieces(position, oppColor) && oppHasBlockingBishop) { if (hasSupportingBishop) { delta -= 5; } else { delta -= 20; } } if (blocked && numberOfNonPawnPieces(position, pawnColor) <= numberOfNonPawnPieces(position, oppColor) && getPieceCount(position, (Piece) (BISHOP | pawnColor)) > 0 && hasSupportingBishop == FALSE) { delta -= 10; } if ((base->passedPawns[pawnColor] & butterflySquares[square]) != EMPTY_BITBOARD) { const int attackerDist = distance(position->king[pawnColor], square); const int defenderDist = distance(position->king[oppColor], square); delta += max(0, 5 * (defenderDist - attackerDist)); if (oppHasBlockingBishop) { if (hasSupportingBishop) { delta += 10; } else if (getPieceCount(position, (Piece) (KNIGHT | pawnColor)) > 0) { delta += 5; } } else { delta += 20; } } #endif if (delta > 0) { base->endgamePoints[pawnColor] += quad(0, delta, pawnRank); } } } INLINE static void evaluatePawns(const Position * position, EvaluationBase * base) { Square square; Bitboard pieces = (base->weakPawns[WHITE] | base->weakPawns[BLACK]); const int whiteDoubles = getNumberOfSetSquares(base->doubledPawns[WHITE]); const int blackDoubles = getNumberOfSetSquares(base->doubledPawns[BLACK]); base->openingPoints[WHITE] -= whiteDoubles * PAWN_MALUS_DOUBLED_OPENING; base->endgamePoints[WHITE] -= whiteDoubles * PAWN_MALUS_DOUBLED_ENDGAME; base->openingPoints[BLACK] -= blackDoubles * PAWN_MALUS_DOUBLED_OPENING; base->endgamePoints[BLACK] -= blackDoubles * PAWN_MALUS_DOUBLED_ENDGAME; ITERATE_BITBOARD(&pieces, square) { const Color pawnColor = pieceColor(position->piece[square]); const Color oppColor = opponent(pawnColor); const bool isolated = (bool) ((companionFiles[square] & position->piecesOfType[position->piece[square]]) == EMPTY_BITBOARD); const bool onOpenFile = (bool) (testSquare(base->upwardRealm[oppColor], square) == FALSE && testSquare(base->doubledPawns[pawnColor], square) == FALSE); if (isolated) { if (onOpenFile) { base->openingPoints[pawnColor] -= PAWN_MALUS_ISOLATED_ON_OPEN_FILE; } else { base->openingPoints[pawnColor] -= PAWN_MALUS_ISOLATED_OPENING; } base->endgamePoints[pawnColor] -= PAWN_MALUS_ISOLATED_ENDGAME; if (testSquare(base->fixedPawns[pawnColor], square)) { base->openingPoints[pawnColor] -= PAWN_MALUS_ISOLATED_FIXED_OPENING; base->endgamePoints[pawnColor] -= PAWN_MALUS_ISOLATED_FIXED_ENDGAME; } } else /* backward */ { if (onOpenFile) { base->openingPoints[pawnColor] -= PAWN_MALUS_BACKWARD_ON_OPEN_FILE; } else { base->openingPoints[pawnColor] -= PAWN_MALUS_BACKWARD_OPENING; } base->endgamePoints[pawnColor] -= PAWN_MALUS_BACKWARD_ENDGAME; if (testSquare(base->fixedPawns[pawnColor], square)) { base->openingPoints[pawnColor] -= PAWN_MALUS_BACKWARD_FIXED_OPENING; base->endgamePoints[pawnColor] -= PAWN_MALUS_BACKWARD_FIXED_ENDGAME; } } } pieces = (base->candidatePawns[WHITE] | base->candidatePawns[BLACK]); ITERATE_BITBOARD(&pieces, square) { const Color pawnColor = pieceColor(position->piece[square]); const Bitboard supporters = candidateSupporters[pawnColor][square] & position->piecesOfType[PAWN | pawnColor]; const Bitboard defenders = candidateDefenders[pawnColor][square] & position->piecesOfType[PAWN | opponent(pawnColor)]; if (getNumberOfSetSquares(supporters) >= getNumberOfSetSquares(defenders)) { const Bitboard ownDefenders = generalMoves[PAWN | opponent(pawnColor)][square] & position->piecesOfType[PAWN | pawnColor]; const Bitboard attackers = generalMoves[PAWN | pawnColor][square] & position->piecesOfType[PAWN | opponent(pawnColor)]; if (getNumberOfSetSquares(ownDefenders) >= getNumberOfSetSquares(attackers)) { const Rank pawnRank = colorRank(pawnColor, square); base->openingPoints[pawnColor] += quad(PAWN_CANDIDATE_OPENING_MIN, PAWN_CANDIDATE_OPENING_MAX, pawnRank); base->endgamePoints[pawnColor] += quad(PAWN_CANDIDATE_ENDGAME_MIN, PAWN_CANDIDATE_ENDGAME_MAX, pawnRank); } } } } INLINE bool isBlockingSquare(const Position * position, const EvaluationBase * base, const Square square, const Color blockingColor) { const Square blockedSquare = (Square) (blockingColor == WHITE ? square + 8 : square - 8); const Piece blockedPawn = (Piece) (PAWN | opponent(blockingColor)); return (bool) (position->piece[blockedSquare] == blockedPawn && squareIsPawnSafe(base, blockingColor, square)); } INLINE int pawnDefenderDistance(const Square defenderSquare, const Color defenderColor, const Square pawnSquare) { const int defenderRank = rank(defenderSquare); const int pawnRank = rank(pawnSquare); if (defenderColor == WHITE) { return (defenderRank <= pawnRank ? abs(file(defenderSquare) - file(pawnSquare)) : distance(defenderSquare, pawnSquare)); } else { return (defenderRank >= pawnRank ? abs(file(defenderSquare) - file(pawnSquare)) : distance(defenderSquare, pawnSquare)); } } #ifdef BONUS_TARGETS INLINE void evaluateTargets(const Bitboard openingTargets, const Bitboard endgameTargets, const Bitboard moves, int *opCount, int *egCount) { *opCount += STD_BONUS_COUNT * getNumberOfSetSquares(moves & openingTargets); *egCount += STD_BONUS_COUNT * getNumberOfSetSquares(moves & endgameTargets); } #endif INLINE static int getMobilityCount(const EvaluationBase * base, const Bitboard moves, const Color color) { return getNumberOfSetSquares(moves & base->countedSquares[color]) + getNumberOfSetSquares(moves & base->unprotectedPieces[opponent(color)]); } #define MOBN 13 #define MEBN 6 INLINE static void evaluateKnight(const Position * position, EvaluationBase * base, const Square square) { const static int mobOpBonus[17] = { -(14 + 8), -(8 + 6), -8, -4, 0, 4, 8, (8 + 3), (11 + 2), MOBN, MOBN, MOBN, MOBN, MOBN, MOBN, MOBN, MOBN }; const static int mobEgBonus[17] = { -(14 + 8), -(8 + 6), -8, -4, 0, 3, (3 + 2), (5 + 1), (6 + 0), MEBN, MEBN, MEBN, MEBN, MEBN, MEBN, MEBN, MEBN }; const Piece piece = position->piece[square]; const Color color = pieceColor(piece); const Color oppColor = opponent(color); const Bitboard moves = getKnightMoves(square); const int mobilityCount = getMobilityCount(base, moves, color); int opCount = 0, egCount = 0; #ifdef OUTPOST_SQUARE_BONUS const Bitboard outpostAttacks = moves & base->weakOutpostSquares[oppColor]; #endif #ifdef CALCULATE_TARGETS base->pieceAttacks[color] |= moves; #endif if (position->piecesOfType[KNIGHT | oppColor] == EMPTY_BITBOARD && position->piecesOfType[BISHOP | oppColor] != EMPTY_BITBOARD && hasAttackingBishop(position, oppColor, square) == FALSE) { opCount += STD_BONUS_COUNT; egCount += STD_BONUS_COUNT; } if (squareIsPawnSafe(base, color, square)) { opCount += STD_BONUS_COUNT; egCount += STD_BONUS_COUNT; } if (testSquare(base->pawnProtectedSquares[color], square)) { const Bitboard protectors = generalMoves[PAWN | oppColor][square] & position->piecesOfType[PAWN | color]; const int numProtectors = getNumberOfSetSquares(protectors); opCount += numProtectors * 2 * STD_BONUS_COUNT; egCount += numProtectors * 2 * STD_BONUS_COUNT; } #ifdef OUTPOST_SQUARE_BONUS if (outpostAttacks != EMPTY_BITBOARD) { const int count = getNumberOfSetSquares(outpostAttacks); opCount += count * STD_BONUS_COUNT; egCount += count * STD_BONUS_COUNT; } else if (testSquare(base->weakOutpostSquares[oppColor], square)) { opCount += STD_BONUS_COUNT; egCount += STD_BONUS_COUNT; } #endif #ifdef BONUS_TARGETS evaluateTargets(base->openingTargets[color], base->endgameTargets[color], moves, &opCount, &egCount); #endif opCount = min(opCount, NUM_EXPO_FACTORS - 1); egCount = min(egCount, NUM_EXPO_FACTORS - 1); base->openingPoints[color] += mobOpBonus[mobilityCount] + expoValue[opCount]; base->endgamePoints[color] += mobEgBonus[mobilityCount] + expoValue[egCount]; if (base->evaluateKingSafety[oppColor] && (moves & base->kingAttackSquares[oppColor]) != EMPTY_BITBOARD) { base->numAttackers[color]++; base->attackPoints[color] += KNIGHT_BONUS_ATTACK; } #ifdef KNIGHT_VS_PASSED_WING_PAWNS if (base->passedPawns[oppColor] != EMPTY_BITBOARD) { const int malus[8] = { 12, 8, 5, 3, 3, 5, 8, 12 }; Bitboard passers = base->passedPawns[oppColor]; Square pawnSquare; ITERATE_BITBOARD(&passers, pawnSquare) { base->endgamePoints[color] -= malus[file(pawnSquare)] + pawnDefenderDistance(position->king[color], color, pawnSquare); } } #endif } #define MOBB 30 #define MEBB 30 INLINE static void evaluateBishop(const Position * position, EvaluationBase * base, const Square square) { const static int mobOpBonus[18] = { -(35 + 10), -(26 + 9), -(18 + 8), -(11 + 7), -(5 + 6), -5, 0, 5, 10, 15, (20 + 4), (24 + 3), (27 + 2), (29 + 1), MOBB, MOBB, MOBB, MOBB }; const static int mobEgBonus[18] = { -(40 + 11), -(30 + 10), -(21 + 9), -(13 + 8), -(6 + 7), -6, 0, 5, 10, 15, (20 + 4), (24 + 3), (27 + 2), (29 + 1), MEBB, MEBB, MEBB, MEBB }; const Piece piece = position->piece[square]; const Color color = pieceColor(piece); const Color oppColor = opponent(color); const Bitboard xrayPieces = position->piecesOfType[QUEEN | color]; const Bitboard moves = getMagicBishopMoves(square, position->allPieces & ~xrayPieces); const int mobilityCount = getMobilityCount(base, moves, color); /* const Bitboard moves = getMagicBishopMoves(square, position->allPieces); */ int opCount = 0, egCount = 0; #ifdef PINNED_KNIGHT_BONUS Bitboard pinnedKnights = moves & position->piecesOfType[oppColor | KNIGHT]; #endif #ifdef OUTPOST_SQUARE_BONUS const Bitboard outpostAttacks = moves & base->weakOutpostSquares[oppColor]; #endif #ifdef BISHOP_BLOCKERS const Bitboard blockers = squaresAbove[color][square] & moves & (position->piecesOfType[PAWN | color] | (position->piecesOfType[PAWN | opponent(color)] & base->pawnProtectedSquares[opponent(color)])); #endif #ifdef CALCULATE_TARGETS base->pieceAttacks[color] |= moves; #endif if (squareIsPawnSafe(base, color, square)) { opCount += STD_BONUS_COUNT; egCount += STD_BONUS_COUNT; } if (testSquare(base->pawnProtectedSquares[color], square)) { opCount += STD_BONUS_COUNT; egCount += STD_BONUS_COUNT; } #ifdef OUTPOST_SQUARE_BONUS if (outpostAttacks != EMPTY_BITBOARD) { const int count = getNumberOfSetSquares(outpostAttacks); opCount += count * STD_BONUS_COUNT; egCount += count * STD_BONUS_COUNT; } else if (testSquare(base->weakOutpostSquares[oppColor], square)) { opCount += STD_BONUS_COUNT; egCount += STD_BONUS_COUNT; } #endif #ifdef PINNED_KNIGHT_BONUS if (pinnedKnights != EMPTY_BITBOARD) { Square knightSquare; const Bitboard targets = position->piecesOfType[oppColor | QUEEN] | position->piecesOfType[oppColor | ROOK] | minValue[position->king[oppColor]]; ITERATE_BITBOARD(&pinnedKnights, knightSquare) { if (squareIsPawnSafe(base, color, knightSquare) && pieceIsPinnedByBishop(position, knightSquare, square, targets)) { opCount += 2 * STD_BONUS_COUNT; egCount += STD_BONUS_COUNT; } } } #endif #ifdef BONUS_TARGETS evaluateTargets(base->openingTargets[color], base->endgameTargets[color], moves, &opCount, &egCount); #endif opCount = min(opCount, NUM_EXPO_FACTORS - 1); egCount = min(egCount, NUM_EXPO_FACTORS - 1); base->openingPoints[color] += mobOpBonus[mobilityCount] + expoValue[opCount]; base->endgamePoints[color] += mobEgBonus[mobilityCount] + expoValue[egCount]; if (base->evaluateKingSafety[oppColor] && (moves & base->kingAttackSquares[oppColor]) != EMPTY_BITBOARD) { base->numAttackers[color]++; base->attackPoints[color] += BISHOP_BONUS_ATTACK; } #ifdef BISHOP_BLOCKERS if (blockers != EMPTY_BITBOARD) { const int numBlockers = getNumberOfSetSquares(blockers); assert(numBlockers >= 1 && numBlockers <= 2); base->openingPoints[color] -= BISHOP_MALUS_BLOCKER[numBlockers]; base->endgamePoints[color] -= BISHOP_MALUS_BLOCKER[numBlockers]; } #endif } INLINE static void evaluateWhiteTrappedBishops(const Position * position, EvaluationBase * base) { if ((position->piece[A7] == WHITE_BISHOP && position->piece[B6] == BLACK_PAWN) || (position->piece[B8] == WHITE_BISHOP && position->piece[C7] == BLACK_PAWN) || (position->piece[H7] == WHITE_BISHOP && position->piece[G6] == BLACK_PAWN) || (position->piece[G8] == WHITE_BISHOP && position->piece[F7] == BLACK_PAWN)) { base->openingPoints[WHITE] -= BISHOP_MALUS_TRAPPED; base->endgamePoints[WHITE] -= BISHOP_MALUS_TRAPPED; } if ((position->piece[A6] == WHITE_BISHOP && position->piece[B5] == BLACK_PAWN) || (position->piece[H6] == WHITE_BISHOP && position->piece[G5] == BLACK_PAWN)) { base->openingPoints[WHITE] -= BISHOP_MALUS_TRAPPED / 2; base->endgamePoints[WHITE] -= BISHOP_MALUS_TRAPPED / 2; } if ((position->piece[C1] == WHITE_BISHOP && position->piece[D2] == WHITE_PAWN && position->piece[D3] != NO_PIECE) || (position->piece[F1] == WHITE_BISHOP && position->piece[E2] == WHITE_PAWN && position->piece[E3] != NO_PIECE)) { base->openingPoints[WHITE] -= BISHOP_MALUS_BLOCKED; base->endgamePoints[WHITE] -= BISHOP_MALUS_BLOCKED; } } INLINE static void evaluateBlackTrappedBishops(const Position * position, EvaluationBase * base) { if ((position->piece[A2] == BLACK_BISHOP && position->piece[B3] == WHITE_PAWN) || (position->piece[B1] == BLACK_BISHOP && position->piece[C2] == WHITE_PAWN) || (position->piece[H2] == BLACK_BISHOP && position->piece[G3] == WHITE_PAWN) || (position->piece[G1] == BLACK_BISHOP && position->piece[F2] == WHITE_PAWN)) { base->openingPoints[BLACK] -= BISHOP_MALUS_TRAPPED; base->endgamePoints[BLACK] -= BISHOP_MALUS_TRAPPED; } if ((position->piece[A3] == BLACK_BISHOP && position->piece[B4] == WHITE_PAWN) || (position->piece[H3] == BLACK_BISHOP && position->piece[G4] == WHITE_PAWN)) { base->openingPoints[BLACK] -= BISHOP_MALUS_TRAPPED / 2; base->endgamePoints[BLACK] -= BISHOP_MALUS_TRAPPED / 2; } if ((position->piece[C8] == BLACK_BISHOP && position->piece[D7] == BLACK_PAWN && position->piece[D6] != NO_PIECE) || (position->piece[F8] == BLACK_BISHOP && position->piece[E7] == BLACK_PAWN && position->piece[E6] != NO_PIECE)) { base->openingPoints[BLACK] -= BISHOP_MALUS_BLOCKED; base->endgamePoints[BLACK] -= BISHOP_MALUS_BLOCKED; } } #define MOBR 12 #define MEBR 22 INLINE static void evaluateRook(const Position * position, EvaluationBase * base, const Square square) { const static int mobOpBonus[19] = { -(18 + 6), -(13 + 5), -(9 + 4), -(6 + 3), -6, -4, -2, 0, 2, 4, 6, 8, 9, 10, 11, MOBR, MOBR, MOBR, MOBR }; const static int mobEgBonus[19] = { -(30 + 8), -(23 + 7), -(17 + 6), -(12 + 5), -12, -8, -4, 0, 4, 8, 12, 16, (16 + 3), (19 + 2), (21 + 1), MEBR, MEBR, MEBR, MEBR }; const Piece piece = position->piece[square]; const Color color = pieceColor(piece); const Color oppColor = opponent(color); const Bitboard seventhRank = (color == WHITE ? squaresOfRank[RANK_7] : squaresOfRank[RANK_2]); const Bitboard moves = getMagicRookMoves(square, position->allPieces); const Bitboard xrayPieces = position->piecesOfType[QUEEN | color] | position->piecesOfType[piece]; const Bitboard xrayMoves = getMagicRookMoves(square, position->allPieces & ~xrayPieces); const int mobilityCount = getMobilityCount(base, xrayMoves, color); const Bitboard fileSquares = squaresOfFile[file(square)]; const Bitboard ownPawns = position->piecesOfType[PAWN | color]; int opCount = 0, egCount = 0; #ifdef OUTPOST_SQUARE_BONUS const Bitboard outpostAttacks = moves & base->weakOutpostSquares[oppColor]; #endif #ifdef CALCULATE_TARGETS base->pieceAttacks[color] |= moves; #endif if (squareIsPawnSafe(base, color, square)) { opCount += STD_BONUS_COUNT; egCount += STD_BONUS_COUNT; } #ifdef OUTPOST_SQUARE_BONUS if (outpostAttacks != EMPTY_BITBOARD) { const int count = getNumberOfSetSquares(outpostAttacks); opCount += count * STD_BONUS_COUNT; egCount += count * STD_BONUS_COUNT; } else if (testSquare(base->weakOutpostSquares[oppColor], square)) { opCount += STD_BONUS_COUNT; egCount += STD_BONUS_COUNT; } #endif #ifdef BONUS_TARGETS evaluateTargets(base->openingTargets[color], base->endgameTargets[color], moves, &opCount, &egCount); #endif opCount = min(opCount, NUM_EXPO_FACTORS - 1); egCount = min(egCount, NUM_EXPO_FACTORS - 1); base->openingPoints[color] += mobOpBonus[mobilityCount] + expoValue[opCount]; base->endgamePoints[color] += mobEgBonus[mobilityCount] + expoValue[egCount]; /* Add a bonus if this rook is located on an open file. */ if ((ownPawns & fileSquares) == EMPTY_BITBOARD) { const int fileDiff = abs(file(square) - file(position->king[oppColor])); if ((position->piecesOfType[PAWN | oppColor] & fileSquares) == EMPTY_BITBOARD) { base->openingPoints[color] += ROOK_BONUS_ON_OPEN_FILE; base->endgamePoints[color] += ROOK_BONUS_ON_OPEN_FILE; } else { base->openingPoints[color] += ROOK_BONUS_ON_SEMIOPEN_FILE; base->endgamePoints[color] += ROOK_BONUS_ON_SEMIOPEN_FILE; } if (fileDiff == 0 && base->evaluateKingSafety[oppColor]) { base->openingPoints[color] += ROOK_BONUS_KING_FILE; } if (fileDiff == 1 && base->evaluateKingSafety[oppColor]) { base->openingPoints[color] += ROOK_BONUS_LATERAL_KING_FILE; } } if (testSquare(rookTraps[color], square) && (moves & centralFiles) == EMPTY_BITBOARD) { const Bitboard legalRankMoves = moves & ~position->piecesOfColor[color] & squaresOfRank[rank(square)]; if (getNumberOfSetSquares(legalRankMoves) <= 1) { const Bitboard blockers = minValue[position->king[color]] | position->piecesOfType[PAWN | color]; const int malus = ((blockers & rookBlockers[square]) != EMPTY_BITBOARD ? ROOK_MALUS_BLOCKED : ROOK_MALUS_SQUEEZED); base->openingPoints[color] -= malus; base->endgamePoints[color] -= malus; } } if (testSquare(seventhRank, square) && ((seventhRank & position->piecesOfType[PAWN | oppColor]) || (rank(position->king[oppColor]) == rank(square) + colorSign[color]))) { base->openingPoints[color] += ROOK_BONUS_ON_SEVENTH_RANK_OPENING; base->endgamePoints[color] += ROOK_BONUS_ON_SEVENTH_RANK_ENDGAME; } if (base->evaluateKingSafety[oppColor] && (xrayMoves & base->kingAttackSquares[oppColor]) != EMPTY_BITBOARD) { base->numAttackers[color]++; base->attackPoints[color] += ROOK_BONUS_ATTACK; } #ifdef MALUS_ROOK_BLOCKING_PASSER if (numberOfNonPawnPieces(position, color) == 2 && colorRank(color, square) == RANK_8 && testSquare(base->passedPawns[color], (Square) downward(color, square)) && (fileSquares & squaresBelow[color][square] & position->piecesOfType[ROOK | oppColor]) != EMPTY_BITBOARD && (companionFiles[square] & (position->piecesOfType[WHITE_PAWN] | position->piecesOfType[BLACK_PAWN])) == EMPTY_BITBOARD) { base->endgamePoints[color] -= ROOK_MALUS_BLOCKING_PASSER; } #endif #ifdef BONUS_SPACE_ATTACKS if (testSquare(attackingRealm[color], square)) { base->spaceAttackPoints[color]++; } #endif #ifdef BONUS_EXCHANGE_UP if (position->piecesOfType[ROOK | oppColor] == EMPTY_BITBOARD && position->piecesOfType[PAWN | color] != EMPTY_BITBOARD) { if (base->passedPawns[color] != EMPTY_BITBOARD) { base->openingPoints[color] += 25; base->endgamePoints[color] += 50; } else { base->openingPoints[color] += 15; base->endgamePoints[color] += 30; } } #endif } #define MOBQ 0 #define MEBQ 0 INLINE static void evaluateQueen(const Position * position, EvaluationBase * base, const Square square) { const static int mobOpBonus[36] = { -(13 + 5), -(9 + 4), -(6 + 3), -(4 + 2), -(4), -(3), -(2), -(1), 0, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ, MOBQ }; const static int mobEgBonus[36] = { -(13 + 5), -(9 + 4), -(6 + 3), -(4 + 2), -(4), -(3), -(2), -(1), 0, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ, MEBQ }; const Piece piece = position->piece[square]; const Color color = pieceColor(piece); const Color oppColor = opponent(color); const Bitboard seventhRank = (color == WHITE ? squaresOfRank[RANK_7] : squaresOfRank[RANK_2]); const int proximityCount = 14 - taxiDistance(square, position->king[oppColor]); const Bitboard moves = getMagicQueenMoves(square, position->allPieces); const Bitboard outpostAttacks = moves & base->weakOutpostSquares[oppColor]; const int mobilityCount = getMobilityCount(base, moves, color); int opCount = 0, egCount = 0; #ifdef CALCULATE_TARGETS base->pieceAttacks[color] |= moves; #endif #ifdef OUTPOST_SQUARE_BONUS if (outpostAttacks != EMPTY_BITBOARD) { const int count = getNumberOfSetSquares(outpostAttacks); opCount += count * STD_BONUS_COUNT; } #endif opCount = min(opCount, NUM_EXPO_FACTORS - 1); egCount = min(egCount, NUM_EXPO_FACTORS - 1); base->openingPoints[color] += proximityCount + mobOpBonus[mobilityCount] + expoValue[opCount]; base->endgamePoints[color] += proximityCount + mobEgBonus[mobilityCount] + expoValue[egCount]; if (testSquare(seventhRank, square) && ((seventhRank & position->piecesOfType[PAWN | oppColor]) || (rank(position->king[oppColor]) == rank(square) + colorSign[color]))) { base->openingPoints[color] += QUEEN_BONUS_ON_SEVENTH_RANK_OPENING; base->endgamePoints[color] += QUEEN_BONUS_ON_SEVENTH_RANK_ENDGAME; } if (base->evaluateKingSafety[oppColor] && (moves & base->kingAttackSquares[oppColor]) != EMPTY_BITBOARD) { base->numAttackers[color]++; base->attackPoints[color] += QUEEN_BONUS_ATTACK; } #ifdef BONUS_SPACE_ATTACKS if (testSquare(attackingRealm[color], square)) { base->spaceAttackPoints[color] += 3; } #endif } INLINE static int getSafetyMalusOfKingFile(const Position * position, const int file, const Square kingSquare, const Color color) { const Square startSquare = getSquare(file, rank(kingSquare)); const Square promotionSquare = (color == WHITE ? getSquare(file, RANK_8) : getSquare(file, RANK_1)); Bitboard candidates = (squaresBetween[startSquare][promotionSquare] | (minValue[startSquare])) & position->piecesOfType[PAWN | color]; int promotionDistance = 0, pawnSquare; ITERATE_BITBOARD(&candidates, pawnSquare) { if (distance(pawnSquare, promotionSquare) > promotionDistance) { promotionDistance = distance(pawnSquare, promotionSquare); } } assert(promotionDistance >= 0 && promotionDistance <= 6); return 36 - promotionDistance * promotionDistance; } INLINE static int getPawnAttackMalusOfKingFile(const Position * position, const int file, const Color color) { const Color oppColor = opponent(color); const Square promotionSquare = (color == WHITE ? getSquare(file, RANK_1) : getSquare(file, RANK_8)); Bitboard candidates = squaresOfFile[file] & position->piecesOfType[PAWN | oppColor]; int promotionDistance = 7, pawnSquare; ITERATE_BITBOARD(&candidates, pawnSquare) { if (distance(pawnSquare, promotionSquare) < promotionDistance) { promotionDistance = distance(pawnSquare, promotionSquare); } } assert(promotionDistance >= 1 && promotionDistance <= 7); return KING_MALUS_PAWN_ATTACK[promotionDistance]; } INLINE static int getExpositionValue(const Position * position, const Square kingSquare, const Color color) { const Bitboard obstacles = position->piecesOfType[PAWN | color]; const Bitboard diaExposition = getMagicBishopMoves(kingSquare, obstacles) & ~obstacles; const int diaExpositionValue = 6 - min(6, getNumberOfSetSquares(diaExposition)); return 36 - diaExpositionValue * diaExpositionValue; } INLINE static int getSafetyMalusOfKingSquare(const Position * position, const Square kingSquare, const Color color) { const int kingFile = file(kingSquare); int malus = getExpositionValue(position, kingSquare, color) + getSafetyMalusOfKingFile(position, kingFile, kingSquare, color); if (kingFile > FILE_A) { malus += getSafetyMalusOfKingFile(position, kingFile - 1, kingSquare, color); } if (kingFile < FILE_H) { malus += getSafetyMalusOfKingFile(position, kingFile + 1, kingSquare, color); } if (malus == 0) { malus = 11; /* malus for weak back rank */ } malus += getPawnAttackMalusOfKingFile(position, kingFile, color); if (kingFile > FILE_A) { malus += getPawnAttackMalusOfKingFile(position, kingFile - 1, color); } if (kingFile < FILE_H) { malus += getPawnAttackMalusOfKingFile(position, kingFile + 1, color); } return malus; } static int getPawnShelterMalus(const Position * position, const Color color, KingSafetyHashInfo * kingSafetyHashtable) { const Bitboard hashValue = getKingPawnSafetyHashValue(position, color); KingSafetyHashInfo *kingSafetyHashInfo = &kingSafetyHashtable[hashValue & KINGSAFETY_HASHTABLE_MASK]; if (kingSafetyHashInfo->hashValue == hashValue && kingSafetyHashInfo->hashValue != 0) { return kingSafetyHashInfo->safetyMalus; } else { const int rankByColor[2] = { RANK_1, RANK_8 }; int cr00, cr000; const Square kingSquare = position->king[color]; int pawnShelterMalus = 0, castlingShelterMalus = 0; if (color == WHITE) { cr00 = WHITE_00, cr000 = WHITE_000; } else { cr00 = BLACK_00, cr000 = BLACK_000; } pawnShelterMalus = castlingShelterMalus = getSafetyMalusOfKingSquare(position, kingSquare, color); if (position->castlingRights & cr00) { const Square kingSquare = getSquare(FILE_G, rankByColor[color]); const int malus00 = getSafetyMalusOfKingSquare(position, kingSquare, color); castlingShelterMalus = min(malus00, castlingShelterMalus); } if (position->castlingRights & cr000) { const Square kingSquare = getSquare(FILE_B, rankByColor[color]); const int malus000 = getSafetyMalusOfKingSquare(position, kingSquare, color); castlingShelterMalus = min(malus000, castlingShelterMalus); } pawnShelterMalus = (pawnShelterMalus + castlingShelterMalus) / 2; kingSafetyHashInfo->hashValue = hashValue; kingSafetyHashInfo->safetyMalus = pawnShelterMalus; return pawnShelterMalus; } } static int getKingSafetyMalus(const Position * position, EvaluationBase * base, const Color color) { const Color oppColor = opponent(color); const Square kingSquare = position->king[color]; const Bitboard protectingPawn = (color == WHITE ? minValue[kingSquare] << 8 : minValue[kingSquare] >> 8); const Bitboard pawnAttackers = position->piecesOfType[PAWN | oppColor] & kingAttacks[kingSquare]. pawnAttackers[oppColor] & ~protectingPawn; int pawnShelterMalus = 0, attackMalus = 0; #ifdef MALUS_QUEEN_DEFENDER_DISTANCE int queenMalus; const int queenDistance = getMinimalTaxiDistance(position, kingSquare, (Piece) (QUEEN | color)); #endif base->numAttackers[oppColor] += getNumberOfSetSquares(pawnAttackers); attackMalus = (base->attackPoints[oppColor] * KING_ATTACK_WEIGHT[base->numAttackers[oppColor]]) / 256; #ifdef MALUS_QUEEN_DEFENDER_DISTANCE queenMalus = (KING_ATTACK_WEIGHT[min(16, 1 + base->numAttackers[oppColor])] * queenDistance * 8) / 256; #endif pawnShelterMalus = getPawnShelterMalus(position, color, base->kingsafetyHashtable); #ifdef MALUS_QUEEN_DEFENDER_DISTANCE return attackMalus + pawnShelterMalus + queenMalus; #else return attackMalus + pawnShelterMalus; #endif } Bitboard getPromotablePawns(const Position * position, const Color color) { const Color oppColor = opponent(color); const Square oppKing = position->king[oppColor]; const bool lightSquaredBishop = (bool) (EMPTY_BITBOARD != (lightSquares & position->piecesOfType[BISHOP | color])); const Bitboard pawns = position->piecesOfType[PAWN | color]; Bitboard supporters; File excludeFile; Rank promotionRank; Square promotionSquare; if (color == WHITE) { excludeFile = (lightSquaredBishop ? FILE_H : FILE_A); promotionRank = RANK_8; } else { excludeFile = (lightSquaredBishop ? FILE_A : FILE_H); promotionRank = RANK_1; } promotionSquare = getSquare(excludeFile, promotionRank); supporters = companionFiles[promotionSquare] & pawns; if (distance(oppKing, promotionSquare) <= 1 && supporters == EMPTY_BITBOARD) { return pawns & ~squaresOfFile[excludeFile]; } else { return pawns; } } static int getWinningChances(const Position * position, const Color color) { const int MIN_CHANCES = 1; const Color oppColor = opponent(color); const int numPawns = position->numberOfPawns[color]; const int numPieces = position->numberOfPieces[color] - numPawns - 1; const int numOppPawns = position->numberOfPawns[oppColor]; const int numOppPieces = position->numberOfPieces[oppColor] - numOppPawns - 1; const bool rookPresent = pieceIsPresent(position, (Piece) (ROOK | color)); const bool queenPresent = pieceIsPresent(position, (Piece) (QUEEN | color)); if (rookPresent || queenPresent) { const bool oppRookPresent = pieceIsPresent(position, (Piece) (ROOK | oppColor)); const bool oppQueenPresent = pieceIsPresent(position, (Piece) (QUEEN | oppColor)); if (queenPresent) { if (numPieces == 1 && numPawns == 2 && oppQueenPresent) { const Bitboard pawns = position->piecesOfType[PAWN | color]; if ((((pawns & squaresOfFile[FILE_A]) && (pawns & squaresOfFile[FILE_B])) || ((pawns & squaresOfFile[FILE_H]) && (pawns & squaresOfFile[FILE_G])))) { return 12; } } if (rookPresent || numPawns >= 2 || numPieces >= 3 || getPieceCount(position, (Piece) (QUEEN | color)) >= 2) { return 16; } assert(rookPresent == FALSE); assert(numPawns <= 1); assert(numPieces <= 2); assert(getPieceCount(position, (Piece) (QUEEN | color)) == 1); if (numPawns == 0) /* KQKx, KQBKx, KQNKx */ { if (oppQueenPresent || getPieceCount(position, (Piece) (ROOK | oppColor)) >= 2) { return 2; /* KQBKQ, KQNKQ, KQBKRR, KQNKRR */ } else if (numPieces == 1 && numOppPieces >= 2) { /* single queen vs. two pieces */ return (oppRookPresent ? 2 : 8); } } else { assert(numPawns == 1); if (numPieces == 1 && (oppQueenPresent || (numOppPieces >= 2 && oppRookPresent))) { /* KQPKQx, KQPKRBx, KQPKRNx */ Bitboard pawns = position->piecesOfType[(Piece) (PAWN | color)]; const Square pawnSquare = getNextSquare(&pawns); assert(pawnSquare != NO_SQUARE); if (testSquare(passedPawnCorridor[color][pawnSquare], position->king[oppColor])) { return 4; } else { return 16; } } if (numPieces == 2 && oppQueenPresent && numOppPieces >= 2) { assert(pieceIsPresent(position, (Piece) (KNIGHT | color)) || pieceIsPresent(position, (Piece) (BISHOP | color))); /* KQ[BN]PKQ[RBN] */ return 4; /* kamikaze sac possible */ } } } else /* rook present: */ { assert(rookPresent); assert(queenPresent == FALSE); if (numPieces == 1 && numPawns == 2) { const Bitboard pawns = position->piecesOfType[(Piece) (PAWN | color)]; if ((((pawns & squaresOfFile[FILE_A]) && (pawns & squaresOfFile[FILE_C])) || ((pawns & squaresOfFile[FILE_H]) && (pawns & squaresOfFile[FILE_F])))) { return 12; } } if (numPawns >= 2 || numPieces >= 3) { if (getPieceCount(position, (Piece) (ROOK | color)) == 1 && numPawns == 0 && oppRookPresent && numPieces <= numOppPieces + 1) { return 4; /* R+[BN]+[BN] vs. R+[BN] */ } if (numPawns == 0 && getPieceCount(position, (Piece) (ROOK | oppColor)) >= 2) { /* R+R+[BN] vs. R+R+x */ return 2; } return 16; } assert(numPawns <= 1); assert(numPieces <= 2); if (getPieceCount(position, (Piece) (ROOK | color)) == 2) { if (numPawns >= 1) { return 16; } assert(numPawns == 0); if (oppQueenPresent || (oppRookPresent && numOppPieces >= 2)) { /* 2 rooks vs. queen */ return 2; } else { return 16; } } assert(getPieceCount(position, (Piece) (ROOK | color)) == 1); if (numPawns == 0) { if (oppQueenPresent || oppRookPresent) { /* rook (+ minor piece) vs. queen */ return 2; } else { /* rook (+ minor piece) vs. minor piece(s) */ return (numPieces > numOppPieces ? 16 : 2); } } else { assert(numPawns == 1); if (numPieces == 1) { if (numOppPieces >= 2) { /* rook + pawn vs. 2+ pieces */ if (oppRookPresent || pieceIsPresent(position, (Piece) (BISHOP | oppColor))) { return 2; /* kamikaze sac possible */ } else { return 16; /* two knights might have serious problems */ } } if (oppRookPresent || numOppPawns >= 2) { return 12; } } else { assert(numPieces == 2); if (oppRookPresent && numOppPieces >= 2) { /* KR[BN]PKR[BN]x */ return 8; /* kamikaze sac possible */ } } } } } else /* no major pieces present: */ { const bool kamikazeSac = (bool) (numOppPieces >= numPawns); if (numPieces == 0) /* king (+pawns) */ { if (numPawns == 0) { return 0; } else { Bitboard pawns = position->piecesOfType[(Piece) (PAWN | color)]; if ((pawns & nonA & nonH) != EMPTY_BITBOARD) { return 16; } else { const Square king = position->king[color]; const Square oppKing = position->king[oppColor]; Square square; ITERATE_BITBOARD(&pawns, square) { const int promotionRank = (color == WHITE ? RANK_8 : RANK_1); const Square promotionSquare = getSquare(file(square), promotionRank); const int oppKingDist = distance(oppKing, promotionSquare); assert(file(square) == FILE_A || file(square) == FILE_H); if (oppKingDist > distance(square, promotionSquare) || oppKingDist > distance(king, promotionSquare)) { return 16; } } return MIN_CHANCES; /* king holds pawn(s) */ } } } if (numPawns == 0 && numPieces - numOppPieces <= 1 && getPieceCount(position, (Piece) (BISHOP | color)) < 2) { /* no pawns, only one minor piece up */ if (numOppPawns > 0 && numOppPieces > 0 && pieceIsPresent(position, (Piece) (BISHOP | color)) == FALSE) { return 12; /* opp might have chances */ } return (numPieces > 1 ? MIN_CHANCES + 1 : MIN_CHANCES); } if (numPawns == 1 && numPieces <= numOppPieces) { return 2; /* one pawn, opp may sac piece for pawn */ } if (pieceIsPresent(position, (Piece) (KNIGHT | color)) == FALSE) { /* only bishops: */ const Bitboard exclude = position->piecesOfType[(Piece) (PAWN | color)] | minValue[position->king[color]]; const Bitboard bishops = position->piecesOfColor[color] & ~exclude; int numBishops = numPieces; assert(getPieceCount(position, (Piece) (BISHOP | color)) == numPieces); if (numPieces > 1) { if (((bishops & lightSquares) == EMPTY_BITBOARD) || ((bishops & darkSquares) == EMPTY_BITBOARD)) { numBishops = 1; } } if (numBishops == 2 && numPawns == 0) { if (pieceIsPresent(position, (Piece) (ROOK | oppColor)) || pieceIsPresent(position, (Piece) (BISHOP | oppColor))) { return MIN_CHANCES; } } if (numBishops == 1) { const bool oppColors = oppositeColoredBishops(position); const int max = (oppColors ? 8 : 16); if (numPawns == 0) { return MIN_CHANCES; } else if (kamikazeSac) { if (pieceIsPresent(position, (Piece) (BISHOP | oppColor)) || pieceIsPresent(position, (Piece) (ROOK | oppColor))) { return 4; } else { return 12; } } else { const Bitboard promotablePawns = getPromotablePawns(position, color); const int numPromotablePawns = getNumberOfSetSquares(promotablePawns); const int numDefenders = (oppColors ? getPieceCount(position, (Piece) (BISHOP | oppColor)) : 0); return (numPromotablePawns > numDefenders ? max : MIN_CHANCES); } } } else if (pieceIsPresent(position, (Piece) (BISHOP | color)) == FALSE) { /* only knights: */ assert(getPieceCount(position, (Piece) (KNIGHT | color)) == numPieces); if (numPieces == 2) { /* king + two knights (+ pawn) */ if (numPawns == 0) { if (numOppPawns > 0 && pieceIsPresent(position, (Piece) (ROOK | oppColor))) { return 12; /* winning chances for opponent */ } else if (numOppPieces == 0 && numOppPawns != 0) { return 2; /* small chances */ } else { return MIN_CHANCES; /* no chances */ } } if (kamikazeSac) { return 12; } } if (numPieces == 1) { Bitboard pawns = position->piecesOfType[(Piece) (PAWN | color)]; if (numPawns == 0) { return MIN_CHANCES; } else if (kamikazeSac) { if (pieceIsPresent(position, (Piece) (BISHOP | oppColor)) || pieceIsPresent(position, (Piece) (ROOK | oppColor))) { return 4; } else { return 12; } } else if ((pawns & nonA & nonH) != EMPTY_BITBOARD) { return 16; } else /* Check for advanced border pawns: */ { const Square pawnSquare = getNextSquare(&pawns); const int promotionRank = (color == WHITE ? RANK_8 : RANK_1); const Square promotionSquare = getSquare(file(pawnSquare), promotionRank); assert(pawnSquare != NO_SQUARE); assert(file(pawnSquare) == FILE_A || file(pawnSquare) == FILE_H); if (distance(pawnSquare, promotionSquare) == 1 && distance(position->king[oppColor], promotionSquare) <= 1) { assert((color == WHITE && rank(pawnSquare) == RANK_7) || (color == BLACK && rank(pawnSquare) == RANK_2)); return MIN_CHANCES; } } } } } return 16; } INLINE static bool kingSafetyEvalRequired(const Position * position, const Color color) { const Color oppColor = opponent(color); return (bool) (numberOfNonPawnPieces(position, oppColor) >= 3 && position->piecesOfType[QUEEN | oppColor] != EMPTY_BITBOARD); } INLINE static int getPawnAttackDistance(const Position * position, const EvaluationBase * base, const Color color) { const Color oppColor = opponent(color); const Bitboard forbiddenSquares = position->piecesOfType[PAWN | color] | base->pawnProtectedSquares[oppColor]; return getFloodValue(position->king[color], position->piecesOfType[PAWN | oppColor], ~forbiddenSquares); } INLINE static bool kingIsOffside(const Position * position, const EvaluationBase * base, const Color color, int *distanceDiff) { if (base->passedPawns[color] != EMPTY_BITBOARD || position->piecesOfType[PAWN | color] == EMPTY_BITBOARD) { return FALSE; } else { const Color oppColor = opponent(color); const Bitboard realm = kingRealm[oppColor] [position->king[oppColor]][position->king[color]]; const Bitboard ownPawns = position->piecesOfType[PAWN | color]; if ((realm & ownPawns) == ownPawns) { const int attackerDistance = getPawnAttackDistance(position, base, oppColor); const int defenderDistance = getPawnAttackDistance(position, base, color); *distanceDiff = (position->activeColor == color ? (defenderDistance - 1) - attackerDistance : defenderDistance - (attackerDistance - 1)); return (bool) (*distanceDiff > 1); } } return FALSE; } INLINE static bool kingIsTrapped(const Position * position, const Color kingColor) { const Square kingSquare = position->king[kingColor]; const Rank kingRank = colorRank(kingColor, kingSquare); const File kingFile = file(kingSquare); if (kingRank == RANK_1 && (kingFile == FILE_A || kingFile == FILE_H)) { const int upward = (kingColor == WHITE ? 8 : -8); const Color oppColor = opponent(kingColor); const Piece blockingPiece = position->piece[kingSquare + upward + upward]; if (position->piece[kingSquare + upward] == (PAWN | kingColor) && (blockingPiece == (PAWN | oppColor) || blockingPiece == (BISHOP | oppColor))) { return TRUE; } } return FALSE; } INLINE static void initializeEvaluationBase(EvaluationBase * base, KingSafetyHashInfo * kingsafetyHashtable) { base->openingPoints[WHITE] = base->openingPoints[BLACK] = 0; base->endgamePoints[WHITE] = base->endgamePoints[BLACK] = 0; base->kingsafetyHashtable = kingsafetyHashtable; } INLINE static void evaluatePieces(const Position * position, EvaluationBase * base) { const Bitboard exclude = position->piecesOfType[WHITE_PAWN] | position->piecesOfType[BLACK_PAWN] | minValue[position->king[WHITE]] | minValue[position->king[BLACK]]; Bitboard pieces = position->allPieces & (~exclude); Square square; ITERATE_BITBOARD(&pieces, square) { const PieceType pieceType = pieceType(position->piece[square]); switch (pieceType) { case QUEEN: evaluateQueen(position, base, square); break; case ROOK: evaluateRook(position, base, square); break; case BISHOP: evaluateBishop(position, base, square); break; case KNIGHT: evaluateKnight(position, base, square); break; } } if (position->piecesOfType[WHITE_BISHOP] != EMPTY_BITBOARD) { evaluateWhiteTrappedBishops(position, base); } if (position->piecesOfType[BLACK_BISHOP] != EMPTY_BITBOARD) { evaluateBlackTrappedBishops(position, base); } } INLINE Bitboard getFixedPawns(const Position * position, const EvaluationBase * base, const Color color) { const Color oppColor = opponent(color); const Bitboard candidates = position->piecesOfType[PAWN | color] & ~base->pawnProtectedSquares[color]; const Bitboard blockers = position->piecesOfType[PAWN | color] | position->piecesOfColor[oppColor] | base->pawnProtectedSquares[oppColor]; return candidates & (color == WHITE ? blockers >> 8 : blockers << 8); } INLINE static int getPositionalValue(Position * position, EvaluationBase * base) { int value, openingValue, endgameValue; const int pi = phaseIndex(position); #ifdef BONUS_TARGETS Bitboard defaultTargets; #endif #ifdef MALUS_OFFSIDE_KING Color color; #endif #ifdef BONUS_VALUABLE_TARGETS Color color; #endif assert(pi >= 0 && pi <= 256); base->openingPoints[WHITE] = base->openingPoints[BLACK] = base->endgamePoints[WHITE] = base->endgamePoints[BLACK] = 0; base->countedSquares[WHITE] = ~((position->piecesOfColor[WHITE] | base->pawnProtectedSquares[BLACK]) & ~getOrdinaryPieces(position, BLACK)); base->unprotectedPieces[WHITE] = position->piecesOfColor[WHITE] & ~base->pawnProtectedSquares[WHITE]; base->countedSquares[BLACK] = ~((position->piecesOfColor[BLACK] | base->pawnProtectedSquares[WHITE]) & ~getOrdinaryPieces(position, WHITE)); base->unprotectedPieces[BLACK] = position->piecesOfColor[BLACK] & ~base->pawnProtectedSquares[BLACK]; base->numAttackers[WHITE] = base->numAttackers[BLACK] = 0; base->attackPoints[WHITE] = base->attackPoints[BLACK] = 0; base->spaceAttackPoints[WHITE] = base->spaceAttackPoints[BLACK] = 0; #ifdef BONUS_TARGETS defaultTargets = (base->passedPawns[WHITE] << 8) | getFixedPawns(position, base, BLACK); base->openingTargets[WHITE] = base->endgameTargets[WHITE] = base->countedSquares[WHITE] & defaultTargets; defaultTargets = (base->passedPawns[BLACK] >> 8) | getFixedPawns(position, base, WHITE); base->openingTargets[BLACK] = base->endgameTargets[BLACK] = base->countedSquares[BLACK] & defaultTargets; #endif #ifdef CALCULATE_TARGETS base->pieceAttacks[WHITE] = base->pieceAttacks[BLACK] = EMPTY_BITBOARD; #endif if ((base->evaluateKingSafety[WHITE] = kingSafetyEvalRequired(position, WHITE)) != FALSE) { base->kingAttackSquares[WHITE] = getKingMoves(position->king[WHITE]); base->kingAttacks[WHITE] = &kingAttacks[position->king[WHITE]]; #ifdef BONUS_TARGETS base->openingTargets[WHITE] |= base->countedSquares[WHITE] & squaresInDistance[2][position->king[BLACK]]; #endif } if ((base->evaluateKingSafety[BLACK] = kingSafetyEvalRequired(position, BLACK)) != FALSE) { base->kingAttackSquares[BLACK] = getKingMoves(position->king[BLACK]); base->kingAttacks[BLACK] = &kingAttacks[position->king[BLACK]]; #ifdef BONUS_TARGETS base->openingTargets[BLACK] |= base->countedSquares[BLACK] & squaresInDistance[2][position->king[WHITE]]; #endif } evaluatePieces(position, base); if (base->passedPawns[WHITE] != EMPTY_BITBOARD || base->passedPawns[BLACK] != EMPTY_BITBOARD) { evaluatePassedPawns(position, base); } if (base->evaluateKingSafety[WHITE]) { base->openingPoints[WHITE] -= getKingSafetyMalus(position, base, WHITE); } if (base->evaluateKingSafety[BLACK]) { base->openingPoints[BLACK] -= getKingSafetyMalus(position, base, BLACK); } #ifdef MALUS_OFFSIDE_KING for (color = WHITE; color <= BLACK; color++) { const int numNonPawnPieces = numberOfNonPawnPieces(position, color); int distanceDiff = 0; if (numNonPawnPieces <= 2 && kingIsOffside(position, base, color, &distanceDiff)) { int malus = 0; if (numNonPawnPieces == 1) { malus = 30 * distanceDiff; } else { malus = 15 * distanceDiff; } base->endgamePoints[color] -= malus; } } #endif #ifdef BONUS_SPACE_ATTACKS { const Bitboard whiteAttackers = position->piecesOfColor[WHITE] & attackingRealm[WHITE]; const Bitboard blackAttackers = position->piecesOfColor[BLACK] & attackingRealm[BLACK]; const int numWhiteAttackers = getNumberOfSetSquares(whiteAttackers); const int numBlackAttackers = getNumberOfSetSquares(blackAttackers); base->openingPoints[WHITE] += SPACE_BONUS_WEIGHT[numWhiteAttackers] * (base->spaceAttackPoints[WHITE] + numWhiteAttackers); base->openingPoints[BLACK] += SPACE_BONUS_WEIGHT[numBlackAttackers] * (base->spaceAttackPoints[BLACK] + numBlackAttackers); } #endif openingValue = base->openingPoints[WHITE] - base->openingPoints[BLACK]; endgameValue = base->endgamePoints[WHITE] - base->endgamePoints[BLACK]; value = (openingValue * (256 - pi) + endgameValue * pi) / 256; return value; } int getValue(Position * position, const int alpha, const int beta, PawnHashInfo * pawnHashtable, KingSafetyHashInfo * kingsafetyHashtable) { const int MAX_DELTA = 200; EvaluationBase base; int value, lazyValue, chances = 16; Color winningColor; PawnHashInfo *pawnHashInfo = &pawnHashtable[position->pawnHashValue & PAWN_HASHTABLE_MASK]; initializeEvaluationBase(&base, kingsafetyHashtable); if (pawnHashInfo->hashValue == position->pawnHashValue && pawnHashInfo->hashValue != 0) { #ifndef NDEBUG getPawnInfo(position, &base); evaluatePawns(position, &base); assert(base.openingPoints[WHITE] == pawnHashInfo->openingPoints[WHITE]); assert(base.openingPoints[BLACK] == pawnHashInfo->openingPoints[BLACK]); assert(base.endgamePoints[WHITE] == pawnHashInfo->endgamePoints[WHITE]); assert(base.endgamePoints[BLACK] == pawnHashInfo->endgamePoints[BLACK]); assert(base.pawnProtectedSquares[WHITE] == pawnHashInfo->pawnProtectedSquares[WHITE]); assert(base.pawnProtectedSquares[BLACK] == pawnHashInfo->pawnProtectedSquares[BLACK]); assert(base.passedPawns[WHITE] == pawnHashInfo->passedPawns[WHITE]); assert(base.passedPawns[BLACK] == pawnHashInfo->passedPawns[BLACK]); #endif base.openingPoints[WHITE] = pawnHashInfo->openingPoints[WHITE]; base.openingPoints[BLACK] = pawnHashInfo->openingPoints[BLACK]; base.endgamePoints[WHITE] = pawnHashInfo->endgamePoints[WHITE]; base.endgamePoints[BLACK] = pawnHashInfo->endgamePoints[BLACK]; } else { getPawnInfo(position, &base); evaluatePawns(position, &base); pawnHashInfo->hashValue = position->pawnHashValue; pawnHashInfo->openingPoints[WHITE] = base.openingPoints[WHITE]; pawnHashInfo->openingPoints[BLACK] = base.openingPoints[BLACK]; pawnHashInfo->endgamePoints[WHITE] = base.endgamePoints[WHITE]; pawnHashInfo->endgamePoints[BLACK] = base.endgamePoints[BLACK]; pawnHashInfo->pawnProtectedSquares[WHITE] = base.pawnProtectedSquares[WHITE]; pawnHashInfo->pawnProtectedSquares[BLACK] = base.pawnProtectedSquares[BLACK]; pawnHashInfo->passedPawns[WHITE] = base.passedPawns[WHITE]; pawnHashInfo->passedPawns[BLACK] = base.passedPawns[BLACK]; pawnHashInfo->weakOutpostSquares[WHITE] = base.weakOutpostSquares[WHITE]; pawnHashInfo->weakOutpostSquares[BLACK] = base.weakOutpostSquares[BLACK]; pawnHashInfo->pawnAttackableSquares[WHITE] = base.pawnAttackableSquares[WHITE]; pawnHashInfo->pawnAttackableSquares[BLACK] = base.pawnAttackableSquares[BLACK]; #ifdef BONUS_HIDDEN_PASSER pawnHashInfo->hasPassersOrCandidates[WHITE] = base.hasPassersOrCandidates[WHITE]; pawnHashInfo->hasPassersOrCandidates[BLACK] = base.hasPassersOrCandidates[BLACK]; #endif } value = positionalBalance(position, &base); winningColor = (value > 0 ? position->activeColor : opponent(position->activeColor)); if (numberOfNonPawnPieces(position, winningColor) <= 4) { chances = getWinningChances(position, winningColor); } lazyValue = (value * chances) / 16; #ifdef TRACE_EVAL logDebug("\nStarting evaluation.\n"); logDebug("phaseIndex = %d\n", phaseIndex(position)); logDebug("opvWhite = %d egvWhite = %d\n", position->openingValue[WHITE], position->endgameValue[WHITE]); logDebug("opvBlack = %d egvBlack = %d\n", position->openingValue[BLACK], position->endgameValue[BLACK]); logDebug("basicValue = %d\n\n", basicValue); logPosition(position); logDebug("\n"); #endif if (numberOfNonPawnPieces(position, WHITE) <= 3 || numberOfNonPawnPieces(position, BLACK) <= 3 || (lazyValue >= alpha - MAX_DELTA && lazyValue <= beta + MAX_DELTA)) { int positionalValue; Color effectiveWinningColor; if (pawnHashInfo->hashValue == position->pawnHashValue && pawnHashInfo->hashValue != 0) { base.pawnProtectedSquares[WHITE] = pawnHashInfo->pawnProtectedSquares[WHITE]; base.pawnProtectedSquares[BLACK] = pawnHashInfo->pawnProtectedSquares[BLACK]; base.passedPawns[WHITE] = pawnHashInfo->passedPawns[WHITE]; base.passedPawns[BLACK] = pawnHashInfo->passedPawns[BLACK]; base.weakOutpostSquares[WHITE] = pawnHashInfo->weakOutpostSquares[WHITE]; base.weakOutpostSquares[BLACK] = pawnHashInfo->weakOutpostSquares[BLACK]; base.pawnAttackableSquares[WHITE] = pawnHashInfo->pawnAttackableSquares[WHITE]; base.pawnAttackableSquares[BLACK] = pawnHashInfo->pawnAttackableSquares[BLACK]; #ifdef BONUS_HIDDEN_PASSER base.hasPassersOrCandidates[WHITE] = pawnHashInfo->hasPassersOrCandidates[WHITE]; base.hasPassersOrCandidates[BLACK] = pawnHashInfo->hasPassersOrCandidates[BLACK]; #endif } positionalValue = getPositionalValue(position, &base); value += (position->activeColor == WHITE ? positionalValue : -positionalValue); effectiveWinningColor = (value > 0 ? position->activeColor : opponent(position->activeColor)); if (effectiveWinningColor != winningColor) { chances = (numberOfNonPawnPieces(position, effectiveWinningColor) <= 4 ? getWinningChances(position, effectiveWinningColor) : 16); } } return (value * chances) / 16; } static void transposeMatrix(const int human[], int machine[]) { int file, rank, i = 0; for (rank = RANK_8; rank >= RANK_1; rank--) { for (file = FILE_A; file <= FILE_H; file++) { const Square machineSquare = getSquare(file, rank); machine[machineSquare] = human[i++]; } } } #define PSV(piece,square,stage) pieceSquareValue[(piece)][(square)][(stage)] static void initializePieceSquareValues() { const int PawnFileOpening = 5; const int KnightCentreOpening = 5; const int KnightCentreEndgame = 5; const int KnightRankOpening = 5; const int KnightBackRankOpening = 0; const int KnightTrapped = 100; const int BishopCentreOpening = 2; const int BishopCentreEndgame = 3; const int BishopBackRankOpening = 10; const int BishopDiagonalOpening = 4; const int RookFileOpening = 3; const int QueenCentreOpening = 1; const int QueenCentreEndgame = 4; const int QueenBackRankOpening = 5; const int KingCentreEndgame = 12; const int KingFileOpening = 10; const int KingRankOpening = 10; const int PawnFile[8] = { -3, -1, +0, +1, +1, +0, -1, -3, }; const int KnightLine[8] = { -4, -2, +0, +1, +1, +0, -2, -4, }; const int KnightRank[8] = { -2, -1, +0, +1, +2, +3, +2, +1, }; const int BishopLine[8] = { -3, -1, +0, +1, +1, +0, -1, -3, }; const int RookFile[8] = { -2, -1, +0, +1, +1, +0, -1, -2, }; const int QueenFileOpening[8] = { -2, -1, +0, +0, +0, +0, -1, -2, }; const int QueenRankOpening[8] = { -1, +0, +0, +0, +0, +0, +0, -1, }; const int QueenFileEndgame[8] = { -3, -1, +0, +1, +1, +0, -1, -3, }; const int QueenRankEndgame[8] = { -3, -1, +0, +1, +1, +0, -1, -3, }; const int KingFileEndgame[8] = { -3, -1, +0, +1, +1, +0, -1, -3, }; const int KingRankEndgame[8] = { -3, -1, +0, +1, +1, +0, -1, -3, }; const int KingFile[8] = { +3, +4, +2, +0, +0, +2, +4, +3, }; const int KingRank[8] = { +1, +0, -2, -3, -4, -5, -6, -7, }; int i; Square sq; for (i = 0; i < 16; i++) { int j; for (j = 0; j < _64_; j++) { pieceSquareValue[i][j][0] = pieceSquareValue[i][j][1] = 0; } } /* pawns */ ITERATE(sq) { PSV(WHITE_PAWN, sq, OPENING) += PawnFile[file(sq)] * PawnFileOpening; PSV(WHITE_PAWN, sq, OPENING) += PAWN_VALUE_OPENING; PSV(WHITE_PAWN, sq, ENDGAME) += PAWN_VALUE_ENDGAME; } PSV(WHITE_PAWN, D3, OPENING) += 10; PSV(WHITE_PAWN, E3, OPENING) += 10; PSV(WHITE_PAWN, D4, OPENING) += 20; PSV(WHITE_PAWN, E4, OPENING) += 20; PSV(WHITE_PAWN, D5, OPENING) += 10; PSV(WHITE_PAWN, E5, OPENING) += 10; /* knights */ ITERATE(sq) { PSV(WHITE_KNIGHT, sq, OPENING) += VALUE_KNIGHT_OPENING; PSV(WHITE_KNIGHT, sq, ENDGAME) += VALUE_KNIGHT_ENDGAME; PSV(WHITE_KNIGHT, sq, OPENING) += KnightLine[file(sq)] * KnightCentreOpening; PSV(WHITE_KNIGHT, sq, OPENING) += KnightLine[rank(sq)] * KnightCentreOpening; PSV(WHITE_KNIGHT, sq, ENDGAME) += KnightLine[file(sq)] * KnightCentreEndgame; PSV(WHITE_KNIGHT, sq, ENDGAME) += KnightLine[rank(sq)] * KnightCentreEndgame; PSV(WHITE_KNIGHT, sq, OPENING) += KnightRank[rank(sq)] * KnightRankOpening; } for (sq = A1; sq <= H1; sq++) { PSV(WHITE_KNIGHT, sq, OPENING) -= KnightBackRankOpening; } PSV(WHITE_KNIGHT, A8, OPENING) -= KnightTrapped; PSV(WHITE_KNIGHT, H8, OPENING) -= KnightTrapped; /* bishops */ ITERATE(sq) { PSV(WHITE_BISHOP, sq, OPENING) += VALUE_BISHOP_OPENING; PSV(WHITE_BISHOP, sq, ENDGAME) += VALUE_BISHOP_ENDGAME; PSV(WHITE_BISHOP, sq, OPENING) += BishopLine[file(sq)] * BishopCentreOpening; PSV(WHITE_BISHOP, sq, OPENING) += BishopLine[rank(sq)] * BishopCentreOpening; PSV(WHITE_BISHOP, sq, ENDGAME) += BishopLine[file(sq)] * BishopCentreEndgame; PSV(WHITE_BISHOP, sq, ENDGAME) += BishopLine[rank(sq)] * BishopCentreEndgame; } for (sq = A1; sq <= H1; sq++) { PSV(WHITE_BISHOP, sq, OPENING) -= BishopBackRankOpening; } for (i = 0; i < 8; i++) { sq = getSquare(i, i); PSV(WHITE_BISHOP, sq, OPENING) += BishopDiagonalOpening; PSV(WHITE_BISHOP, getFlippedSquare(sq), OPENING) += BishopDiagonalOpening; } /* rooks */ ITERATE(sq) { PSV(WHITE_ROOK, sq, OPENING) += VALUE_ROOK_OPENING; PSV(WHITE_ROOK, sq, ENDGAME) += VALUE_ROOK_ENDGAME; PSV(WHITE_ROOK, sq, OPENING) += RookFile[file(sq)] * RookFileOpening - 25; } /* queens */ ITERATE(sq) { PSV(WHITE_QUEEN, sq, OPENING) += VALUE_QUEEN_OPENING; PSV(WHITE_QUEEN, sq, ENDGAME) += VALUE_QUEEN_ENDGAME; PSV(WHITE_QUEEN, sq, OPENING) += QueenFileOpening[file(sq)] * QueenCentreOpening; PSV(WHITE_QUEEN, sq, OPENING) += QueenRankOpening[rank(sq)] * QueenCentreOpening; PSV(WHITE_QUEEN, sq, ENDGAME) += QueenFileEndgame[file(sq)] * QueenCentreEndgame; PSV(WHITE_QUEEN, sq, ENDGAME) += QueenRankEndgame[rank(sq)] * QueenCentreEndgame; } for (sq = A1; sq <= H1; sq++) { PSV(WHITE_QUEEN, sq, OPENING) -= QueenBackRankOpening; } /* king */ ITERATE(sq) { PSV(WHITE_KING, sq, ENDGAME) += KingFileEndgame[file(sq)] * KingCentreEndgame; PSV(WHITE_KING, sq, ENDGAME) += KingRankEndgame[rank(sq)] * KingCentreEndgame; PSV(WHITE_KING, sq, OPENING) += KingFile[file(sq)] * KingFileOpening; PSV(WHITE_KING, sq, OPENING) += KingRank[rank(sq)] * KingRankOpening; } /* Set the value of the black pieces. */ ITERATE(sq) { int stage; for (stage = OPENING; stage <= ENDGAME; stage++) { pieceSquareValue[BLACK_KING][sq][stage] = pieceSquareValue[WHITE_KING][getFlippedSquare(sq)][stage]; pieceSquareValue[BLACK_QUEEN][sq][stage] = pieceSquareValue[WHITE_QUEEN][getFlippedSquare(sq)][stage]; pieceSquareValue[BLACK_ROOK][sq][stage] = pieceSquareValue[WHITE_ROOK][getFlippedSquare(sq)][stage]; pieceSquareValue[BLACK_BISHOP][sq][stage] = pieceSquareValue[WHITE_BISHOP][getFlippedSquare(sq)][stage]; pieceSquareValue[BLACK_KNIGHT][sq][stage] = pieceSquareValue[WHITE_KNIGHT][getFlippedSquare(sq)][stage]; pieceSquareValue[BLACK_PAWN][sq][stage] = pieceSquareValue[WHITE_PAWN][getFlippedSquare(sq)][stage]; } } } void initializeKingAttacks() { Square square; ITERATE(square) { const Bitboard corona = getKingMoves(square); KingAttacks *attackInfo = &kingAttacks[square]; Square attackerSquare; attackInfo->diaAttackers = attackInfo->orthoAttackers = attackInfo->knightAttackers = attackInfo->pawnAttackers[WHITE] = attackInfo->pawnAttackers[WHITE] = EMPTY_BITBOARD; ITERATE(attackerSquare) { attackInfo->attackedByDia[attackerSquare] = attackInfo->attackedByOrtho[attackerSquare] = NO_SQUARE; } ITERATE(attackerSquare) { Bitboard dia, ortho; const Bitboard knight = corona & generalMoves[WHITE_KNIGHT][attackerSquare]; const Bitboard whitePawn = corona & generalMoves[WHITE_PAWN][attackerSquare]; const Bitboard blackPawn = corona & generalMoves[BLACK_PAWN][attackerSquare]; dia = corona & generalMoves[WHITE_BISHOP][attackerSquare]; ortho = corona & generalMoves[WHITE_ROOK][attackerSquare]; if (dia != EMPTY_BITBOARD) { Square attackedSquare; int dist = 8; setSquare(attackInfo->diaAttackers, attackerSquare); ITERATE_BITBOARD(&dia, attackedSquare) { const int currentDistance = distance(attackerSquare, attackedSquare); if (currentDistance < dist) { attackInfo->attackedByDia[attackerSquare] = attackedSquare; dist = currentDistance; } } } if (ortho != EMPTY_BITBOARD) { Square attackedSquare; int dist = 8; setSquare(attackInfo->orthoAttackers, attackerSquare); ITERATE_BITBOARD(&ortho, attackedSquare) { const int currentDistance = distance(attackerSquare, attackedSquare); if (currentDistance < dist) { attackInfo->attackedByOrtho[attackerSquare] = attackedSquare; dist = currentDistance; } } } if (knight != EMPTY_BITBOARD) { setSquare(attackInfo->knightAttackers, attackerSquare); } if (whitePawn != EMPTY_BITBOARD) { setSquare(attackInfo->pawnAttackers[WHITE], attackerSquare); } if (blackPawn != EMPTY_BITBOARD) { setSquare(attackInfo->pawnAttackers[BLACK], attackerSquare); } } } } int initializeModuleEvaluation() { int i; Square square, kingsquare, catchersquare; centralFiles = squaresOfFile[FILE_D] | squaresOfFile[FILE_E]; attackingRealm[WHITE] = squaresOfRank[RANK_5] | squaresOfRank[RANK_6] | squaresOfRank[RANK_7] | squaresOfRank[RANK_8]; attackingRealm[BLACK] = squaresOfRank[RANK_4] | squaresOfRank[RANK_3] | squaresOfRank[RANK_2] | squaresOfRank[RANK_1]; rookTraps[WHITE] = rookTraps[BLACK] = EMPTY_BITBOARD; setSquare(rookTraps[WHITE], A1); setSquare(rookTraps[WHITE], B1); setSquare(rookTraps[WHITE], C1); setSquare(rookTraps[WHITE], A2); setSquare(rookTraps[WHITE], B2); setSquare(rookTraps[WHITE], F1); setSquare(rookTraps[WHITE], G1); setSquare(rookTraps[WHITE], H1); setSquare(rookTraps[WHITE], G2); setSquare(rookTraps[WHITE], H2); ITERATE(square) { Color color; Square kingSquare; for (color = WHITE; color <= BLACK; color++) { passedPawnRectangle[color][square] = passedPawnCorridor[color][square] = candidateDefenders[color][square] = candidateSupporters[color][square] = EMPTY_BITBOARD; } if (testSquare(rookTraps[WHITE], square)) { setSquare(rookTraps[BLACK], getFlippedSquare(square)); } ITERATE(kingSquare) { kingRealm[WHITE][square][kingSquare] = kingRealm[BLACK][square][kingSquare] = EMPTY_BITBOARD; } } ITERATE(square) { const int squarefile = file(square); const int squarerank = rank(square); int d1 = min(distance(square, D4), distance(square, E4)); int d2 = min(distance(square, D5), distance(square, E5)); int td1 = min(taxiDistance(square, D4), taxiDistance(square, E4)); int td2 = min(taxiDistance(square, D5), taxiDistance(square, E5)); centerDistance[square] = min(d1, d2); centerTaxiDistance[square] = min(td1, td2); butterflySquares[square] = generalMoves[KING][square] & ~squaresOfFile[squarefile]; lateralSquares[square] = generalMoves[KING][square] & squaresOfRank[squarerank]; companionFiles[square] = ((squaresOfFile[squarefile] & nonA) >> 1) | ((squaresOfFile[squarefile] & nonH) << 1); rookBlockers[square] = EMPTY_BITBOARD; ITERATE(kingsquare) { const int kingsquarefile = file(kingsquare); const int kingsquarerank = rank(kingsquare); Square targetSquare; if (kingsquarerank >= squarerank && distance(square, kingsquare) <= 7 - squarerank) { setSquare(passedPawnRectangle[WHITE][square], kingsquare); } if (kingsquarerank <= squarerank && distance(square, kingsquare) <= squarerank) { setSquare(passedPawnRectangle[BLACK][square], kingsquare); } if (kingsquarefile == squarefile) { if (kingsquarerank > squarerank) { setSquare(passedPawnCorridor[WHITE][square], kingsquare); } if (kingsquarerank < squarerank) { setSquare(passedPawnCorridor[BLACK][square], kingsquare); } } if (squarerank == kingsquarerank) { if (squarefile <= FILE_C && kingsquarefile <= FILE_C && kingsquarefile > squarefile) { setSquare(rookBlockers[square], kingsquare); } if (squarefile >= FILE_F && kingsquarefile >= FILE_F && kingsquarefile < squarefile) { setSquare(rookBlockers[square], kingsquare); } } ITERATE(targetSquare) { if (distance(square, targetSquare) < distance(kingsquare, targetSquare)) { const Rank targetrank = rank(targetSquare); if (targetrank <= squarerank + 1) { setSquare(kingRealm[WHITE][square][kingsquare], targetSquare); } if (targetrank >= squarerank - 1) { setSquare(kingRealm[BLACK][square][kingsquare], targetSquare); } } } } ITERATE(catchersquare) { if (abs(file(catchersquare) - squarefile) == 1) { if (rank(catchersquare) > squarerank) { setSquare(candidateDefenders[WHITE][square], catchersquare); } if (rank(catchersquare) <= squarerank) { setSquare(candidateSupporters[WHITE][square], catchersquare); } if (rank(catchersquare) < squarerank) { setSquare(candidateDefenders[BLACK][square], catchersquare); } if (rank(catchersquare) >= squarerank) { setSquare(candidateSupporters[BLACK][square], catchersquare); } } } } ITERATE(square) { const int squarerank = rank(square); ITERATE(kingsquare) { if (squarerank >= RANK_2 && squarerank <= RANK_7) { passedPawnDefenderMalus[WHITE][WHITE][square][kingsquare] = getPassedPawnDefenderMalus(WHITE, WHITE, square, kingsquare); passedPawnDefenderMalus[WHITE][BLACK][square][kingsquare] = getPassedPawnDefenderMalus(WHITE, BLACK, square, kingsquare); passedPawnDefenderMalus[BLACK][WHITE][square][kingsquare] = getPassedPawnDefenderMalus(BLACK, WHITE, square, kingsquare); passedPawnDefenderMalus[BLACK][BLACK][square][kingsquare] = getPassedPawnDefenderMalus(BLACK, BLACK, square, kingsquare); } else { passedPawnDefenderMalus[WHITE][WHITE][square][kingsquare] = passedPawnDefenderMalus[WHITE][BLACK][square][kingsquare] = passedPawnDefenderMalus[BLACK][WHITE][square][kingsquare] = passedPawnDefenderMalus[BLACK][BLACK][square][kingsquare] = 0; } } } initializePieceSquareValues(); initializeKingAttacks(); attackPoints[WHITE_KING] = 0; attackPoints[WHITE_QUEEN] = QUEEN_BONUS_ATTACK; attackPoints[WHITE_ROOK] = ROOK_BONUS_ATTACK; attackPoints[WHITE_BISHOP] = BISHOP_BONUS_ATTACK; attackPoints[WHITE_KNIGHT] = KNIGHT_BONUS_ATTACK; attackPoints[WHITE_PAWN] = 0; attackPoints[BLACK_KING] = 0; attackPoints[BLACK_QUEEN] = QUEEN_BONUS_ATTACK; attackPoints[BLACK_ROOK] = ROOK_BONUS_ATTACK; attackPoints[BLACK_BISHOP] = BISHOP_BONUS_ATTACK; attackPoints[BLACK_KNIGHT] = KNIGHT_BONUS_ATTACK; attackPoints[BLACK_PAWN] = 0; weakOutpostSquareCandidates[WHITE] = weakOutpostSquareCandidates[BLACK] = EMPTY_BITBOARD; setSquare(weakOutpostSquareCandidates[WHITE], C4); setSquare(weakOutpostSquareCandidates[WHITE], D4); setSquare(weakOutpostSquareCandidates[WHITE], E4); setSquare(weakOutpostSquareCandidates[WHITE], F4); setSquare(weakOutpostSquareCandidates[WHITE], C3); setSquare(weakOutpostSquareCandidates[WHITE], D3); setSquare(weakOutpostSquareCandidates[WHITE], E3); setSquare(weakOutpostSquareCandidates[WHITE], F3); setSquare(weakOutpostSquareCandidates[BLACK], C5); setSquare(weakOutpostSquareCandidates[BLACK], D5); setSquare(weakOutpostSquareCandidates[BLACK], E5); setSquare(weakOutpostSquareCandidates[BLACK], F5); setSquare(weakOutpostSquareCandidates[BLACK], C6); setSquare(weakOutpostSquareCandidates[BLACK], D6); setSquare(weakOutpostSquareCandidates[BLACK], E6); setSquare(weakOutpostSquareCandidates[BLACK], F6); expoFactor[0] = 1024; for (i = 1; i < NUM_EXPO_FACTORS; i++) { expoFactor[i] = (1044 * expoFactor[i - 1]) / 1024; } for (i = 0; i < NUM_EXPO_FACTORS; i++) { expoValue[i] = (100 * expoFactor[i]) / 1024 - 100; /*logDebug("ev(%d)=%d\n", i, expoValue[i]); */ } return 0; } bool flipTest(Position * position, PawnHashInfo * pawnHashtable, KingSafetyHashInfo * kingsafetyHashtable) { int v1, v2; initializePosition(position); v1 = getValue(position, VALUE_MATED, -VALUE_MATED, pawnHashtable, kingsafetyHashtable); flipPosition(position); initializePosition(position); v2 = getValue(position, VALUE_MATED, -VALUE_MATED, pawnHashtable, kingsafetyHashtable); flipPosition(position); initializePosition(position); if (v1 != v2) { const int debugFlag = debugOutput; debugOutput = TRUE; logDebug("flip test failed: v1=%d v2=%d\n", v1, v2); logPosition(position); logDebug("hash: %llu\n", position->hashValue); getValue(position, VALUE_MATED, -VALUE_MATED, pawnHashtable, kingsafetyHashtable); flipPosition(position); initializePosition(position); logPosition(position); getValue(position, VALUE_MATED, -VALUE_MATED, pawnHashtable, kingsafetyHashtable); flipPosition(position); initializePosition(position); debugOutput = debugFlag; } return (bool) (v1 == v2); } static int testPawnInfoGeneration() { Variation variation; EvaluationBase base; initializeVariation(&variation, "8/7p/5k2/5p2/p1p2P2/Pr1pPK2/1P1R3P/8 b - - 0 1"); getPawnInfo(&variation.singlePosition, &base); assert(getNumberOfSetSquares(base.pawnProtectedSquares[WHITE]) == 8); assert(testSquare(base.pawnProtectedSquares[WHITE], B4)); assert(testSquare(base.pawnProtectedSquares[WHITE], A3)); assert(testSquare(base.pawnProtectedSquares[WHITE], C3)); assert(testSquare(base.pawnProtectedSquares[WHITE], D4)); assert(testSquare(base.pawnProtectedSquares[WHITE], F4)); assert(testSquare(base.pawnProtectedSquares[WHITE], E5)); assert(testSquare(base.pawnProtectedSquares[WHITE], G5)); assert(testSquare(base.pawnProtectedSquares[WHITE], G3)); assert(getNumberOfSetSquares(base.pawnProtectedSquares[BLACK]) == 7); assert(testSquare(base.pawnProtectedSquares[BLACK], B3)); assert(testSquare(base.pawnProtectedSquares[BLACK], D3)); assert(testSquare(base.pawnProtectedSquares[BLACK], C2)); assert(testSquare(base.pawnProtectedSquares[BLACK], E2)); assert(testSquare(base.pawnProtectedSquares[BLACK], E4)); assert(testSquare(base.pawnProtectedSquares[BLACK], G4)); assert(testSquare(base.pawnProtectedSquares[BLACK], G6)); assert(getNumberOfSetSquares(base.passedPawns[WHITE]) == 0); assert(getNumberOfSetSquares(base.passedPawns[BLACK]) == 1); assert(testSquare(base.passedPawns[BLACK], D3)); assert(getNumberOfSetSquares(base.weakPawns[WHITE]) == 3); assert(testSquare(base.weakPawns[WHITE], B2)); assert(testSquare(base.weakPawns[WHITE], E3)); assert(testSquare(base.weakPawns[WHITE], H2)); assert(getNumberOfSetSquares(base.weakPawns[BLACK]) == 4); assert(testSquare(base.weakPawns[BLACK], A4)); assert(testSquare(base.weakPawns[BLACK], C4)); assert(testSquare(base.weakPawns[BLACK], F5)); assert(testSquare(base.weakPawns[BLACK], H7)); initializeVariation(&variation, "4k3/2p5/p2p4/P2P4/1PP3p1/7p/7P/4K3 w - - 0 1"); getPawnInfo(&variation.singlePosition, &base); assert(getNumberOfSetSquares(base.passedPawns[WHITE]) == 0); assert(getNumberOfSetSquares(base.passedPawns[BLACK]) == 0); assert(getNumberOfSetSquares(base.weakPawns[WHITE]) == 1); assert(testSquare(base.weakPawns[WHITE], H2)); assert(getNumberOfSetSquares(base.weakPawns[BLACK]) == 3); assert(testSquare(base.weakPawns[BLACK], A6)); assert(testSquare(base.weakPawns[BLACK], C7)); assert(testSquare(base.weakPawns[BLACK], G4)); return 0; } static int testWeakPawnDetection() { Position position; Bitboard expectedResult = EMPTY_BITBOARD; EvaluationBase base; clearPosition(&position); position.piece[E1] = WHITE_KING; position.piece[E8] = BLACK_KING; position.piece[A3] = WHITE_PAWN; position.piece[B5] = WHITE_PAWN; position.piece[B6] = WHITE_PAWN; position.piece[C4] = WHITE_PAWN; position.piece[E4] = WHITE_PAWN; position.piece[G4] = WHITE_PAWN; position.piece[H2] = WHITE_PAWN; position.piece[A4] = BLACK_PAWN; position.piece[B7] = BLACK_PAWN; setSquare(expectedResult, A3); setSquare(expectedResult, E4); initializePosition(&position); getPawnInfo(&position, &base); assert(base.weakPawns[WHITE] == expectedResult); expectedResult = EMPTY_BITBOARD; setSquare(expectedResult, B7); assert(base.weakPawns[BLACK] == expectedResult); assert(base.candidatePawns[BLACK] == EMPTY_BITBOARD); position.piece[C4] = NO_PIECE; position.piece[C5] = WHITE_PAWN; initializePosition(&position); getPawnInfo(&position, &base); expectedResult = EMPTY_BITBOARD; setSquare(expectedResult, C5); assert(base.candidatePawns[WHITE] == expectedResult); clearPosition(&position); position.piece[E1] = WHITE_KING; position.piece[E8] = BLACK_KING; position.piece[A3] = WHITE_PAWN; position.piece[B5] = WHITE_PAWN; position.piece[B6] = WHITE_PAWN; position.piece[C4] = WHITE_PAWN; position.piece[E4] = WHITE_PAWN; position.piece[G4] = WHITE_PAWN; position.piece[H2] = WHITE_PAWN; position.piece[A4] = BLACK_PAWN; position.piece[B7] = BLACK_PAWN; position.piece[D6] = BLACK_PAWN; expectedResult = EMPTY_BITBOARD; setSquare(expectedResult, A3); setSquare(expectedResult, E4); setSquare(expectedResult, C4); initializePosition(&position); getPawnInfo(&position, &base); assert(base.weakPawns[WHITE] == expectedResult); assert(base.candidatePawns[WHITE] == EMPTY_BITBOARD); expectedResult = EMPTY_BITBOARD; setSquare(expectedResult, B7); setSquare(expectedResult, D6); assert(base.weakPawns[BLACK] == expectedResult); assert(base.candidatePawns[BLACK] == EMPTY_BITBOARD); position.piece[G5] = BLACK_PAWN; expectedResult = EMPTY_BITBOARD; setSquare(expectedResult, A3); setSquare(expectedResult, E4); setSquare(expectedResult, C4); setSquare(expectedResult, H2); initializePosition(&position); getPawnInfo(&position, &base); assert(base.weakPawns[WHITE] == expectedResult); assert(base.candidatePawns[WHITE] == EMPTY_BITBOARD); expectedResult = EMPTY_BITBOARD; setSquare(expectedResult, B7); setSquare(expectedResult, D6); setSquare(expectedResult, G5); assert(base.weakPawns[BLACK] == expectedResult); assert(base.candidatePawns[BLACK] == EMPTY_BITBOARD); return 0; } static int testBaseInitialization() { Variation variation; initializeVariation(&variation, FEN_GAMESTART); assert(testSquare(passedPawnCorridor[WHITE][B4], B6)); assert(testSquare(passedPawnCorridor[BLACK][B4], B6) == FALSE); assert(testSquare(passedPawnCorridor[WHITE][C2], H7) == FALSE); assert(testSquare(passedPawnCorridor[BLACK][G6], G2)); return 0; } /* static int testFlippings() { const char fen1[] = "2rr2k1/1b3ppp/pb2p3/1p2P3/1P2BPnq/P1N3P1/1B2Q2P/R4R1K b - - 0 1"; const char fen2[] = "4k3/2p5/p2p4/P2P4/1PP3p1/7p/7P/4K3 w - - 0 1"; const char fen3[] = "8/7p/5k2/5p2/p1p2P2/Pr1pPK2/1P1R3P/8 b - - 0 1"; const char fen4[] = "6r1/Q2Pn2k/p1p1P2p/5p2/2PqR1r1/1P6/P6P/5R1K b - - 5 4"; const char fen5[] = "Q4rk1/2bb1ppp/4pn2/pQ5q/3P4/N4N2/5PPP/R1B2RK1 w - a6 0 4"; Variation variation; initializeVariation(&variation, fen1); assert(flipTest(&variation.singlePosition) != FALSE); initializeVariation(&variation, fen2); assert(flipTest(&variation.singlePosition) != FALSE); initializeVariation(&variation, fen3); assert(flipTest(&variation.singlePosition) != FALSE); initializeVariation(&variation, fen4); assert(flipTest(&variation.singlePosition) != FALSE); initializeVariation(&variation, fen5); assert(flipTest(&variation.singlePosition) != FALSE); return 0; } */ static int testWinningChancesCalculations() { Position position; clearPosition(&position); position.piece[E1] = WHITE_KING; position.piece[E8] = BLACK_KING; initializePosition(&position); assert(getWinningChances(&position, WHITE) == 0); assert(getWinningChances(&position, BLACK) == 0); position.piece[A8] = BLACK_KNIGHT; initializePosition(&position); assert(getWinningChances(&position, BLACK) == 1); position.piece[A8] = BLACK_BISHOP; initializePosition(&position); assert(getWinningChances(&position, BLACK) == 1); position.piece[A8] = BLACK_ROOK; initializePosition(&position); assert(getWinningChances(&position, BLACK) > 0); position.piece[A8] = WHITE_QUEEN; initializePosition(&position); assert(getWinningChances(&position, WHITE) > 0); position.piece[A8] = NO_PIECE; position.piece[B1] = WHITE_KNIGHT; position.piece[G1] = WHITE_KNIGHT; initializePosition(&position); assert(getWinningChances(&position, WHITE) == 1); position.piece[A7] = BLACK_PAWN; initializePosition(&position); assert(getWinningChances(&position, WHITE) > 0); position.piece[B8] = BLACK_KNIGHT; initializePosition(&position); assert(getWinningChances(&position, WHITE) <= 4); position.piece[B2] = WHITE_KNIGHT; initializePosition(&position); assert(getWinningChances(&position, WHITE) > 0); clearPosition(&position); position.piece[E1] = WHITE_KING; position.piece[E8] = BLACK_KING; position.piece[C1] = WHITE_BISHOP; position.piece[F1] = WHITE_BISHOP; initializePosition(&position); assert(getWinningChances(&position, WHITE) > 0); position.piece[F1] = NO_PIECE; position.piece[G1] = WHITE_BISHOP; initializePosition(&position); assert(getWinningChances(&position, WHITE) == 1); position.piece[A2] = WHITE_PAWN; initializePosition(&position); assert(getWinningChances(&position, WHITE) > 0); position.piece[E8] = NO_PIECE; position.piece[B8] = BLACK_KING; initializePosition(&position); assert(getWinningChances(&position, WHITE) == 1); position.piece[A2] = NO_PIECE; position.piece[H2] = WHITE_PAWN; position.piece[B8] = NO_PIECE; position.piece[H8] = BLACK_KING; initializePosition(&position); assert(getWinningChances(&position, WHITE) > 0); clearPosition(&position); position.piece[E1] = WHITE_KING; position.piece[E8] = BLACK_KING; position.piece[C7] = BLACK_BISHOP; position.piece[F7] = BLACK_BISHOP; initializePosition(&position); assert(getWinningChances(&position, BLACK) > 0); position.piece[F7] = NO_PIECE; position.piece[G7] = BLACK_BISHOP; initializePosition(&position); assert(getWinningChances(&position, BLACK) == 1); position.piece[H4] = BLACK_PAWN; initializePosition(&position); assert(getWinningChances(&position, BLACK) > 0); position.piece[E1] = NO_PIECE; position.piece[H2] = WHITE_KING; initializePosition(&position); assert(getWinningChances(&position, BLACK) == 1); position.piece[H4] = NO_PIECE; position.piece[G4] = BLACK_PAWN; initializePosition(&position); assert(getWinningChances(&position, BLACK) > 0); position.piece[G4] = NO_PIECE; position.piece[A4] = BLACK_PAWN; position.piece[H2] = NO_PIECE; position.piece[A2] = WHITE_KING; initializePosition(&position); assert(getWinningChances(&position, BLACK) > 0); clearPosition(&position); position.piece[F1] = WHITE_KING; position.piece[G7] = BLACK_KING; position.piece[H2] = WHITE_PAWN; position.piece[H3] = WHITE_PAWN; position.piece[H4] = WHITE_PAWN; position.piece[D5] = WHITE_BISHOP; initializePosition(&position); assert(getWinningChances(&position, WHITE) == 1); position.piece[D5] = NO_PIECE; position.piece[D6] = WHITE_BISHOP; initializePosition(&position); assert(getWinningChances(&position, WHITE) == 16); return 0; } int testModuleEvaluation() { int result; if ((result = testPawnInfoGeneration()) != 0) { return result; } if ((result = testWeakPawnDetection()) != 0) { return result; } if ((result = testBaseInitialization()) != 0) { return result; } /* if ((result = testFlippings()) != 0) { return result; } */ if ((result = testWinningChancesCalculations()) != 0) { return result; } return 0; }