[go: up one dir, main page]

Menu

Diff of /evaluation.c [000000] .. [r1]  Maximize  Restore

Switch to side-by-side view

--- a
+++ b/evaluation.c
@@ -0,0 +1,3291 @@
+/*
+    Protector -- a UCI chess engine
+
+    Copyright (C) 2008 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#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
+
+#include "evaluation.h"
+
+/*
+#define CALCULATE_TARGETS
+#define MALUS_OFFSIDE_KING
+#define BONUS_CONNECTED_DISTANT_PASSERS
+#define BONUS_EXCHANGE_UP
+*/
+
+/* -------------------------------------------------------------------------- */
+
+#define MAL_STD 100
+#define MAL_WGT 75
+const int MALUS_FACTOR = 105;
+
+const int PAWN_VALUE_OPENING = 75;
+const int PAWN_VALUE_ENDGAME = 90;
+const int PAWN_MALUS_DOUBLED_OPENING = (10 * MAL_WGT) / MAL_STD;
+const int PAWN_MALUS_DOUBLED_ENDGAME = (20 * MAL_WGT) / MAL_STD;
+const int PAWN_MALUS_ISOLATED_OPENING = (10 * MAL_WGT) / MAL_STD;
+const int PAWN_MALUS_ISOLATED_ON_OPEN_FILE = (20 * MAL_WGT) / MAL_STD;
+const int PAWN_MALUS_ISOLATED_ENDGAME = (20 * MAL_WGT) / MAL_STD;
+const int PAWN_MALUS_ISOLATED_FIXED_OPENING = (6 * MAL_WGT) / MAL_STD;
+const int PAWN_MALUS_ISOLATED_FIXED_ENDGAME = (6 * MAL_WGT) / MAL_STD;
+const int PAWN_MALUS_BACKWARD_OPENING = (8 * MAL_WGT) / MAL_STD;
+const int PAWN_MALUS_BACKWARD_ON_OPEN_FILE = (16 * MAL_WGT) / MAL_STD;
+const int PAWN_MALUS_BACKWARD_ENDGAME = (10 * MAL_WGT) / MAL_STD;
+const int PAWN_MALUS_BACKWARD_FIXED_OPENING = (4 * MAL_WGT) / MAL_STD;
+const int PAWN_MALUS_BACKWARD_FIXED_ENDGAME = (4 * MAL_WGT) / MAL_STD;
+
+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_MOBILITY_THRESHOLD = 4;
+const int KNIGHT_MOBILITY_BONUS_OPENING = 4;
+const int KNIGHT_MOBILITY_BONUS_ENDGAME = 4;
+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_MOBILITY_THRESHOLD = 6;
+const int BISHOP_MOBILITY_BONUS_OPENING = 5;
+const int BISHOP_MOBILITY_BONUS_ENDGAME = 5;
+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_MOBILITY_THRESHOLD = 7;
+const int ROOK_MOBILITY_BONUS_OPENING = 2;
+const int ROOK_MOBILITY_BONUS_ENDGAME = 4;
+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_MOBILITY_THRESHOLD = 13;
+const int QUEEN_MOBILITY_BONUS_OPENING = 1;
+const int QUEEN_MOBILITY_BONUS_ENDGAME = 2;
+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
+};
+
+/* -------------------------------------------------------------------------- */
+
+#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;
+
+const int KnightOutpostBonus[_64_] = {
+   0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0,
+   0, 2, 5, 10, 10, 5, 2, 0,
+   0, 2, 5, 10, 10, 5, 2, 0,
+   0, 0, 4, 5, 5, 4, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0,
+   0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+int centerDistance[_64_], centerTaxiDistance[_64_];
+int KNIGHT_OUTPOST_BONUS[2][_64_];
+int attackPoints[16];
+Bitboard leeSquares[_64_], luvSquares[_64_];
+Bitboard abghFiles;
+Bitboard weakOutpostSquareCandidates[2];
+Bitboard butterflySquares[_64_];
+Bitboard lateralSquares[_64_];
+Bitboard companionFiles[_64_];
+Bitboard passedPawnRectangle[2][_64_];
+Bitboard passedPawnCorridor[2][_64_];
+Bitboard passedPawnCatcher[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;
+
+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 Position * position,
+                                    const Color color, const Square square)
+{
+   const Bitboard attackers = position->piecesOfType[PAWN | opponent(color)];
+
+   return (bool) ((attackers & candidateDefenders[color][square]) ==
+                  EMPTY_BITBOARD);
+}
+
+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;
+   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);
+   base->pawnAttackableSquares[WHITE] =
+      ((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);
+   base->pawnAttackableSquares[BLACK] =
+      ((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] |
+      base->pawnAttackableSquares[WHITE];
+   blackSwamp = base->downwardRealm[WHITE] | base->upwardRealm[BLACK] |
+      base->pawnAttackableSquares[BLACK];
+
+   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 & ~(base->pawnAttackableSquares[WHITE] |
+                 whiteLateralSquares | tmp1));
+
+   tmp2 = ~(white | black | base->pawnProtectedSquares[WHITE]);
+   tmp1 = (blackLateralSquares & tmp2) << 8;
+   tmp1 |= (tmp1 & squaresOfRank[RANK_6] & tmp2) << 8;
+   base->weakPawns[BLACK] =
+      (black & ~(base->pawnAttackableSquares[BLACK] |
+                 blackLateralSquares | tmp1));
+
+   base->weakOutpostSquares[WHITE] = base->upwardRealm[WHITE] &
+      ~(base->pawnAttackableSquares[WHITE] |
+        base->downwardRealm[BLACK] | white | black) &
+      weakOutpostSquareCandidates[WHITE];
+
+   base->weakOutpostSquares[BLACK] = base->upwardRealm[BLACK] &
+      ~(base->pawnAttackableSquares[BLACK] |
+        base->downwardRealm[WHITE] | white | black) &
+      weakOutpostSquareCandidates[BLACK];
+
+   /* Calculate the candidates */
+   base->candidatePawns[WHITE] = white & ~base->passedPawns[WHITE] &
+      (base->pawnAttackableSquares[WHITE] | whiteLateralSquares) &
+      ~(base->upwardRealm[BLACK] | base->downwardRealm[WHITE]);
+
+   base->candidatePawns[BLACK] = black & ~base->passedPawns[BLACK] &
+      (base->pawnAttackableSquares[BLACK] | blackLateralSquares) &
+      ~(base->upwardRealm[WHITE] | base->downwardRealm[BLACK]);
+
+#ifdef BONUS_HIDDEN_PASSER
+   /* Calculate the hidden candidates */
+   base->hiddenCandidatePawns[WHITE] = white & (black >> 8) &
+      ~base->pawnAttackableSquares[BLACK] & ~(blackLateralSquares) &
+      (squaresOfRank[RANK_5] | squaresOfRank[RANK_6]) &
+      base->pawnProtectedSquares[WHITE];
+
+   base->hiddenCandidatePawns[BLACK] = black & (white << 8) &
+      ~base->pawnAttackableSquares[WHITE] & ~(whiteLateralSquares) &
+      (squaresOfRank[RANK_4] | squaresOfRank[RANK_3]) &
+      base->pawnProtectedSquares[BLACK];
+#endif
+
+   tmp1 = black & base->pawnProtectedSquares[BLACK];
+   tmp2 = ((tmp1 & nonA) >> 9) & ((tmp1 & nonH) >> 7);
+   tmp2 &= ~base->pawnAttackableSquares[WHITE];
+   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 &= ~base->pawnAttackableSquares[BLACK];
+   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
+}
+
+bool pawnIsPassed(const Position * position, const Square pawnSquare)
+{
+   const Color pawnColor = pieceColor(position->piece[pawnSquare]);
+   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)
+{
+   int numWeaknesses[2];
+   Square square;
+   Bitboard pieces = (base->weakPawns[WHITE] | base->weakPawns[BLACK]);
+   const int whiteDoubles = getNumberOfSetSquares(base->doubledPawns[WHITE]);
+   const int blackDoubles = getNumberOfSetSquares(base->doubledPawns[BLACK]);
+   Color color;
+
+   numWeaknesses[WHITE] = whiteDoubles;
+   numWeaknesses[BLACK] = blackDoubles;
+   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 >
+         (testSquare(base->upwardRealm[oppColor], square) == FALSE &&
+          testSquare(base->doubledPawns[pawnColor], square) == FALSE);
+
+      numWeaknesses[pawnColor]++;
+
+      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;
+         }
+      }
+   }
+
+   for (color = WHITE; color <= BLACK; color++)
+   {
+      int weight = 100, i;
+
+      for (i = 0; i < numWeaknesses[color]; i++)
+      {
+         weight = (weight * MALUS_FACTOR) / 100;
+      }
+
+      base->openingPoints[color] =
+         (weight * base->openingPoints[color]) / 100;
+      base->endgamePoints[color] =
+         (weight * base->endgamePoints[color]) / 100;
+   }
+
+   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 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(position, 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));
+   }
+}
+
+INLINE static void evaluateKnight(const Position * position,
+                                  EvaluationBase * base, const Square square)
+{
+   const Piece piece = position->piece[square];
+   const Color color = pieceColor(piece);
+   const Color oppColor = opponent(color);
+   const Bitboard moves = getKnightMoves(square);
+   const int mobilityCount =
+      getNumberOfSetSquares(moves & base->countedSquares[color]) -
+      KNIGHT_MOBILITY_THRESHOLD;
+
+#ifdef OUTPOST_SQUARE_BONUS
+   const Bitboard outpostAttacks = moves & base->weakOutpostSquares[oppColor];
+#endif
+
+#ifdef CALCULATE_TARGETS
+   base->pieceAttacks[color] |= moves;
+#endif
+
+   base->openingPoints[color] += mobilityCount *
+      KNIGHT_MOBILITY_BONUS_OPENING;
+   base->endgamePoints[color] += mobilityCount *
+      KNIGHT_MOBILITY_BONUS_ENDGAME;
+
+   if (base->evaluateKingSafety[oppColor] &&
+       (moves & base->kingAttackSquares[oppColor]) != EMPTY_BITBOARD)
+   {
+      base->numAttackers[color]++;
+      base->attackPoints[color] += KNIGHT_BONUS_ATTACK;
+   }
+
+   if (KNIGHT_OUTPOST_BONUS[color][square] > 0 &&
+       testSquare(base->pawnProtectedSquares[color], square))
+   {
+      const Bitboard protectors =
+         generalMoves[PAWN | oppColor][square] &
+         position->piecesOfType[PAWN | color];
+
+      base->openingPoints[color] += getNumberOfSetSquares(protectors) *
+         KNIGHT_OUTPOST_BONUS[color][square];
+   }
+
+#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
+
+#ifdef OUTPOST_SQUARE_BONUS
+   if (outpostAttacks != EMPTY_BITBOARD)
+   {
+      const int count = getNumberOfSetSquares(outpostAttacks);
+
+      base->openingPoints[color] += count * KNIGHT_MOBILITY_BONUS_OPENING;
+   }
+   else if (testSquare(base->weakOutpostSquares[oppColor], square))
+   {
+      base->openingPoints[color] += KNIGHT_MOBILITY_BONUS_OPENING;
+   }
+#endif
+}
+
+INLINE static void evaluateBishop(const Position * position,
+                                  EvaluationBase * base, const Square square)
+{
+   const Piece piece = position->piece[square];
+   const Color color = pieceColor(piece);
+   const Color oppColor = opponent(color);
+   const Bitboard moves = getMagicBishopMoves(square, position->allPieces);
+   const int mobilityCount =
+      getNumberOfSetSquares(moves & base->countedSquares[color]) -
+      BISHOP_MOBILITY_THRESHOLD;
+#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
+
+   base->openingPoints[color] += mobilityCount *
+      BISHOP_MOBILITY_BONUS_OPENING;
+   base->endgamePoints[color] += mobilityCount *
+      BISHOP_MOBILITY_BONUS_ENDGAME;
+
+   if (base->evaluateKingSafety[oppColor] &&
+       testSquare(base->kingAttacks[oppColor]->diaAttackers, square))
+   {
+      const Bitboard xrayPieces = position->piecesOfType[QUEEN | color];
+      const Bitboard xrayMoves =
+         getMagicBishopMoves(square, position->allPieces & ~xrayPieces);
+
+      if ((xrayMoves & 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
+
+#ifdef OUTPOST_SQUARE_BONUS
+   if (outpostAttacks != EMPTY_BITBOARD)
+   {
+      const int count = getNumberOfSetSquares(outpostAttacks);
+
+      base->openingPoints[color] += count * BISHOP_MOBILITY_BONUS_OPENING;
+   }
+   else if (testSquare(base->weakOutpostSquares[oppColor], square))
+   {
+      base->openingPoints[color] += BISHOP_MOBILITY_BONUS_OPENING;
+   }
+#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(position, color, knightSquare) &&
+             pieceIsPinnedByBishop(position, knightSquare, square, targets))
+         {
+            base->openingPoints[color] += BISHOP_BONUS_PINNING_KNIGHT_OPENING;
+            base->endgamePoints[color] += BISHOP_BONUS_PINNING_KNIGHT_ENDGAME;
+         }
+      }
+   }
+#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;
+   }
+}
+
+INLINE static void evaluateRook(const Position * position,
+                                EvaluationBase * base, const Square square)
+{
+   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 int mobilityCount =
+      getNumberOfSetSquares(moves & base->countedSquares[color]) -
+      ROOK_MOBILITY_THRESHOLD;
+   const Bitboard fileSquares = squaresOfFile[file(square)];
+   const Bitboard ownPawns = position->piecesOfType[PAWN | color];
+
+#ifdef OUTPOST_SQUARE_BONUS
+   const Bitboard outpostAttacks = moves & base->weakOutpostSquares[oppColor];
+#endif
+
+#ifdef CALCULATE_TARGETS
+   base->pieceAttacks[color] |= moves;
+#endif
+
+   base->openingPoints[color] += mobilityCount * ROOK_MOBILITY_BONUS_OPENING;
+   base->endgamePoints[color] += mobilityCount * ROOK_MOBILITY_BONUS_ENDGAME;
+
+   /* 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 & base->countedSquares[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] &&
+       testSquare(base->kingAttacks[oppColor]->orthoAttackers, square))
+   {
+      const Bitboard xrayPieces = position->piecesOfType[QUEEN | color] |
+         position->piecesOfType[piece];
+      const Bitboard xrayMoves =
+         getMagicRookMoves(square, position->allPieces & ~xrayPieces);
+
+      if ((xrayMoves & base->kingAttackSquares[oppColor]) != EMPTY_BITBOARD)
+      {
+         base->numAttackers[color]++;
+         base->attackPoints[color] += ROOK_BONUS_ATTACK;
+      }
+   }
+
+#ifdef OUTPOST_SQUARE_BONUS
+   if ((outpostAttacks & fileSquares) != EMPTY_BITBOARD)
+   {
+      const int count = getNumberOfSetSquares(outpostAttacks);
+
+      base->openingPoints[color] += count * ROOK_MOBILITY_BONUS_OPENING;
+   }
+   else if (testSquare(base->weakOutpostSquares[oppColor], square))
+   {
+      base->openingPoints[color] += ROOK_MOBILITY_BONUS_OPENING;
+   }
+#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)
+   {
+      base->endgamePoints[color] -= ROOK_MALUS_BLOCKING_PASSER;
+   }
+#endif
+
+#ifdef BONUS_SPACE_ATTACKS
+   if (testSquare(attackingRealm[color], square))
+   {
+      base->spaceAttackPoints[color]++;
+   }
+#endif
+}
+
+INLINE static void evaluateQueen(const Position * position,
+                                 EvaluationBase * base, const Square square)
+{
+   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 mobilityCount = 10 -
+      taxiDistance(square, position->king[oppColor]);
+
+#ifdef OUTPOST_SQUARE_BONUS
+   const Bitboard moves = getMagicQueenMoves(square, position->allPieces);
+   const Bitboard outpostAttacks = moves & base->weakOutpostSquares[oppColor];
+#endif
+
+#ifdef CALCULATE_TARGETS
+   base->pieceAttacks[color] |= moves;
+#endif
+
+   base->openingPoints[color] += mobilityCount;
+   base->endgamePoints[color] += mobilityCount;
+
+   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 OUTPOST_SQUARE_BONUS
+   if (outpostAttacks != EMPTY_BITBOARD)
+   {
+      const int count = getNumberOfSetSquares(outpostAttacks);
+
+      base->openingPoints[color] += count;
+   }
+#endif
+
+#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
+}
+
+static int getWinningChances(const Position * position, 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;
+         Bitboard pawns = position->piecesOfType[(Piece) (PAWN | color)];
+         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 == 1)
+         {
+            const int max = (oppositeColoredBishops(position) ? 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 if ((pawns & nonA & nonH) != EMPTY_BITBOARD)
+            {
+               return max;
+            }
+            else                /* Check for wrong colored bishops: */
+            {
+               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);
+                  Bitboard requiredBishop, criticalOwnPawns;
+
+                  if (distance(oppKing, promotionSquare) > 1)
+                  {
+                     return max;
+                  }
+
+                  requiredBishop = (squareColor(promotionSquare) == LIGHT ?
+                                    lightSquares : darkSquares);
+
+                  if ((requiredBishop & bishops) != EMPTY_BITBOARD)
+                  {
+                     return max;
+                  }
+
+                  criticalOwnPawns = position->piecesOfType[PAWN | oppColor] &
+                     squaresAbove[color][square] &
+                     (file(square) == FILE_A ?
+                      squaresOfFile[FILE_B] : squaresOfFile[FILE_G]);
+
+                  if (criticalOwnPawns != EMPTY_BITBOARD)
+                  {
+                     return max;
+                  }
+               }
+
+               /* no winning bishop+pawn combination found */
+
+               return 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;
+
+#ifdef BONUS_EXCHANGE_UP
+   Color color;
+#endif
+
+   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);
+   }
+
+#ifdef BONUS_EXCHANGE_UP
+   for (color = WHITE; color <= BLACK; color++)
+   {
+      const Color oppColor = opponent(color);
+
+      if (hasOrthoPieces(position, oppColor) == FALSE &&
+          position->piecesOfType[ROOK | color] != EMPTY_BITBOARD &&
+          numberOfNonPawnPieces(position, color) >=
+          numberOfNonPawnPieces(position, oppColor) &&
+          (base->weakPawns[oppColor] != EMPTY_BITBOARD ||
+           base->passedPawns[color] != EMPTY_BITBOARD))
+      {
+         base->endgamePoints[color] += 8;
+
+         if (base->passedPawns[color] != EMPTY_BITBOARD)
+         {
+            base->endgamePoints[color] += 24;
+         }
+         else if (getWidth(position->piecesOfType[PAWN | color]) > 3)
+         {
+            base->endgamePoints[color] += 8;
+         }
+      }
+   }
+#endif
+}
+
+INLINE static int getPositionalValue(Position * position,
+                                     EvaluationBase * base)
+{
+   int value, openingValue, endgameValue;
+   const int pi = phaseIndex(position);
+
+#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->countedSquares[BLACK] = ~position->piecesOfColor[BLACK];
+   base->numAttackers[WHITE] = base->numAttackers[BLACK] = 0;
+   base->attackPoints[WHITE] = base->attackPoints[BLACK] = 0;
+   base->spaceAttackPoints[WHITE] = base->spaceAttackPoints[BLACK] = 0;
+#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]];
+   }
+
+   if ((base->evaluateKingSafety[BLACK] =
+        kingSafetyEvalRequired(position, BLACK)) != FALSE)
+   {
+      base->kingAttackSquares[BLACK] = getKingMoves(position->king[BLACK]);
+      base->kingAttacks[BLACK] = &kingAttacks[position->king[BLACK]];
+   }
+
+   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];
+#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];
+#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 tmp1[_64_];
+   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);
+
+   transposeMatrix(&KnightOutpostBonus[0], &tmp1[0]);
+
+   ITERATE(square)
+   {
+      Color color;
+      Square kingSquare;
+
+      leeSquares[square] = luvSquares[square] = EMPTY_BITBOARD;
+
+      for (color = WHITE; color <= BLACK; color++)
+      {
+         passedPawnRectangle[color][square] =
+            passedPawnCorridor[color][square] =
+            passedPawnCatcher[color][square] =
+            candidateDefenders[color][square] =
+            candidateSupporters[color][square] = EMPTY_BITBOARD;
+      }
+
+      if (testSquare(rookTraps[WHITE], square))
+      {
+         setSquare(rookTraps[BLACK], getFlippedSquare(square));
+      }
+
+      KNIGHT_OUTPOST_BONUS[WHITE][square] = tmp1[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));
+
+      KNIGHT_OUTPOST_BONUS[BLACK][square] =
+         KNIGHT_OUTPOST_BONUS[WHITE][getFlippedSquare(square)];
+
+      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 (file(square) <= FILE_D)
+         {
+            if (kingsquarefile < squarefile)
+            {
+               setSquare(leeSquares[square], kingsquare);
+            }
+
+            if (kingsquarefile > squarefile)
+            {
+               setSquare(luvSquares[square], kingsquare);
+            }
+         }
+         else
+         {
+            if (kingsquarefile > squarefile)
+            {
+               setSquare(leeSquares[square], kingsquare);
+            }
+
+            if (kingsquarefile < squarefile)
+            {
+               setSquare(luvSquares[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)
+      {
+         const int catcherrank = rank(catchersquare);
+         const int promotionCountWhite = RANK_8 - squarerank;
+         const int promotionCountBlack = squarerank - RANK_1;
+         const int promotionCountWhiteCatcher =
+            (catcherrank == RANK_2 ?
+             RANK_8 - catcherrank - 1 : RANK_8 - catcherrank);
+         const int promotionCountBlackCatcher =
+            (catcherrank == RANK_7 ?
+             catcherrank - RANK_1 - 1 : catcherrank - RANK_1);
+
+         if (promotionCountBlackCatcher < promotionCountWhite + 1)
+         {
+            setSquare(passedPawnCatcher[WHITE][square], catchersquare);
+         }
+
+         if (promotionCountWhiteCatcher < promotionCountBlack + 1)
+         {
+            setSquare(passedPawnCatcher[BLACK][square], 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;
+         }
+      }
+   }
+
+   abghFiles = squaresOfFile[FILE_A] | squaresOfFile[FILE_B] |
+      squaresOfFile[FILE_G] | squaresOfFile[FILE_H];
+
+   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);
+
+   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));
+
+   assert(KNIGHT_OUTPOST_BONUS[WHITE][A8] == KnightOutpostBonus[0]);
+   assert(KNIGHT_OUTPOST_BONUS[WHITE][H1] == KnightOutpostBonus[63]);
+   assert(KNIGHT_OUTPOST_BONUS[WHITE][D4] == KnightOutpostBonus[35]);
+   assert(KNIGHT_OUTPOST_BONUS[WHITE][D3] == KnightOutpostBonus[43]);
+
+   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;
+}