]> git.sesse.net Git - stockfish/blobdiff - src/evaluate.cpp
Symmetric king safety
[stockfish] / src / evaluate.cpp
index ccc3d9154d62612daea3c68ab972e42d6afb2553..a945c5c7f2c29d34b18ac2ccd08ac3c6b97dcc9d 100644 (file)
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <algorithm>
 #include <cassert>
 #include <iomanip>
 #include <sstream>
-#include <algorithm>
 
 #include "bitcount.h"
 #include "evaluate.h"
@@ -90,8 +90,8 @@ namespace {
   }
 
   // Evaluation weights, initialized from UCI options
-  enum { Mobility, PawnStructure, PassedPawns, Space, KingDangerUs, KingDangerThem };
-  struct Weight { int mg, eg; } Weights[6];
+  enum { Mobility, PawnStructure, PassedPawns, Space, KingSafety };
+  struct Weight { int mg, eg; } Weights[5];
 
   typedef Value V;
   #define S(mg, eg) make_score(mg, eg)
@@ -103,7 +103,7 @@ namespace {
   //
   // Values modified by Joona Kiiski
   const Score WeightsInternal[] = {
-    S(289, 344), S(233, 201), S(221, 273), S(46, 0), S(271, 0), S(307, 0)
+    S(289, 344), S(233, 201), S(221, 273), S(46, 0), S(289, 0)
   };
 
   // MobilityBonus[PieceType][attacked] contains bonuses for middle and end
@@ -158,6 +158,9 @@ namespace {
     S(0, 0), S(0, 0), S(56, 70), S(56, 70), S(76, 99), S(86, 118)
   };
 
+  // Hanging[side to move] contains a bonus for each enemy hanging piece
+  const Score Hanging[2] = { S(23, 20) , S(35, 45) };
+
   #undef S
 
   const Score Tempo            = make_score(24, 11);
@@ -166,7 +169,6 @@ namespace {
   const Score RookSemiopenFile = make_score(19, 10);
   const Score BishopPawns      = make_score( 8, 12);
   const Score MinorBehindPawn  = make_score(16,  0);
-  const Score UndefendedMinor  = make_score(25, 10);
   const Score TrappedRook      = make_score(90,  0);
   const Score Unstoppable      = make_score( 0, 20);
 
@@ -200,9 +202,9 @@ namespace {
   const int BishopCheck       = 2;
   const int KnightCheck       = 3;
 
-  // KingDanger[Color][attackUnits] contains the actual king danger weighted
-  // scores, indexed by color and by a calculated integer number.
-  Score KingDanger[COLOR_NB][128];
+  // KingDanger[attackUnits] contains the actual king danger weighted
+  // scores, indexed by a calculated integer number.
+  Score KingDanger[128];
 
 
   // apply_weight() weighs score 'v' by weight 'w' trying to prevent overflow
@@ -499,7 +501,7 @@ namespace {
 
         // Finally, extract the king danger score from the KingDanger[]
         // array and subtract the score from evaluation.
-        score -= KingDanger[Us == Search::RootColor][attackUnits];
+        score -= KingDanger[attackUnits];
     }
 
     if (Trace)
@@ -517,17 +519,10 @@ namespace {
 
     const Color Them = (Us == WHITE ? BLACK : WHITE);
 
-    Bitboard b, undefendedMinors, weakEnemies;
+    Bitboard b, weakEnemies;
     Score score = SCORE_ZERO;
 
-    // Undefended minors get penalized even if they are not under attack
-    undefendedMinors =  pos.pieces(Them, BISHOP, KNIGHT)
-                      & ~ei.attackedBy[Them][ALL_PIECES];
-
-    if (undefendedMinors)
-        score += UndefendedMinor;
-
-    // Enemy pieces not defended by a pawn and under our attack
+    // Enemies not defended by a pawn and under our attack
     weakEnemies =  pos.pieces(Them)
                  & ~ei.attackedBy[Them][PAWN]
                  & ei.attackedBy[Us][ALL_PIECES];
@@ -535,13 +530,18 @@ namespace {
     // Add a bonus according if the attacking pieces are minor or major
     if (weakEnemies)
     {
-        b = weakEnemies & (ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
+        b = weakEnemies & (ei.attackedBy[Us][PAWN] | ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP]);
         if (b)
             score += Threat[0][type_of(pos.piece_on(lsb(b)))];
 
         b = weakEnemies & (ei.attackedBy[Us][ROOK] | ei.attackedBy[Us][QUEEN]);
         if (b)
             score += Threat[1][type_of(pos.piece_on(lsb(b)))];
+
+        b = weakEnemies & ~ei.attackedBy[Them][ALL_PIECES];
+        if (b)
+            score += more_than_one(b) ? Hanging[Us != pos.side_to_move()] * popcount<Max15>(b)
+                                      : Hanging[Us == pos.side_to_move()];
     }
 
     if (Trace)
@@ -779,11 +779,11 @@ namespace {
              sf = ScaleFactor(50 * sf / SCALE_FACTOR_NORMAL);
     }
 
-    // Interpolate between a middlegame and an endgame score, scaling by 'sf'
+    // Interpolate between a middlegame and a (scaled by 'sf') endgame score
     Value v =  mg_value(score) * int(ei.mi->game_phase())
-             + eg_value(score) * int(sf) / SCALE_FACTOR_NORMAL * int(PHASE_MIDGAME - ei.mi->game_phase());
+             + eg_value(score) * int(PHASE_MIDGAME - ei.mi->game_phase()) * sf / SCALE_FACTOR_NORMAL;
 
-    v /= PHASE_MIDGAME;
+    v /= int(PHASE_MIDGAME);
 
     // In case of tracing add all single evaluation contributions for both white and black
     if (Trace)
@@ -902,8 +902,7 @@ namespace Eval {
     Weights[PawnStructure]  = weight_option("Pawn Structure (Midgame)", "Pawn Structure (Endgame)", WeightsInternal[PawnStructure]);
     Weights[PassedPawns]    = weight_option("Passed Pawns (Midgame)", "Passed Pawns (Endgame)", WeightsInternal[PassedPawns]);
     Weights[Space]          = weight_option("Space", "Space", WeightsInternal[Space]);
-    Weights[KingDangerUs]   = weight_option("Cowardice", "Cowardice", WeightsInternal[KingDangerUs]);
-    Weights[KingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[KingDangerThem]);
+    Weights[KingSafety]     = weight_option("King Safety", "King Safety", WeightsInternal[KingSafety]);
 
     const double MaxSlope = 30;
     const double Peak = 1280;
@@ -911,9 +910,7 @@ namespace Eval {
     for (int t = 0, i = 1; i < 100; ++i)
     {
         t = int(std::min(Peak, std::min(0.4 * i * i, t + MaxSlope)));
-
-        KingDanger[1][i] = apply_weight(make_score(t, 0), Weights[KingDangerUs]);
-        KingDanger[0][i] = apply_weight(make_score(t, 0), Weights[KingDangerThem]);
+        KingDanger[i] = apply_weight(make_score(t, 0), Weights[KingSafety]);
     }
   }