]> git.sesse.net Git - stockfish/blobdiff - src/evaluate.cpp
Introduce new Threats weights = {350, 256}
[stockfish] / src / evaluate.cpp
index 44a0669f9c0ca7c13f8ceda90141a235cccc811f..406d07459df577af3c617b40b91d2257a1774d32 100644 (file)
@@ -107,10 +107,10 @@ namespace {
 
 
   // Evaluation weights, indexed by the corresponding evaluation term
-  enum { Mobility, PawnStructure, PassedPawns, Space, KingSafety };
+  enum { Mobility, PawnStructure, PassedPawns, Space, KingSafety, Threats };
 
   const struct Weight { int mg, eg; } Weights[] = {
-    {289, 344}, {233, 201}, {221, 273}, {46, 0}, {322, 0}
+    {289, 344}, {233, 201}, {221, 273}, {46, 0}, {322, 0}, {350, 256}
   };
 
   Score operator*(Score s, const Weight& w) {
@@ -141,6 +141,11 @@ namespace {
       S(112,125), S(113,127), S(117,137), S(122,143) }
   };
 
+  // Mask of allowed outpost squares indexed by color
+  const Bitboard OutpostMask[COLOR_NB] = {
+    Rank4BB | Rank5BB | Rank6BB, Rank5BB | Rank4BB | Rank3BB
+  };
+
   // Outpost[knight/bishop][supported by pawn] contains bonuses for knights and
   // bishops outposts, bigger if outpost piece is supported by a pawn.
   const Score Outpost[][2] = {
@@ -148,17 +153,23 @@ namespace {
     { S(18, 5), S(27, 8) }  // Bishops
   };
 
-  // Threat[defended/weak][minor/rook attacking][attacked PieceType] contains
+  // ReachableOutpost[knight/bishop][supported by pawn] contains bonuses for knights and
+  // bishops which can reach a outpost square in one move, bigger if outpost square is supported by a pawn.
+  const Score ReachableOutpost[][2] = {
+    { S(21, 5), S(31, 8) }, // Knights
+    { S( 8, 2), S(13, 4) }  // Bishops
+  };
+
+  // Threat[minor/rook][attacked PieceType] contains
   // bonuses according to which piece type attacks which one.
-  const Score Threat[][2][PIECE_TYPE_NB] = {
-  { { S(0, 0), S( 0, 0), S(19, 37), S(24, 37), S(44, 97), S(35,106) },   // Minor on Defended
-    { S(0, 0), S( 0, 0), S( 9, 14), S( 9, 14), S( 7, 14), S(24, 48) } }, // Rook on Defended
-  { { S(0, 0), S( 0,32), S(33, 41), S(31, 50), S(41,100), S(35,104) },   // Minor on Weak
-    { S(0, 0), S( 0,27), S(26, 57), S(26, 57), S(0 , 43), S(23, 51) } }  // Rook on Weak
+  // Attacks on lesser pieces which are pawn defended are not considered.
+  const Score Threat[2][PIECE_TYPE_NB] = {
+   { S(0, 0), S(0, 32), S(25, 39), S(28, 44), S(42, 98), S(35,105) }, // Minor attacks
+   { S(0, 0), S(0, 27), S(26, 57), S(26, 57), S( 0, 30), S(23, 51) }  // Rook attacks
   };
 
   // ThreatenedByPawn[PieceType] contains a penalty according to which piece
-  // type is attacked by an enemy pawn.
+  // type is attacked by a pawn.
   const Score ThreatenedByPawn[PIECE_TYPE_NB] = {
     S(0, 0), S(0, 0), S(107, 138), S(84, 122), S(114, 203), S(121, 217)
   };
@@ -172,8 +183,8 @@ namespace {
 
   // PassedFile[File] contains a bonus according to the file of a passed pawn.
   const Score PassedFile[] = {
-    S( 12,  10), S( 3,  10), S( 1, -8), S(-27, -12),
-    S(-27, -12), S( 1, -8),  S( 3, 10), S( 12,  10)
+    S( 12,  10), S( 3, 10), S( 1, -8), S(-27, -12),
+    S(-27, -12), S( 1, -8), S( 3, 10), S( 12,  10)
   };
 
   const Score ThreatenedByHangingPawn = S(40, 60);
@@ -258,7 +269,7 @@ namespace {
   template<PieceType Pt, Color Us, bool DoTrace>
   Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility, const Bitboard* mobilityArea) {
 
-    Bitboard b;
+    Bitboard b, bb;
     Square s;
     Score score = SCORE_ZERO;
 
@@ -284,7 +295,7 @@ namespace {
         {
             ei.kingAttackersCount[Us]++;
             ei.kingAttackersWeight[Us] += KingAttackWeights[Pt];
-            Bitboard bb = b & ei.attackedBy[Them][KING];
+            bb = b & ei.attackedBy[Them][KING];
             if (bb)
                 ei.kingAdjacentZoneAttacksCount[Us] += popcount<Max15>(bb);
         }
@@ -300,11 +311,16 @@ namespace {
 
         if (Pt == BISHOP || Pt == KNIGHT)
         {
-            // Bonus for outpost square
-            if (   relative_rank(Us, s) >= RANK_4
-                && relative_rank(Us, s) <= RANK_6
-                && !(pos.pieces(Them, PAWN) & pawn_attack_span(Us, s)))
+            // Bonus for outpost squares
+            bb = OutpostMask[Us] & ~ei.pi->pawn_attacks_span(Them);
+            if (bb & s)
                 score += Outpost[Pt == BISHOP][!!(ei.attackedBy[Us][PAWN] & s)];
+            else
+            {
+                bb &= b & ~pos.pieces(Us);
+                if (bb)
+                   score += ReachableOutpost[Pt == BISHOP][!!(ei.attackedBy[Us][PAWN] & bb)];
+            }
 
             // Bonus when behind a pawn
             if (    relative_rank(Us, s) < RANK_5
@@ -484,7 +500,6 @@ namespace {
     const Bitboard TRank2BB = (Us == WHITE ? Rank2BB  : Rank7BB);
     const Bitboard TRank7BB = (Us == WHITE ? Rank7BB  : Rank2BB);
 
-    enum { Defended, Weak };
     enum { Minor, Rook };
 
     Bitboard b, weak, defended, safeThreats;
@@ -510,33 +525,21 @@ namespace {
     // Non-pawn enemies defended by a pawn
     defended = (pos.pieces(Them) ^ pos.pieces(Them, PAWN)) & ei.attackedBy[Them][PAWN];
 
-    // Add a bonus according to the kind of attacking pieces
-    if (defended)
-    {
-        b = defended & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
-        while (b)
-            score += Threat[Defended][Minor][type_of(pos.piece_on(pop_lsb(&b)))];
-
-        b = defended & ei.attackedBy[Us][ROOK];
-        while (b)
-            score += Threat[Defended][Rook][type_of(pos.piece_on(pop_lsb(&b)))];
-    }
-
     // Enemies not defended by a pawn and under our attack
     weak =   pos.pieces(Them)
           & ~ei.attackedBy[Them][PAWN]
           &  ei.attackedBy[Us][ALL_PIECES];
 
     // Add a bonus according to the kind of attacking pieces
-    if (weak)
+    if (defended | weak)
     {
-        b = weak & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
+        b = (defended | weak) & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
         while (b)
-            score += Threat[Weak][Minor][type_of(pos.piece_on(pop_lsb(&b)))];
+            score += Threat[Minor][type_of(pos.piece_on(pop_lsb(&b)))];
 
-        b = weak & ei.attackedBy[Us][ROOK];
+        b = (pos.pieces(Them, QUEEN) | weak) & ei.attackedBy[Us][ROOK];
         while (b)
-            score += Threat[Weak][Rook][type_of(pos.piece_on(pop_lsb(&b)))];
+            score += Threat[Rook ][type_of(pos.piece_on(pop_lsb(&b)))];
 
         b = weak & ~ei.attackedBy[Them][ALL_PIECES];
         if (b)
@@ -563,9 +566,9 @@ namespace {
         score += popcount<Max15>(b) * PawnAttackThreat;
 
     if (DoTrace)
-        Trace::add(THREAT, Us, score);
+        Trace::add(THREAT, Us, score * Weights[Threats]);
 
-    return score;
+    return score * Weights[Threats];
   }
 
 
@@ -688,24 +691,23 @@ namespace {
   }
 
 
-  // evaluate_initiative() computes the initiative correction value for the position, i.e. 
-  // second order bonus/malus based on the known attacking/defending status of the players. 
-  Score evaluate_initiative(const Position& pos, const EvalInfo& ei, const Score positional_score) {
+  // evaluate_initiative() computes the initiative correction value for the
+  // position, i.e. second order bonus/malus based on the known attacking/defending
+  // status of the players.
+  Score evaluate_initiative(const Position& pos, int asymmetry, Value eg) {
 
-    int pawns           =  pos.count<PAWN>(WHITE) + pos.count<PAWN>(BLACK);
-    int king_separation =  distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK));
-    int asymmetry       =  ei.pi->pawn_asymmetry();
+    int kingDistance = distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK));
+    int pawns = pos.count<PAWN>(WHITE) + pos.count<PAWN>(BLACK);
 
     // Compute the initiative bonus for the attacking side
-    int attacker_bonus =   8 * (pawns + asymmetry + king_separation) - 120;
+    int initiative = 8 * (pawns + asymmetry + kingDistance - 15);
 
-    // Now apply the bonus: note that we find the attacking side by extracting the sign 
-    // of the endgame value of "positional_score", and that we carefully cap the bonus so
-    // that the endgame score with the correction will never be divided by more than two.
-    int eg = eg_value(positional_score);
-    int value = ((eg > 0) - (eg < 0)) * std::max( attacker_bonus , -abs( eg / 2 ) );
+    // Now apply the bonus: note that we find the attacking side by extracting
+    // the sign of the endgame value, and that we carefully cap the bonus so
+    // that the endgame score will never be divided by more than two.
+    int value = ((eg > 0) - (eg < 0)) * std::max(initiative, -abs(eg / 2));
 
-    return make_score( 0 , value ) ; 
+    return make_score(0, value);
   }
 
 } // namespace
@@ -789,9 +791,9 @@ Value Eval::evaluate(const Position& pos) {
   // Evaluate space for both sides, only during opening
   if (pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) >= 12222)
       score += (evaluate_space<WHITE>(pos, ei) - evaluate_space<BLACK>(pos, ei)) * Weights[Space];
-  
-  // Evaluate initiative
-  score += evaluate_initiative(pos, ei, score);
+
+  // Evaluate position potential for the winning side
+  score += evaluate_initiative(pos, ei.pi->pawn_asymmetry(), eg_value(score));
 
   // Scale winning side if position is more drawish than it appears
   Color strongSide = eg_value(score) > VALUE_DRAW ? WHITE : BLACK;