#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);

#ifdef MOBILITY_TABLES
#ifdef  TEST_SETUP
   const Bitboard mobSquares = base->countedSquares[COLOR] |
      getNonPawnPieces(position, OPPCOLOR);
#else
   const Bitboard mobSquares = base->countedSquares[COLOR];
#endif
#else
   const Bitboard mobSquares = (squaresAbove[COLOR][square] &
                                base->countedSquares[COLOR]) |
      getNonPawnPieces(position, OPPCOLOR);
#endif

   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(2, 2));
   }

   if (testSquare(base->weakOutpostSquares[OPPCOLOR], square))
   {
      addBonus(base, V(2, 2));
   }
#endif

#ifdef MOBILITY_TABLES
   addBonus(base, KnightMobilityBonus[mobilityCount]);
#else
   addBonus(base, mobilityCount * V(6, 8));
#endif

   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 KNIGHT_VS_PASSED_WING_PAWNS
   if (base->passedPawns[OPPCOLOR] != EMPTY_BITBOARD)
   {
      const static int malus[8] = { 12, 8, 5, 3, 3, 5, 8, 12 };
      Bitboard passers = base->passedPawns[OPPCOLOR];
      Square pawnSquare;

      ITERATE_BITBOARD(&passers, pawnSquare)
      {
         const int egMalus = malus[file(pawnSquare)] + 2 *
            pawnDefenderDistance(position->king[COLOR], COLOR, pawnSquare);

         addMalus(base, V(0, egMalus));
      }
   }
#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 static INT32 BISHOP_MALUS_BLOCKER[3] =
      { V(0, 0), V(-3, -3), V(-8, -8) };
   const Bitboard xrayPieces = position->piecesOfType[QUEEN | COLOR];
   const Bitboard moves =
      getMagicBishopMoves(square, position->allPieces & ~xrayPieces);

#ifdef MOBILITY_TABLES
#ifdef  TEST_SETUP
   const Bitboard mobSquares = base->countedSquares[COLOR] |
      getNonPawnPieces(position, OPPCOLOR);
#else
   const Bitboard mobSquares = base->countedSquares[COLOR];
#endif
#else
   const Bitboard mobSquares = (squaresAbove[COLOR][square] &
                                base->countedSquares[COLOR]) |
      getNonPawnPieces(position, OPPCOLOR);
#endif

   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

#ifdef BISHOP_BLOCKERS
   const Bitboard blockers = squaresAbove[COLOR][square] & moves &
      (position->piecesOfType[PAWN | COLOR] |
       (position->piecesOfType[PAWN | OPPCOLOR] &
        base->pawnProtectedSquares[OPPCOLOR]));

   if (blockers != EMPTY_BITBOARD)
   {
      const int numBlockers = getNumberOfSetSquares(blockers);

      assert(numBlockers >= 1 && numBlockers <= 2);
      addBonus(base, BISHOP_MALUS_BLOCKER[numBlockers]);
   }
#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(2, 2));
   }

   if (testSquare(base->weakOutpostSquares[OPPCOLOR], square))
   {
      addBonus(base, V(2, 2));
   }
#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

#ifdef MOBILITY_TABLES
   addBonus(base, BishopMobilityBonus[mobilityCount]);
#else
   addBonus(base, mobilityCount * V(5, 7));
#endif

   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(2, 2));
   }

   if (testSquare(base->weakOutpostSquares[OPPCOLOR], square))
   {
      addBonus(base, V(2, 2));
   }
#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

#ifdef MOBILITY_TABLES
   addBonus(base, RookMobilityBonus[mobilityCount]);
#else
   addBonus(base, mobilityCount * V(2, 4));
#endif

#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 BONUS_EXCHANGE_UP
   if (position->piecesOfType[ROOK | OPPCOLOR] == EMPTY_BITBOARD &&
       hasQueen(position, COLOR) == hasQueen(position, OPPCOLOR) &&
       position->piecesOfType[PAWN | COLOR] != EMPTY_BITBOARD)
   {
      if (base->passedPawns[COLOR] != EMPTY_BITBOARD)
      {
         addBonus(base, V(25, 25));
      }
      else
      {
         addBonus(base, V(15, 15));
      }
   }
#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(2, 1));
   }
#endif

#ifdef MOBILITY_TABLES
   addBonus(base, QueenMobilityBonus[mobilityCount]);
#else
   addBonus(base, mobilityCount * V(1, 2));
#endif

   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 ppWeight = 118 - 3 * getPieceWeight(position, OPPCOLOR);
   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 ? 18 : 14);

            endgameBonus += rankFactor * bonus;
         }
         else
         {
            int bonus =
               ((obstacles & ~ownAttacks) == EMPTY_BITBOARD ? 10 : 6);

            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 * ppWeight) / 256;
   egValue = (endgameBonus * ppWeight) / 256;

#ifdef INCLUDE_PASSERS_IN_FUTILITY_MARGIN
   base->futilityMargin[OPPCOLOR] =
      max(base->futilityMargin[OPPCOLOR], max(opValue, egValue));
#endif

   addBonus(base, V(opValue, egValue));
}

#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); */
         }
      }
   }
}

#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 > RANK_3 && fai == fdi + 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 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;
}

#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)]);
   }
}
