]> git.sesse.net Git - stockfish/blobdiff - src/evaluate.cpp
Change evaluate() signature
[stockfish] / src / evaluate.cpp
index aeecc0b7ff8b19c815a65e3cc22a9715d89847d3..981c97db9b33628ca7fa7237de74a7c956dcc61d 100644 (file)
 
 namespace {
 
+  // Struct EvalInfo contains various information computed and collected
+  // by the evaluation functions.
+  struct EvalInfo {
+
+    // Middle and end game position's static evaluations
+    Score value;
+
+    // margin[color] stores the evaluation margins we should consider for
+    // the given position. This is a kind of uncertainty estimation and
+    // typically is used by the search for pruning decisions.
+    Value margin[2];
+
+    // Pointers to material and pawn hash table entries
+    MaterialInfo* mi;
+    PawnInfo* pi;
+
+    // attackedBy[color][piece type] is a bitboard representing all squares
+    // attacked by a given color and piece type, attackedBy[color][0] contains
+    // all squares attacked by the given color.
+    Bitboard attackedBy[2][8];
+
+    // kingZone[color] is the zone around the enemy king which is considered
+    // by the king safety evaluation. This consists of the squares directly
+    // adjacent to the king, and the three (or two, for a king on an edge file)
+    // squares two ranks in front of the king. For instance, if black's king
+    // is on g8, kingZone[WHITE] is a bitboard containing the squares f8, h8,
+    // f7, g7, h7, f6, g6 and h6.
+    Bitboard kingZone[2];
+
+    // kingAttackersCount[color] is the number of pieces of the given color
+    // which attack a square in the kingZone of the enemy king.
+    int kingAttackersCount[2];
+
+    // kingAttackersWeight[color] is the sum of the "weight" of the pieces of the
+    // given color which attack a square in the kingZone of the enemy king. The
+    // weights of the individual piece types are given by the variables
+    // QueenAttackWeight, RookAttackWeight, BishopAttackWeight and
+    // KnightAttackWeight in evaluate.cpp
+    int kingAttackersWeight[2];
+
+    // kingAdjacentZoneAttacksCount[color] is the number of attacks to squares
+    // directly adjacent to the king of the given color. Pieces which attack
+    // more than one square are counted multiple times. For instance, if black's
+    // king is on g8 and there's a white knight on g5, this knight adds
+    // 2 to kingAdjacentZoneAttacksCount[BLACK].
+    int kingAdjacentZoneAttacksCount[2];
+  };
+
   const int Sign[2] = { 1, -1 };
 
   // Evaluation grain size, must be a power of 2
@@ -187,7 +235,7 @@ namespace {
 
   // Function prototypes
   template<bool HasPopCnt>
-  Value do_evaluate(const Position& pos, EvalInfo& ei);
+  Value do_evaluate(const Position& pos, Value margins[]);
 
   template<Color Us, bool HasPopCnt>
   void init_attack_tables(const Position& pos, EvalInfo& ei);
@@ -229,17 +277,18 @@ void prefetchPawn(Key key, int threadID) {
 /// evaluate() is the main evaluation function. It always computes two
 /// values, an endgame score and a middle game score, and interpolates
 /// between them based on the remaining material.
-Value evaluate(const Position& pos, EvalInfo& ei) {
+Value evaluate(const Position& pos, Value margins[]) {
 
-    return CpuHasPOPCNT ? do_evaluate<true>(pos, ei)
-                        : do_evaluate<false>(pos, ei);
+    return CpuHasPOPCNT ? do_evaluate<true>(pos, margins)
+                        : do_evaluate<false>(pos, margins);
 }
 
 namespace {
 
 template<bool HasPopCnt>
-Value do_evaluate(const Position& pos, EvalInfo& ei) {
+Value do_evaluate(const Position& pos, Value margins[]) {
 
+  EvalInfo ei;
   ScaleFactor factor[2];
   Score mobility;
 
@@ -344,6 +393,10 @@ Value do_evaluate(const Position& pos, EvalInfo& ei) {
           factor[BLACK] = sf;
   }
 
+  // Populate margins[]
+  margins[WHITE] = ei.margin[WHITE];
+  margins[BLACK] = ei.margin[BLACK];
+
   // Interpolate between the middle game and the endgame score
   return Sign[pos.side_to_move()] * scale_by_game_phase(ei.value, phase, factor);
 }
@@ -652,10 +705,10 @@ namespace {
 
         // Find the attacked squares around the king which has no defenders
         // apart from the king itself
-        undefended = ei.attacked_by(Them) & ei.attacked_by(Us, KING);
-        undefended &= ~(  ei.attacked_by(Us, PAWN)   | ei.attacked_by(Us, KNIGHT)
-                        | ei.attacked_by(Us, BISHOP) | ei.attacked_by(Us, ROOK)
-                        | ei.attacked_by(Us, QUEEN));
+        undefended = ei.attackedBy[Them][0] & ei.attackedBy[Us][KING];
+        undefended &= ~(  ei.attackedBy[Us][PAWN]   | ei.attackedBy[Us][KNIGHT]
+                        | ei.attackedBy[Us][BISHOP] | ei.attackedBy[Us][ROOK]
+                        | ei.attackedBy[Us][QUEEN]);
 
         // Initialize the 'attackUnits' variable, which is used later on as an
         // index to the KingDangerTable[] array. The initial value is based on
@@ -669,39 +722,39 @@ namespace {
 
         // Analyse enemy's safe queen contact checks. First find undefended
         // squares around the king attacked by enemy queen...
-        b = undefended & ei.attacked_by(Them, QUEEN) & ~pos.pieces_of_color(Them);
+        b = undefended & ei.attackedBy[Them][QUEEN] & ~pos.pieces_of_color(Them);
         if (b)
         {
             // ...then remove squares not supported by another enemy piece
-            b &= (  ei.attacked_by(Them, PAWN)   | ei.attacked_by(Them, KNIGHT)
-                  | ei.attacked_by(Them, BISHOP) | ei.attacked_by(Them, ROOK));
+            b &= (  ei.attackedBy[Them][PAWN]   | ei.attackedBy[Them][KNIGHT]
+                  | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK]);
             if (b)
                 attackUnits += QueenContactCheckBonus * count_1s_max_15<HasPopCnt>(b) * (sente ? 2 : 1);
         }
 
         // Analyse enemy's safe distance checks for sliders and knights
-        safe = ~(pos.pieces_of_color(Them) | ei.attacked_by(Us));
+        safe = ~(pos.pieces_of_color(Them) | ei.attackedBy[Us][0]);
 
         b1 = pos.attacks_from<ROOK>(ksq) & safe;
         b2 = pos.attacks_from<BISHOP>(ksq) & safe;
 
         // Enemy queen safe checks
-        b = (b1 | b2) & ei.attacked_by(Them, QUEEN);
+        b = (b1 | b2) & ei.attackedBy[Them][QUEEN];
         if (b)
             attackUnits += QueenCheckBonus * count_1s_max_15<HasPopCnt>(b);
 
         // Enemy rooks safe checks
-        b = b1 & ei.attacked_by(Them, ROOK);
+        b = b1 & ei.attackedBy[Them][ROOK];
         if (b)
             attackUnits += RookCheckBonus * count_1s_max_15<HasPopCnt>(b);
 
         // Enemy bishops safe checks
-        b = b2 & ei.attacked_by(Them, BISHOP);
+        b = b2 & ei.attackedBy[Them][BISHOP];
         if (b)
             attackUnits += BishopCheckBonus * count_1s_max_15<HasPopCnt>(b);
 
         // Enemy knights safe checks
-        b = pos.attacks_from<KNIGHT>(ksq) & ei.attacked_by(Them, KNIGHT) & safe;
+        b = pos.attacks_from<KNIGHT>(ksq) & ei.attackedBy[Them][KNIGHT] & safe;
         if (b)
             attackUnits += KnightCheckBonus * count_1s_max_15<HasPopCnt>(b);
 
@@ -709,14 +762,14 @@ namespace {
         attackUnits = Min(99, Max(0, attackUnits));
 
         // Finally, extract the king danger score from the KingDangerTable[]
-        // array and subtract the score from evaluation. Set also ei.kingDanger[]
+        // array and subtract the score from evaluation. Set also ei.margin[]
         // value that will be used for pruning because this value can sometimes
         // be very big, and so capturing a single attacking piece can therefore
         // result in a score change far bigger than the value of the captured piece.
         ei.value -= Sign[Us] * KingDangerTable[Us][attackUnits];
-        ei.kingDanger[Us] = mg_value(KingDangerTable[Us][attackUnits]);
+        ei.margin[Us] = mg_value(KingDangerTable[Us][attackUnits]);
     } else
-        ei.kingDanger[Us] = VALUE_ZERO;
+        ei.margin[Us] = VALUE_ZERO;
   }
 
 
@@ -759,7 +812,7 @@ namespace {
             if (pos.square_is_empty(blockSq))
             {
                 squaresToQueen = squares_in_front_of(Us, s);
-                defendedSquares = squaresToQueen & ei.attacked_by(Us);
+                defendedSquares = squaresToQueen & ei.attackedBy[Us][0];
 
                 // If there is an enemy rook or queen attacking the pawn from behind,
                 // add all X-ray attacks by the rook or queen. Otherwise consider only
@@ -768,7 +821,7 @@ namespace {
                     && (squares_behind(Us, s) & pos.pieces(ROOK, QUEEN, Them) & pos.attacks_from<ROOK>(s)))
                     unsafeSquares = squaresToQueen;
                 else
-                    unsafeSquares = squaresToQueen & (ei.attacked_by(Them) | pos.pieces_of_color(Them));
+                    unsafeSquares = squaresToQueen & (ei.attackedBy[Them][0] | pos.pieces_of_color(Them));
 
                 // If there aren't enemy attacks or pieces along the path to queen give
                 // huge bonus. Even bigger if we protect the pawn's path.
@@ -834,8 +887,8 @@ namespace {
     // pawn, or if it is undefended and attacked by an enemy piece.
     Bitboard safe =   SpaceMask[Us]
                    & ~pos.pieces(PAWN, Us)
-                   & ~ei.attacked_by(Them, PAWN)
-                   & (ei.attacked_by(Us) | ~ei.attacked_by(Them));
+                   & ~ei.attackedBy[Them][PAWN]
+                   & (ei.attackedBy[Us][0] | ~ei.attackedBy[Them][0]);
 
     // Find all squares which are at most three squares behind some friendly pawn
     Bitboard behind = pos.pieces(PAWN, Us);