#undef addBonus
#undef addMalus
#undef COLOR
#undef OPPCOLOR
#ifdef PERSPECTIVE_WHITE
#define COLOR WHITE
#define OPPCOLOR BLACK
#define addBonus(base, bonus) (base->balance += bonus);
#define addMalus(base, bonus) (base->balance -= bonus);
#else
#define COLOR BLACK
#define OPPCOLOR WHITE
#define addBonus(base, bonus) (base->balance -= bonus);
#define addMalus(base, bonus) (base->balance += bonus);
#endif
#ifdef PERSPECTIVE_WHITE
INLINE static void addWhitePieceAttackBonus(const Position * position,
EvaluationBase * base,
const Bitboard moves,
const Bitboard candidateTargets,
const Piece attacker)
#else
INLINE static void addBlackPieceAttackBonus(const Position * position,
EvaluationBase * base,
const Bitboard moves,
const Bitboard candidateTargets,
const Piece attacker)
#endif
{
Bitboard targets = moves & candidateTargets;
Square targetSquare;
ITERATE_BITBOARD(&targets, targetSquare)
{
const Piece target = position->piece[targetSquare];
addBonus(base, piecePieceAttackBonus[attacker][target]);
targets &= ~position->piecesOfType[target];
}
}
#ifdef PERSPECTIVE_WHITE
INLINE static void evaluateWhiteAttackers(EvaluationBase * base)
#else
INLINE static void evaluateBlackAttackers(EvaluationBase * base)
#endif
{
static const INT32 multipleAttackersBonus = V(15, 25);
if (base->numPieceAttackers[COLOR] >= 2)
{
addBonus(base, multipleAttackersBonus);
}
}
#ifdef PERSPECTIVE_WHITE
INLINE static void evaluateWhiteKnight(const Position * position,
EvaluationBase * base,
const Square square)
#else
INLINE static void evaluateBlackKnight(const Position * position,
EvaluationBase * base,
const Square square)
#endif
{
const Bitboard moves = getKnightMoves(square);
const Bitboard mobSquares = base->countedSquares[COLOR] |
getNonPawnPieces(position, OPPCOLOR);
const int mobilityCount = getNumberOfSetSquares(moves & mobSquares);
const Rank relativeRank = colorRank(COLOR, square);
#ifdef BONUS_PIECE_ATTACKS
const Bitboard ctm = position->piecesOfType[PAWN | OPPCOLOR] |
position->piecesOfType[BISHOP | OPPCOLOR];
const Bitboard cth = position->piecesOfType[ROOK | OPPCOLOR] |
position->piecesOfType[QUEEN | OPPCOLOR];
const Bitboard candidateTargets = cth |
(ctm & base->unprotectedPieces[OPPCOLOR]);
#endif
#ifdef BONUS_OUTPOST_ATTACKS
const Bitboard outpostAttacks = moves & base->weakOutpostSquares[OPPCOLOR];
#endif
base->knightAttackedSquares[COLOR] |= moves;
if (position->piecesOfType[KNIGHT | OPPCOLOR] == EMPTY_BITBOARD &&
position->piecesOfType[BISHOP | OPPCOLOR] != EMPTY_BITBOARD &&
hasAttackingBishop(position, OPPCOLOR, square) == FALSE)
{
addBonus(base, V(2, 2));
}
if (squareIsPawnSafe(base, COLOR, square) &&
relativeRank >= RANK_4 && relativeRank <= RANK_6 &&
testSquare(border, square) == FALSE)
{
addBonus(base, V(2, 3));
if (testSquare(base->pawnProtectedSquares[COLOR], square))
{
Bitboard targets = base->kingAttackSquares[OPPCOLOR] |
base->unprotectedPieces[OPPCOLOR];
addBonus(base, V(2, 3));
if ((moves & targets) != EMPTY_BITBOARD)
{
addBonus(base, V(5, 5));
if (relativeRank == RANK_5)
{
addBonus(base, V(2, 2));
}
if (file(square) == FILE_D || file(square) == FILE_E)
{
addBonus(base, V(3, 3));
}
}
}
}
#ifdef BONUS_OUTPOST_ATTACKS
if (outpostAttacks != EMPTY_BITBOARD)
{
const int count = getNumberOfSetSquares(outpostAttacks);
addBonus(base,
count * V(BONUS_OUTPOST_ATTACK_OPENING,
BONUS_OUTPOST_ATTACK_ENDGAME));
}
if (testSquare(base->weakOutpostSquares[OPPCOLOR], square))
{
addBonus(base,
V(BONUS_OUTPOST_OCCUPIED_OPENING,
BONUS_OUTPOST_OCCUPIED_ENDGAME));
}
#endif
addBonus(base, KnightMobilityBonus[mobilityCount]);
if (base->evaluateKingSafety[OPPCOLOR] &&
(moves & base->kingAttackSquares[OPPCOLOR]) != EMPTY_BITBOARD)
{
const Bitboard coronaAttacks =
moves & getKingMoves(position->king[OPPCOLOR]);
base->kingSquaresAttackCount[COLOR] +=
getNumberOfSetSquares(coronaAttacks);
base->attackInfo[COLOR] += V(KNIGHT_BONUS_ATTACK, 1);
}
#ifdef BONUS_PIECES_PROTECT_KING
if ((moves & getKingMoves(position->king[COLOR])) != EMPTY_BITBOARD)
{
static const INT32 bonus = V(4, 2);
addBonus(base, bonus);
}
#endif
#ifdef BONUS_PIECE_ATTACKS
#ifdef PERSPECTIVE_WHITE
addWhitePieceAttackBonus(position, base, moves, candidateTargets,
WHITE_KNIGHT);
#else
addBlackPieceAttackBonus(position, base, moves, candidateTargets,
BLACK_KNIGHT);
#endif
if (testSquare(base->pawnProtectedSquares[OPPCOLOR], square))
{
addBonus(base, piecePieceAttackBonus[PAWN | OPPCOLOR][KNIGHT | COLOR]);
base->numPieceAttackers[OPPCOLOR]++;
}
if ((moves & cth) != EMPTY_BITBOARD)
{
base->numPieceAttackers[COLOR]++;
}
#endif
}
#ifdef PERSPECTIVE_WHITE
INLINE static void evaluateWhiteBishop(const Position * position,
EvaluationBase * base,
const Square square)
#else
INLINE static void evaluateBlackBishop(const Position * position,
EvaluationBase * base,
const Square square)
#endif
{
const Bitboard xrayPieces = position->piecesOfType[QUEEN | COLOR];
const Bitboard moves =
getMagicBishopMoves(square, position->allPieces & ~xrayPieces);
const Bitboard mobSquares = base->countedSquares[COLOR] |
getNonPawnPieces(position, OPPCOLOR);
const int mobilityCount = getNumberOfSetSquares(moves & mobSquares);
const Rank relativeRank = colorRank(COLOR, square);
Bitboard squareColorTargets = position->piecesOfType[PAWN | OPPCOLOR] &
squaresBelow[COLOR][square] & base->unprotectedPieces[OPPCOLOR];
#ifdef BONUS_PIECE_ATTACKS
const Bitboard ctm = position->piecesOfType[PAWN | OPPCOLOR] |
position->piecesOfType[KNIGHT | OPPCOLOR];
const Bitboard cth = position->piecesOfType[ROOK | OPPCOLOR] |
position->piecesOfType[QUEEN | OPPCOLOR];
const Bitboard candidateTargets = cth |
(ctm & base->unprotectedPieces[OPPCOLOR]);
#endif
#ifdef BONUS_OUTPOST_ATTACKS
const Bitboard outpostAttacks = moves & base->weakOutpostSquares[OPPCOLOR];
#endif
#ifdef BONUS_SLIDER_ATTACKS
const Piece batteryPiece =
getDiaBatteryPiece(position, moves, square, OPPCOLOR);
#endif
#ifdef PINNED_KNIGHT_BONUS
Bitboard pinnedKnights = moves & position->piecesOfType[OPPCOLOR | KNIGHT];
#endif
if (testSquare(lightSquares, square))
{
const INT32 bonus = ((base->pawnLightSquareMalus[OPPCOLOR] / 2) -
base->pawnLightSquareMalus[COLOR]) * V(1, 1);
addBonus(base, bonus);
squareColorTargets &= lightSquares;
}
else
{
const INT32 bonus = ((base->pawnDarkSquareMalus[OPPCOLOR] / 2) -
base->pawnDarkSquareMalus[COLOR]) * V(1, 1);
addBonus(base, bonus);
squareColorTargets &= darkSquares;
}
addBonus(base, getNumberOfSetSquares(squareColorTargets) * V(0, 2));
base->bishopAttackedSquares[COLOR] |= moves;
if (squareIsPawnSafe(base, COLOR, square) &&
relativeRank >= RANK_4 && relativeRank <= RANK_6 &&
testSquare(border, square) == FALSE &&
testSquare(base->pawnProtectedSquares[COLOR], square))
{
Bitboard targets = base->kingAttackSquares[OPPCOLOR] |
base->unprotectedPieces[OPPCOLOR];
addBonus(base, V(1, 2));
if ((moves & targets) != EMPTY_BITBOARD)
{
addBonus(base, V(3, 4));
}
}
#ifdef BONUS_OUTPOST_ATTACKS
if (outpostAttacks != EMPTY_BITBOARD)
{
const int count = getNumberOfSetSquares(outpostAttacks);
addBonus(base,
count * V(BONUS_OUTPOST_ATTACK_OPENING,
BONUS_OUTPOST_ATTACK_ENDGAME));
}
if (testSquare(base->weakOutpostSquares[OPPCOLOR], square))
{
addBonus(base,
V(BONUS_OUTPOST_OCCUPIED_OPENING,
BONUS_OUTPOST_OCCUPIED_ENDGAME));
}
#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))
{
addBonus(base, V(4, 2));
}
}
}
#endif
#ifdef BONUS_PIECE_ATTACKS
#ifdef PERSPECTIVE_WHITE
addWhitePieceAttackBonus(position, base, moves, candidateTargets,
WHITE_BISHOP);
#else
addBlackPieceAttackBonus(position, base, moves, candidateTargets,
BLACK_BISHOP);
#endif
if (testSquare(base->pawnProtectedSquares[OPPCOLOR], square))
{
addBonus(base, piecePieceAttackBonus[PAWN | OPPCOLOR][BISHOP | COLOR]);
base->numPieceAttackers[OPPCOLOR]++;
}
if ((moves & cth) != EMPTY_BITBOARD)
{
base->numPieceAttackers[COLOR]++;
}
#endif
addBonus(base, BishopMobilityBonus[mobilityCount]);
if (base->evaluateKingSafety[OPPCOLOR] &&
(moves & base->kingAttackSquares[OPPCOLOR]) != EMPTY_BITBOARD)
{
const Bitboard coronaAttacks =
moves & getKingMoves(position->king[OPPCOLOR]);
base->kingSquaresAttackCount[COLOR] +=
getNumberOfSetSquares(coronaAttacks);
base->attackInfo[COLOR] += V(BISHOP_BONUS_ATTACK, 1);
}
#ifdef BONUS_PIECES_PROTECT_KING
if ((moves & getKingMoves(position->king[COLOR])) != EMPTY_BITBOARD)
{
static const INT32 bonus = V(2, 1);
addBonus(base, bonus);
}
#endif
#ifdef BONUS_SLIDER_ATTACKS
if (batteryPiece != NO_PIECE)
{
addBonus(base, sliderAttackPoints[BISHOP | COLOR][batteryPiece]);
if (pieceColor(batteryPiece) == COLOR &&
pieceType(batteryPiece) != PAWN)
{
base->batteryAttackers[COLOR] |= minValue[square];
}
}
#endif
#ifdef MALUS_BISHOP_BORDER
if (relativeRank >= RANK_5 && testSquare(border, square))
{
const Bitboard safeSquares =
squaresOfFileRange[FILE_C][FILE_F] &
~(position->piecesOfColor[COLOR] |
base->pawnProtectedSquares[OPPCOLOR]);
if ((moves & safeSquares) == EMPTY_BITBOARD)
{
addMalus(base, V(BISHOP_MALUS_BLOCKED, BISHOP_MALUS_BLOCKED));
}
}
#endif
}
#ifdef PERSPECTIVE_WHITE
INLINE static void evaluateWhiteRook(const Position * position,
EvaluationBase * base,
const Square square)
#else
INLINE static void evaluateBlackRook(const Position * position,
EvaluationBase * base,
const Square square)
#endif
{
const Piece piece = position->piece[square];
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 Bitboard mobSquares = base->countedSquares[COLOR];
const int mobilityCount = getNumberOfSetSquares(xrayMoves & mobSquares);
const Bitboard fileSquares = squaresOfFile[file(square)];
const Bitboard ownPawns = position->piecesOfType[PAWN | COLOR];
const Rank relativeRank = colorRank(COLOR, square);
#ifdef BONUS_HALF_OPEN_FILE_ROOK
const Bitboard frontSquares = fileSquares & squaresAbove[COLOR][square];
#endif
#ifdef BONUS_PIECE_ATTACKS
const Bitboard ctm = position->piecesOfType[PAWN | OPPCOLOR] |
position->piecesOfType[KNIGHT | OPPCOLOR] |
position->piecesOfType[BISHOP | OPPCOLOR];
const Bitboard cth = position->piecesOfType[QUEEN | OPPCOLOR];
const Bitboard candidateTargets = cth |
(ctm & base->unprotectedPieces[OPPCOLOR]);
#endif
#ifdef BONUS_OUTPOST_ATTACKS
const Bitboard outpostAttacks = moves & base->weakOutpostSquares[OPPCOLOR];
#endif
#ifdef BONUS_SLIDER_ATTACKS
const Piece batteryPiece =
getOrthoBatteryPiece(position, moves, square, OPPCOLOR);
#endif
base->rookAttackedSquares[COLOR] |= moves;
if (squareIsPawnSafe(base, COLOR, square) &&
relativeRank >= RANK_4 && relativeRank <= RANK_6 &&
testSquare(border, square) == FALSE &&
testSquare(base->pawnProtectedSquares[COLOR], square))
{
Bitboard targets = base->kingAttackSquares[OPPCOLOR] |
(squaresOfRank[rank(square)] & base->unprotectedPieces[OPPCOLOR]);
addBonus(base, V(1, 2));
if ((moves & targets) != EMPTY_BITBOARD)
{
addBonus(base, V(3, 4));
}
}
#ifdef BONUS_OUTPOST_ATTACKS
if (outpostAttacks != EMPTY_BITBOARD)
{
const int count = getNumberOfSetSquares(outpostAttacks);
addBonus(base,
count * V(BONUS_OUTPOST_ATTACK_OPENING,
BONUS_OUTPOST_ATTACK_ENDGAME));
}
if (testSquare(base->weakOutpostSquares[OPPCOLOR], square))
{
addBonus(base,
V(BONUS_OUTPOST_OCCUPIED_OPENING,
BONUS_OUTPOST_OCCUPIED_ENDGAME));
}
#endif
#ifdef BONUS_PIECE_ATTACKS
#ifdef PERSPECTIVE_WHITE
addWhitePieceAttackBonus(position, base, moves, candidateTargets,
WHITE_ROOK);
#else
addBlackPieceAttackBonus(position, base, moves, candidateTargets,
BLACK_ROOK);
#endif
if (testSquare(base->pawnProtectedSquares[OPPCOLOR], square))
{
addBonus(base, piecePieceAttackBonus[PAWN | OPPCOLOR][ROOK | COLOR]);
base->numPieceAttackers[OPPCOLOR]++;
}
if ((moves & cth) != EMPTY_BITBOARD)
{
base->numPieceAttackers[COLOR]++;
}
#endif
addBonus(base, RookMobilityBonus[mobilityCount]);
#ifdef BONUS_HALF_OPEN_FILE_ROOK
/* Add a bonus if this rook is located on an open file. */
if ((ownPawns & frontSquares) == EMPTY_BITBOARD)
{
Bitboard oppPawns =
position->piecesOfType[PAWN | OPPCOLOR] & frontSquares;
const int fileDiff = abs(file(square) - file(position->king[OPPCOLOR]));
addBonus(base, V(3, 6));
if (oppPawns == EMPTY_BITBOARD)
{
Bitboard protectedMinors = frontSquares &
base->pawnProtectedSquares[OPPCOLOR] &
(position->piecesOfType[OPPCOLOR | KNIGHT] |
position->piecesOfType[OPPCOLOR | BISHOP]);
if (protectedMinors != EMPTY_BITBOARD)
{
#ifdef PERSPECTIVE_WHITE
const Square minorSquare = getFirstSquare(&protectedMinors);
#else
const Square minorSquare = getLastSquare(&protectedMinors);
#endif
const Bitboard attackers = position->piecesOfType[PAWN | COLOR] &
candidateDefenders[OPPCOLOR][minorSquare];
if (attackers != EMPTY_BITBOARD)
{
addBonus(base, V(15, 5));
}
else
{
addBonus(base, V(10, 0));
}
}
else
{
addBonus(base, V(20, 10));
}
}
else
{
#ifdef PERSPECTIVE_WHITE
const Square pawnSquare = getFirstSquare(&oppPawns);
#else
const Square pawnSquare = getLastSquare(&oppPawns);
#endif
const Bitboard defenders = position->piecesOfType[PAWN | OPPCOLOR] &
candidateDefenders[COLOR][pawnSquare];
if (defenders == EMPTY_BITBOARD)
{
addBonus(base, V(5, 5));
}
}
if (fileDiff == 0 && base->evaluateKingSafety[OPPCOLOR])
{
addBonus(base, V(ROOK_BONUS_KING_FILE, 0));
}
if (fileDiff == 1 && base->evaluateKingSafety[OPPCOLOR])
{
addBonus(base, V(ROOK_BONUS_LATERAL_KING_FILE, 0));
}
}
#else
/* Add a bonus if this rook is located on an open file. */
if ((ownPawns & fileSquares) == EMPTY_BITBOARD)
{
const Bitboard oppPawns = position->piecesOfType[PAWN | OPPCOLOR];
const Bitboard frontSquares = fileSquares & squaresAbove[COLOR][square];
Bitboard protectedBlockers = frontSquares &
base->pawnProtectedSquares[OPPCOLOR] &
(oppPawns | position->piecesOfType[OPPCOLOR | KNIGHT] |
position->piecesOfType[OPPCOLOR | BISHOP]);
#ifdef EXTRA_BONUS_KING_FILE_ATTACKS
const int fileDiff = abs(file(square) - file(position->king[OPPCOLOR]));
#endif
if (protectedBlockers == EMPTY_BITBOARD)
{
if ((frontSquares & oppPawns) == EMPTY_BITBOARD)
{
addBonus(base, V(20, 20));
}
else
{
addBonus(base, V(10, 10));
}
}
else
{
if ((protectedBlockers & oppPawns) != EMPTY_BITBOARD)
{
addBonus(base, V(8, 0));
}
else
{
#ifdef PERSPECTIVE_WHITE
const Square minorSquare = getFirstSquare(&protectedBlockers);
#else
const Square minorSquare = getLastSquare(&protectedBlockers);
#endif
if (squareIsPawnSafe(base, OPPCOLOR, minorSquare))
{
addBonus(base, V(10, 0));
}
else
{
addBonus(base, V(15, 5));
}
}
}
#ifdef EXTRA_BONUS_KING_FILE_ATTACKS
if (fileDiff == 0 && base->evaluateKingSafety[OPPCOLOR])
{
addBonus(base, V(ROOK_BONUS_KING_FILE, 0));
}
if (fileDiff == 1 && base->evaluateKingSafety[OPPCOLOR])
{
addBonus(base, V(ROOK_BONUS_LATERAL_KING_FILE, 0));
}
#endif
}
#endif
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);
addBonus(base, V(-malus, -malus));
}
}
#ifdef BONUS_ROOK_6TH_RANK
if (colorRank(COLOR, square) == RANK_6)
{
const Bitboard targets = minValue[position->king[OPPCOLOR]] |
position->piecesOfType[PAWN | OPPCOLOR];
#ifdef PERSPECTIVE_WHITE
const Bitboard realm =
squaresOfRank[RANK_6] | squaresOfRank[RANK_7] |
squaresOfRank[RANK_8];
#else
const Bitboard realm =
squaresOfRank[RANK_3] | squaresOfRank[RANK_2] |
squaresOfRank[RANK_1];
#endif
if ((realm & targets) != EMPTY_BITBOARD)
{
addBonus(base, V(5, 15));
}
}
else
#endif
if (grantSeventhRankBonus(position, COLOR, OPPCOLOR, square))
{
addBonus(base, V(10, 30));
if (colorRank(COLOR, position->king[OPPCOLOR]) == RANK_8)
{
Bitboard companions = position->piecesOfType[ROOK | COLOR] |
position->piecesOfType[QUEEN | COLOR];
if ((moves & companions & squaresOfRank[rank(square)]) !=
EMPTY_BITBOARD)
{
addBonus(base, V(10, 20));
}
}
}
#ifdef BONUS_ROOK_8TH_RANK
else if (colorRank(COLOR, square) == RANK_8 &&
colorRank(COLOR, position->king[OPPCOLOR]) == RANK_8)
{
addBonus(base, V(5, 10));
}
#endif
if (base->evaluateKingSafety[OPPCOLOR] &&
(xrayMoves & base->kingAttackSquares[OPPCOLOR]) != EMPTY_BITBOARD)
{
const Bitboard coronaAttacks =
xrayMoves & getKingMoves(position->king[OPPCOLOR]);
base->kingSquaresAttackCount[COLOR] +=
getNumberOfSetSquares(coronaAttacks);
base->attackInfo[COLOR] += V(ROOK_BONUS_ATTACK, 1);
}
#ifdef BONUS_PIECES_PROTECT_KING
if ((moves & getKingMoves(position->king[COLOR])) != EMPTY_BITBOARD)
{
static const INT32 bonus = V(3, 1);
addBonus(base, bonus);
}
#endif
#ifdef BONUS_SLIDER_ATTACKS
if (batteryPiece != NO_PIECE)
{
addBonus(base, sliderAttackPoints[ROOK | COLOR][batteryPiece]);
if (pieceColor(batteryPiece) == COLOR &&
pieceType(batteryPiece) != PAWN)
{
base->batteryAttackers[COLOR] |= minValue[square];
}
}
#endif
#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)
{
addBonus(base, V(0, -ROOK_MALUS_BLOCKING_PASSER));
}
#endif
#ifdef BONUS_SPACE_ATTACKS
if (testSquare(attackingRealm[COLOR], square))
{
base->spaceAttackPoints[COLOR]++;
}
#endif
}
#ifdef PERSPECTIVE_WHITE
INLINE static void evaluateWhiteQueen(const Position * position,
EvaluationBase * base,
const Square square)
#else
INLINE static void evaluateBlackQueen(const Position * position,
EvaluationBase * base,
const Square square)
#endif
{
const Bitboard moves = getMagicQueenMoves(square, position->allPieces);
const int mobilityCount =
getNumberOfSetSquares(moves & base->countedSquares[COLOR]);
#ifdef BONUS_PIECE_ATTACKS
const Bitboard candidateTargets = base->unprotectedPieces[OPPCOLOR];
#endif
#ifdef BONUS_OUTPOST_ATTACKS
const Bitboard outpostAttacks = moves & base->weakOutpostSquares[OPPCOLOR];
#endif
#ifdef BONUS_SLIDER_ATTACKS
const Piece orthoBatteryPiece =
getOrthoBatteryPiece(position, moves, square, OPPCOLOR);
const Piece diaBatteryPiece =
getDiaBatteryPiece(position, moves, square, OPPCOLOR);
#endif
base->queenAttackedSquares[COLOR] |= moves;
#ifdef BONUS_OUTPOST_ATTACKS
if (outpostAttacks != EMPTY_BITBOARD)
{
const int count = getNumberOfSetSquares(outpostAttacks);
addBonus(base,
count * V(BONUS_OUTPOST_ATTACK_OPENING,
BONUS_OUTPOST_ATTACK_ENDGAME - 1));
}
#endif
addBonus(base, QueenMobilityBonus[mobilityCount]);
if (grantSeventhRankBonus(position, COLOR, OPPCOLOR, square))
{
addBonus(base, V(5, 25));
if (colorRank(COLOR, position->king[OPPCOLOR]) == RANK_8)
{
if ((moves & position->piecesOfType[ROOK | COLOR] &
squaresOfRank[rank(square)]) != EMPTY_BITBOARD)
{
addBonus(base, V(10, 15));
}
}
}
if (base->evaluateKingSafety[OPPCOLOR])
{
#ifdef EXTRA_BONUS_KING_FILE_ATTACKS
const Bitboard fileSquares = squaresOfFile[file(square)];
const Bitboard ownPawns = position->piecesOfType[PAWN | COLOR];
/* Add a bonus if this queen is located on an open file near the opponent's king. */
if ((ownPawns & fileSquares) == EMPTY_BITBOARD &&
(position->piecesOfType[ROOK | COLOR] & fileSquares) !=
EMPTY_BITBOARD)
{
const int fileDiff =
abs(file(square) - file(position->king[OPPCOLOR]));
if (fileDiff == 0)
{
addBonus(base, V(ROOK_BONUS_KING_FILE, 0));
}
if (fileDiff == 1)
{
addBonus(base, V(ROOK_BONUS_LATERAL_KING_FILE, 0));
}
}
#endif
if ((moves & base->kingAttackSquares[OPPCOLOR]) != EMPTY_BITBOARD)
{
const Bitboard coronaAttacks =
moves & getKingMoves(position->king[OPPCOLOR]);
base->kingSquaresAttackCount[COLOR] +=
getNumberOfSetSquares(coronaAttacks);
base->attackInfo[COLOR] += V(QUEEN_BONUS_ATTACK, 1);
}
}
#ifdef BONUS_PIECES_PROTECT_KING
if ((moves & getKingMoves(position->king[COLOR])) != EMPTY_BITBOARD)
{
static const INT32 bonus = V(5, 2);
addBonus(base, bonus);
}
#endif
#ifdef BONUS_SLIDER_ATTACKS
if (orthoBatteryPiece != NO_PIECE &&
(orthoBatteryPiece & PP_ORTHOPIECE) == 0 &&
pieceType(orthoBatteryPiece) != PAWN)
{
addBonus(base, sliderAttackPoints[QUEEN | COLOR][orthoBatteryPiece]);
if (pieceColor(orthoBatteryPiece) == COLOR)
{
base->batteryAttackers[COLOR] |= minValue[square];
}
}
if (diaBatteryPiece != NO_PIECE && (diaBatteryPiece & PP_DIAPIECE) == 0)
{
addBonus(base, sliderAttackPoints[QUEEN | COLOR][diaBatteryPiece]);
if (pieceColor(diaBatteryPiece) == COLOR &&
pieceType(diaBatteryPiece) != PAWN)
{
base->batteryAttackers[COLOR] |= minValue[square];
}
}
#endif
#ifdef BONUS_SPACE_ATTACKS
if (testSquare(attackingRealm[COLOR], square))
{
base->spaceAttackPoints[COLOR] += 2;
}
#endif
#ifdef BONUS_PIECE_ATTACKS
#ifdef PERSPECTIVE_WHITE
addWhitePieceAttackBonus(position, base, moves, candidateTargets,
WHITE_QUEEN);
#else
addBlackPieceAttackBonus(position, base, moves, candidateTargets,
BLACK_QUEEN);
#endif
if (testSquare(base->pawnProtectedSquares[OPPCOLOR], square))
{
addBonus(base, piecePieceAttackBonus[PAWN | OPPCOLOR][QUEEN | COLOR]);
base->numPieceAttackers[OPPCOLOR]++;
}
#endif
}
#ifdef PERSPECTIVE_WHITE
INLINE static void evaluateWhitePasser(const Position * position,
EvaluationBase * base,
const Square square)
#else
INLINE static void evaluateBlackPasser(const Position * position,
EvaluationBase * base,
const Square square)
#endif
{
const Piece currentPiece = position->piece[square];
const Rank pawnRank = colorRank(COLOR, square);
const int pawnDirection = (COLOR == WHITE ? 8 : -8);
const Square stopSquare = (Square) (square + pawnDirection);
const int numDefenders = position->numberOfPieces[OPPCOLOR] -
position->numberOfPawns[OPPCOLOR];
bool unStoppable = FALSE;
const int rank = pawnRank - RANK_2;
const int rankFactor = rank * (rank - 1);
const int openingBonus = 20 * rankFactor;
int endgameBonus = 10 + rank * rank * 10;
const int pieceWeight = getPieceWeight(position, OPPCOLOR);
const int opWeight = 100 - 2 * pieceWeight;
const int egWeight = 160 - 2 * pieceWeight;
int opValue, egValue;
#ifdef BONUS_OUTSIDE_PASSER
const Bitboard attPawns = position->piecesOfType[currentPiece];
const Bitboard oppPawns = position->piecesOfType[PAWN | OPPCOLOR];
const bool outsideLeft = (bool)
((squaresLeftOf[square] & oppPawns) == EMPTY_BITBOARD &&
(squaresRightOf[square] & attPawns) != EMPTY_BITBOARD);
const bool outsideRight = (bool)
((squaresRightOf[square] & oppPawns) == EMPTY_BITBOARD &&
(squaresLeftOf[square] & attPawns) != EMPTY_BITBOARD);
#endif
if (numDefenders == 1)
{
const int egBonus = quad(0, PASSED_PAWN_BONUS_UNSTOPPABLE, pawnRank);
const int kingDistance = distance(square, position->king[COLOR]);
const Square rectangleSquare =
(COLOR == position->activeColor ?
square : (Square) (square - pawnDirection));
const bool kingInRectangle =
testSquare(passedPawnRectangle[COLOR][rectangleSquare],
position->king[OPPCOLOR]);
if ((kingInRectangle == FALSE &&
(passedPawnCorridor[COLOR][square] &
position->piecesOfColor[COLOR]) == EMPTY_BITBOARD))
{
addBonus(base, V(0, egBonus));
unStoppable = TRUE;
}
else if (kingDistance == 1)
{
const File pawnFile = file(square);
const File kingFile = file(position->king[COLOR]);
const Square promotionSquare =
(COLOR == 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[COLOR]) <= 1)
{
addBonus(base, V(0, egBonus));
unStoppable = TRUE;
}
}
#ifdef BONUS_WINNING_PASSER
if (unStoppable == FALSE &&
base->hasPassersOrCandidates[OPPCOLOR] == FALSE &&
passerWalks(position, square, COLOR))
{
addBonus(base, V(0, egBonus));
unStoppable = TRUE;
}
#endif
}
if (rankFactor > 0 && unStoppable == FALSE)
{
const Square attKing = position->king[COLOR];
const Square defKing = position->king[OPPCOLOR];
const int attackerDistance = distance(attKing, stopSquare);
const int defenderDistance = distance(defKing, stopSquare);
endgameBonus -= 4 * rankFactor * attackerDistance;
endgameBonus += 6 * rankFactor * defenderDistance;
if (position->piece[stopSquare] == NO_PIECE)
{
const Bitboard ownAttacks = base->attackedSquares[COLOR] |
getKingMoves(attKing);
const Bitboard oppAttacks = base->attackedSquares[OPPCOLOR] |
getKingMoves(defKing);
const Bitboard path = passedPawnCorridor[COLOR][square];
const Bitboard ownBlockers = path & position->piecesOfColor[COLOR];
const Bitboard oppBlockers =
path & position->piecesOfColor[OPPCOLOR];
Bitboard obstacles = path & oppAttacks;
if (testSquare(base->attackedSquares[OPPCOLOR], square))
{
const Bitboard candidates =
(position->piecesOfType[ROOK | OPPCOLOR] |
position->piecesOfType[QUEEN | OPPCOLOR]) &
passedPawnCorridor[OPPCOLOR][square] &
getMagicRookMoves(square, position->allPieces);
if (candidates != EMPTY_BITBOARD)
{
obstacles = path;
}
}
obstacles |= oppBlockers;
if (obstacles == EMPTY_BITBOARD)
{
const int bonus = (ownAttacks == path ? 16 : 14);
endgameBonus += rankFactor * bonus;
}
else
{
int bonus =
((obstacles & ~ownAttacks) == EMPTY_BITBOARD ? 12 : 8);
endgameBonus += rankFactor * bonus;
}
if (ownBlockers == EMPTY_BITBOARD)
{
endgameBonus += rankFactor;
}
}
}
if ((position->piecesOfType[currentPiece] & lateralSquares[square]) !=
EMPTY_BITBOARD)
{
endgameBonus += 20 * rank;
}
else if (testSquare(base->pawnProtectedSquares[COLOR], square))
{
endgameBonus += 12 * rank;
}
if (file(square) == FILE_A || file(square) == FILE_H)
{
if (numberOfNonPawnPieces(position, OPPCOLOR) == 2 &&
getPieceCount(position, (Piece) (KNIGHT | OPPCOLOR)) == 1)
{
endgameBonus += endgameBonus / 4;
}
else if (hasOrthoPieces(position, OPPCOLOR))
{
endgameBonus -= endgameBonus / 4;
}
}
#ifdef BONUS_OUTSIDE_PASSER
if (outsideLeft || outsideRight)
{
const int div[8] = { 5, 6, 7, 8, 8, 7, 6, 5 };
endgameBonus += endgameBonus / div[file(square)];
}
#endif
opValue = (openingBonus * opWeight) / 256;
egValue = (endgameBonus * egWeight) / 256;
#ifdef INCLUDE_PASSERS_IN_FUTILITY_MARGIN
base->futilityMargin[OPPCOLOR] =
max(base->futilityMargin[OPPCOLOR], max(opValue, egValue));
#endif
addBonus(base, V(opValue, egValue));
}
#ifdef BONUS_PINS
#ifdef PERSPECTIVE_WHITE
INLINE static void evaluateWhitePins(const Position * position,
EvaluationBase * base)
#else
INLINE static void evaluateBlackPins(const Position * position,
EvaluationBase * base)
#endif
{
const Bitboard pinnedPieces = position->piecesOfColor[COLOR] &
base->attackedSquares[OPPCOLOR] & ~position->piecesOfType[PAWN | COLOR];
const Bitboard unprotectedPieces = ~base->attackedSquares[COLOR] &
(position->piecesOfType[KNIGHT | COLOR] |
position->piecesOfType[BISHOP | COLOR]);
const Bitboard standardTargets =
position->piecesOfType[QUEEN | COLOR] |
position->piecesOfType[ROOK | COLOR];
Bitboard allTargets = unprotectedPieces | standardTargets;
Square targetSquare;
ITERATE_BITBOARD(&allTargets, targetSquare)
{
Bitboard orthoPins = pinnedPieces &
~position->piecesOfType[ROOK | COLOR] &
getMagicRookMoves(targetSquare, position->allPieces);
Bitboard diaPins = pinnedPieces &
~position->piecesOfType[BISHOP | COLOR] &
getMagicBishopMoves(targetSquare, position->allPieces);
const bool targetUnprotected = (bool)
(FALSE == testSquare(base->attackedSquares[COLOR], targetSquare));
Square pinnedPieceSquare;
ITERATE_BITBOARD(&orthoPins, pinnedPieceSquare)
{
const bool pinnedPiecePawnProtected =
testSquare(base->pawnProtectedSquares[COLOR], pinnedPieceSquare);
Piece pinningPiece = getPinningOrthoPiece
(position, OPPCOLOR, pinnedPieceSquare, targetSquare,
targetUnprotected, pinnedPiecePawnProtected);
if (pinningPiece != NO_PIECE)
{
const Piece pinnedPiece = position->piece[pinnedPieceSquare];
addMalus(base, sliderAttackPoints[pinningPiece][pinnedPiece]);
/*dumpSquare(targetSquare);
dumpSquare(pinnedPieceSquare);
dumpPosition(position); */
}
}
ITERATE_BITBOARD(&diaPins, pinnedPieceSquare)
{
const bool pinnedPiecePawnProtected =
testSquare(base->pawnProtectedSquares[COLOR], pinnedPieceSquare);
Piece pinningPiece = getPinningDiaPiece
(position, OPPCOLOR, pinnedPieceSquare, targetSquare,
targetUnprotected, pinnedPiecePawnProtected);
if (pinningPiece != NO_PIECE)
{
const Piece pinnedPiece = position->piece[pinnedPieceSquare];
addMalus(base, sliderAttackPoints[pinningPiece][pinnedPiece]);
/*dumpSquare(targetSquare);
dumpSquare(pinnedPieceSquare);
dumpPosition(position); */
}
}
}
}
#endif
#ifdef PERSPECTIVE_WHITE
INLINE static int getPawnSafetyMalusOfWhiteKingFile(const Position * position,
const int file,
const Square kingSquare,
const int fileType)
#else
INLINE static int getPawnSafetyMalusOfBlackKingFile(const Position * position,
const int file,
const Square kingSquare,
const int fileType)
#endif
{
const Square baseSquare = getSquare(file, rank(kingSquare));
const Bitboard pawnRealm = squaresOfRank[rank(kingSquare)] |
squaresAbove[COLOR][kingSquare];
const Bitboard fileRealm = squaresOfFile[file] & pawnRealm;
const Bitboard diagRealm = pawnRealm &
generalMoves[WHITE_BISHOP][baseSquare] &
(file(kingSquare) <= FILE_D ?
squaresRightOf[baseSquare] : squaresLeftOf[baseSquare]);
Bitboard fileDefenders = fileRealm & position->piecesOfType[PAWN | COLOR];
Bitboard diagDefenders = diagRealm & position->piecesOfType[PAWN | COLOR];
Bitboard attackers = fileRealm & position->piecesOfType[PAWN | OPPCOLOR];
int fdi = 0, fai = 0, fad = 1;
int diaMalus = 0;
#ifdef PERSPECTIVE_WHITE
const Square fileDefenderSquare = getFirstSquare(&fileDefenders);
const Square fileAttackerSquare = getFirstSquare(&attackers);
#else
const Square fileDefenderSquare = getLastSquare(&fileDefenders);
const Square fileAttackerSquare = getLastSquare(&attackers);
#endif
if (fileType == 1)
{
#ifdef PERSPECTIVE_WHITE
const Square diagDefenderSquare = getFirstSquare(&diagDefenders);
#else
const Square diagDefenderSquare = getLastSquare(&diagDefenders);
#endif
const File dfi = (File) (file <= FILE_D ? file : FILE_H - file);
int ddi = 0;
if (diagDefenderSquare != NO_SQUARE)
{
ddi = colorRank(COLOR, diagDefenderSquare);
}
assert(dfi >= FILE_A);
assert(dfi <= FILE_D);
assert(ddi >= RANK_1);
assert(ddi <= RANK_8);
diaMalus = KINGSAFETY_PAWN_BONUS_DEFENDER_DIAG[dfi][ddi];
}
/*if (fileDefenderSquare != NO_SQUARE &&
fileAttackerSquare != NO_SQUARE && diagDefenderSquare != NO_SQUARE)
{
dumpSquare(baseSquare);
dumpSquare(fileDefenderSquare);
dumpSquare(fileAttackerSquare);
dumpSquare(diagDefenderSquare);
dumpBitboard(fileRealm & position->piecesOfType[PAWN | COLOR],
"fileRealm & position->piecesOfType[PAWN | COLOR]");
dumpBitboard(fileRealm & position->piecesOfType[PAWN | OPPCOLOR],
"fileRealm & position->piecesOfType[PAWN | OPPCOLOR]");
dumpBitboard(pawnRealm, "pawnRealm");
dumpBitboard(fileRealm, "fileRealm");
dumpBitboard(diagRealm, "diagRealm");
dumpPosition(position);
} */
if (fileDefenderSquare != NO_SQUARE)
{
fdi = colorRank(COLOR, fileDefenderSquare);
}
if (fileAttackerSquare != NO_SQUARE)
{
fai = colorRank(COLOR, fileAttackerSquare);
if (fai == fdi + 1 &&
(fai > RANK_3 || colorRank(COLOR, kingSquare) > RANK_1))
{
fad = 2;
}
}
assert(fileType >= 0);
assert(fileType <= 2);
assert(fdi >= RANK_1);
assert(fdi <= RANK_8);
assert(fai >= RANK_1);
assert(fai <= RANK_8);
return KINGSAFETY_PAWN_MALUS_DEFENDER[fileType][fdi] +
KINGSAFETY_PAWN_BONUS_ATTACKER[fileType][fai] / fad + diaMalus;
}
#ifdef MALUS_KING_TRAPPED
#ifdef PERSPECTIVE_WHITE
INLINE static bool whiteKingIsTrapped(const Position * position,
EvaluationBase * base)
#else
INLINE static bool blackKingIsTrapped(const Position * position,
EvaluationBase * base)
#endif
{
const Square kingSquare = position->king[COLOR];
if (colorRank(COLOR, kingSquare) == RANK_1)
{
const Bitboard corona = getKingMoves(kingSquare);
const Bitboard ownPawns = position->piecesOfType[PAWN | COLOR];
#ifdef PERSPECTIVE_WHITE
const Bitboard secondRank = squaresOfRank[RANK_2];
const Bitboard blockedObstacles =
(ownPawns | position->piecesOfColor[OPPCOLOR]) >> 8;
#else
const Bitboard secondRank = squaresOfRank[RANK_7];
const Bitboard blockedObstacles =
(ownPawns | position->piecesOfColor[OPPCOLOR]) << 8;
#endif
const Bitboard obstacles = blockedObstacles & ownPawns;
const Bitboard escapeSquares = secondRank & corona;
const Bitboard unavailableSquares =
base->attackedSquares[OPPCOLOR] | obstacles;
if ((escapeSquares & ~unavailableSquares) == EMPTY_BITBOARD)
{
return TRUE;
}
}
return FALSE;
}
#endif
#ifdef PERSPECTIVE_WHITE
INLINE static void evaluateWhitePawns(EvaluationBase * base)
#else
INLINE static void evaluateBlackPawns(EvaluationBase * base)
#endif
{
const static INT32 chainBonusPerFile[8] = {
V(4, 0), V(5, 0), V(5, 0), V(6, 0),
V(6, 0), V(5, 0), V(5, 0), V(4, 0)
};
#ifdef REDUCED_PAWN_EVAL
const static INT32 doubledMalusPerFile[8] = {
V(5, 13), V(7, 15), V(8, 15), V(8, 15),
V(8, 15), V(8, 15), V(7, 15), V(5, 13)
};
#else
const static INT32 doubledMalusPerFile[8] = {
V(5, 17), V(8, 19), V(9, 19), V(9, 19),
V(9, 19), V(9, 19), V(8, 19), V(5, 17)
};
#endif
Bitboard chainPawns = base->chainPawns[COLOR];
Bitboard doubledPawns = base->doubledPawns[COLOR];
Square square;
ITERATE_BITBOARD(&chainPawns, square)
{
addBonus(base, chainBonusPerFile[file(square)]);
}
ITERATE_BITBOARD(&doubledPawns, square)
{
addMalus(base, doubledMalusPerFile[file(square)]);
}
}