]> git.sesse.net Git - stockfish/blobdiff - src/evaluate.cpp
Get rid of an evaluate_pieces() overload
[stockfish] / src / evaluate.cpp
index 99e9f0475281111fff761ad0f4f0b0f33e7e3968..e53af1037e523bc101eece2152fcbf56874a2f20 100644 (file)
@@ -91,7 +91,7 @@ namespace {
 
   // Evaluation weights, initialized from UCI options
   enum { Mobility, PawnStructure, PassedPawns, Space, KingDangerUs, KingDangerThem };
-  Score Weights[6];
+  struct Weight { int mg, eg; } Weights[6];
 
   typedef Value V;
   #define S(mg, eg) make_score(mg, eg)
@@ -119,8 +119,8 @@ namespace {
     { S(-17,-33), S(-11,-16), S(-5,  0), S( 1, 16), S( 7, 32), S(13, 48), // Rooks
       S( 18, 64), S( 22, 80), S(26, 96), S(29,109), S(31,115), S(33,119),
       S( 35,122), S( 36,123), S(37,124) },
-    { S(-12,-20), S( -8,-13), S(-5, -7), S(-2, -1), S( 1,  5), S( 4, 11), // Queens
-      S(  7, 17), S( 10, 23), S(13, 29), S(16, 34), S(18, 38), S(20, 40),
+    { S(-12,-20), S( -8,-13), S(-5, -7), S( 0,  0), S( 6, 10), S(11, 19), // Queens
+      S( 13, 29), S( 18, 38), S(20, 40), S(21, 41), S(22, 41), S(22, 41),
       S( 22, 41), S( 23, 41), S(24, 41), S(25, 41), S(25, 41), S(25, 41),
       S( 25, 41), S( 25, 41), S(25, 41), S(25, 41), S(25, 41), S(25, 41),
       S( 25, 41), S( 25, 41), S(25, 41), S(25, 41) }
@@ -162,9 +162,7 @@ namespace {
 
   const Score Tempo            = make_score(24, 11);
   const Score RookOn7th        = make_score(11, 20);
-  const Score QueenOn7th       = make_score( 3,  8);
   const Score RookOnPawn       = make_score(10, 28);
-  const Score QueenOnPawn      = make_score( 4, 20);
   const Score RookOpenFile     = make_score(43, 21);
   const Score RookSemiopenFile = make_score(19, 10);
   const Score BishopPawns      = make_score( 8, 12);
@@ -173,6 +171,7 @@ namespace {
   const Score UndefendedMinor  = make_score(25, 10);
   const Score TrappedRook      = make_score(90,  0);
   const Score Unstoppable      = make_score( 0, 20);
+  const Score LowMobPenalty    = make_score(40, 20);
 
   // Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by
   // a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only
@@ -188,6 +187,8 @@ namespace {
     (FileCBB | FileDBB | FileEBB | FileFBB) & (Rank7BB | Rank6BB | Rank5BB)
   };
 
+  const Bitboard EdgeBB = Rank1BB | Rank8BB | FileABB | FileHBB;
+
   // King danger constants and variables. The king danger scores are taken
   // from KingDanger[]. Various little "meta-bonuses" measuring the strength
   // of the enemy attack are added up into an integer, which is used as an
@@ -215,8 +216,8 @@ namespace {
   template<Color Us>
   void init_eval_info(const Position& pos, EvalInfo& ei);
 
-  template<Color Us, bool Trace>
-  Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility);
+  template<PieceType Pt, Color Us, bool Trace>
+  Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility, Bitboard* mobilityArea);
 
   template<Color Us, bool Trace>
   Score evaluate_king(const Position& pos, const EvalInfo& ei);
@@ -233,8 +234,8 @@ namespace {
   Score evaluate_unstoppable_pawns(const Position& pos, Color us, const EvalInfo& ei);
 
   Value interpolate(const Score& v, Phase ph, ScaleFactor sf);
-  Score apply_weight(Score v, Score w);
-  Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight);
+  Score apply_weight(Score v, const Weight& w);
+  Weight weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight);
 }
 
 
@@ -318,9 +319,21 @@ Value do_evaluate(const Position& pos) {
   init_eval_info<WHITE>(pos, ei);
   init_eval_info<BLACK>(pos, ei);
 
+  // Do not include in mobility squares protected by enemy pawns or occupied by our pieces
+  Bitboard mobilityArea[] = { ~(ei.attackedBy[BLACK][PAWN] | pos.pieces(WHITE, PAWN, KING)),
+                              ~(ei.attackedBy[WHITE][PAWN] | pos.pieces(BLACK, PAWN, KING)) };
+
   // Evaluate pieces and mobility
-  score +=  evaluate_pieces<WHITE, Trace>(pos, ei, mobility)
-          - evaluate_pieces<BLACK, Trace>(pos, ei, mobility);
+  score += evaluate_pieces<KNIGHT, WHITE, Trace>(pos, ei, mobility, mobilityArea);
+
+  // Sum up all attacked squares (updated in evaluate_pieces)
+  ei.attackedBy[WHITE][ALL_PIECES] =  ei.attackedBy[WHITE][PAWN]   | ei.attackedBy[WHITE][KNIGHT]
+                                    | ei.attackedBy[WHITE][BISHOP] | ei.attackedBy[WHITE][ROOK]
+                                    | ei.attackedBy[WHITE][QUEEN]  | ei.attackedBy[WHITE][KING];
+
+  ei.attackedBy[BLACK][ALL_PIECES] =  ei.attackedBy[BLACK][PAWN]   | ei.attackedBy[BLACK][KNIGHT]
+                                    | ei.attackedBy[BLACK][BISHOP] | ei.attackedBy[BLACK][ROOK]
+                                    | ei.attackedBy[BLACK][QUEEN]  | ei.attackedBy[BLACK][KING];
 
   score += apply_weight(mobility[WHITE] - mobility[BLACK], Weights[Mobility]);
 
@@ -383,6 +396,8 @@ Value do_evaluate(const Position& pos) {
       Tracing::add_term(Tracing::PST, pos.psq_score());
       Tracing::add_term(Tracing::IMBALANCE, ei.mi->material_value());
       Tracing::add_term(PAWN, ei.pi->pawns_value());
+      Tracing::add_term(Tracing::MOBILITY, apply_weight(mobility[WHITE], Weights[Mobility])
+                                         , apply_weight(mobility[BLACK], Weights[Mobility]));
       Score w = ei.mi->space_weight() * evaluate_space<WHITE>(pos, ei);
       Score b = ei.mi->space_weight() * evaluate_space<BLACK>(pos, ei);
       Tracing::add_term(Tracing::SPACE, apply_weight(w, Weights[Space]), apply_weight(b, Weights[Space]));
@@ -452,7 +467,7 @@ Value do_evaluate(const Position& pos) {
   // evaluate_pieces() assigns bonuses and penalties to the pieces of a given color
 
   template<PieceType Pt, Color Us, bool Trace>
-  Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility, Bitboard mobilityArea) {
+  Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility, Bitboard* mobilityArea) {
 
     Bitboard b;
     Square s;
@@ -484,11 +499,19 @@ Value do_evaluate(const Position& pos) {
                 ei.kingAdjacentZoneAttacksCount[Us] += popcount<Max15>(bb);
         }
 
-        int mob = Pt != QUEEN ? popcount<Max15>(b & mobilityArea)
-                              : popcount<Full >(b & mobilityArea);
+        if (Pt == QUEEN)
+            b &= ~(  ei.attackedBy[Them][KNIGHT]
+                   | ei.attackedBy[Them][BISHOP]
+                   | ei.attackedBy[Them][ROOK]);
+
+        int mob = Pt != QUEEN ? popcount<Max15>(b & mobilityArea[Us])
+                              : popcount<Full >(b & mobilityArea[Us]);
 
         mobility[Us] += MobilityBonus[Pt][mob];
 
+        if (mob <= 1 && (EdgeBB & s))
+            score -= LowMobPenalty;
+
         // Decrease score if we are attacked by an enemy pawn. The remaining part
         // of threat evaluation must be done later when we have full attack info.
         if (ei.attackedBy[Them][PAWN] & s)
@@ -514,23 +537,21 @@ Value do_evaluate(const Position& pos) {
                 score += MinorBehindPawn;
         }
 
-        if (  (Pt == ROOK || Pt == QUEEN)
-            && relative_rank(Us, s) >= RANK_5)
+        if (Pt == ROOK)
         {
-            // Major piece on 7th rank and enemy king trapped on 8th
+            // Rook on 7th rank and enemy king trapped on 8th
             if (   relative_rank(Us, s) == RANK_7
                 && relative_rank(Us, pos.king_square(Them)) == RANK_8)
-                score += Pt == ROOK ? RookOn7th : QueenOn7th;
+                score += RookOn7th;
 
-            // Major piece attacking enemy pawns on the same rank/file
-            Bitboard pawns = pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s];
-            if (pawns)
-                score += popcount<Max15>(pawns) * (Pt == ROOK ? RookOnPawn : QueenOnPawn);
-        }
+            // Rook piece attacking enemy pawns on the same rank/file
+            if (relative_rank(Us, s) >= RANK_5)
+            {
+                Bitboard pawns = pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s];
+                if (pawns)
+                    score += popcount<Max15>(pawns) * RookOnPawn;
+            }
 
-        // Special extra evaluation for rooks
-        if (Pt == ROOK)
-        {
             // Give a bonus for a rook on a open or semi-open file
             if (ei.pi->semiopen(Us, file_of(s)))
                 score += ei.pi->semiopen(Them, file_of(s)) ? RookOpenFile : RookSemiopenFile;
@@ -566,36 +587,16 @@ Value do_evaluate(const Position& pos) {
     if (Trace)
         Tracing::terms[Us][Pt] = score;
 
-    return score;
-  }
-
-
-  // evaluate_pieces() assigns bonuses and penalties to all the
-  // pieces of a given color.
-
-  template<Color Us, bool Trace>
-  Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score* mobility) {
-
-    const Color Them = (Us == WHITE ? BLACK : WHITE);
+    const PieceType NextPt = (Us == WHITE ? Pt : PieceType(Pt + 1));
 
-    // Do not include in mobility squares protected by enemy pawns or occupied by our pieces
-    const Bitboard mobilityArea = ~(ei.attackedBy[Them][PAWN] | pos.pieces(Us, PAWN, KING));
-
-    Score score =  evaluate_pieces<KNIGHT, Us, Trace>(pos, ei, mobility, mobilityArea)
-                 + evaluate_pieces<BISHOP, Us, Trace>(pos, ei, mobility, mobilityArea)
-                 + evaluate_pieces<ROOK,   Us, Trace>(pos, ei, mobility, mobilityArea)
-                 + evaluate_pieces<QUEEN,  Us, Trace>(pos, ei, mobility, mobilityArea);
-
-    // Sum up all attacked squares (updated in evaluate_pieces)
-    ei.attackedBy[Us][ALL_PIECES] =  ei.attackedBy[Us][PAWN]   | ei.attackedBy[Us][KNIGHT]
-                                   | ei.attackedBy[Us][BISHOP] | ei.attackedBy[Us][ROOK]
-                                   | ei.attackedBy[Us][QUEEN]  | ei.attackedBy[Us][KING];
-    if (Trace)
-        Tracing::terms[Us][Tracing::MOBILITY] = apply_weight(mobility[Us], Weights[Mobility]);
-
-    return score;
+    return score - evaluate_pieces<NextPt, Them, Trace>(pos, ei, mobility, mobilityArea);
   }
 
+  template<>
+  Score evaluate_pieces<KING, WHITE, false>(const Position&, EvalInfo&, Score*, Bitboard*) { return SCORE_ZERO; }
+  template<>
+  Score evaluate_pieces<KING, WHITE,  true>(const Position&, EvalInfo&, Score*, Bitboard*) { return SCORE_ZERO; }
+
 
   // evaluate_king() assigns bonuses and penalties to a king of a given color
 
@@ -629,6 +630,7 @@ Value do_evaluate(const Position& pos) {
         // the pawn shelter (current 'score' value).
         attackUnits =  std::min(20, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2)
                      + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + popcount<Max15>(undefended))
+                     + 2 * (ei.pinnedPieces[Us] != 0)
                      - mg_value(score) / 32;
 
         // Analyse the enemy's safe queen contact checks. Firstly, find the
@@ -924,28 +926,25 @@ Value do_evaluate(const Position& pos) {
   }
 
   // apply_weight() weights score v by score w trying to prevent overflow
-  Score apply_weight(Score v, Score w) {
+  Score apply_weight(Score v, const Weight& w) {
 
-    return make_score((int(mg_value(v)) * mg_value(w)) / 0x100,
-                      (int(eg_value(v)) * eg_value(w)) / 0x100);
+    return make_score(mg_value(v) * w.mg / 256, eg_value(v) * w.eg / 256);
   }
 
   // weight_option() computes the value of an evaluation weight, by combining
   // two UCI-configurable weights (midgame and endgame) with an internal weight.
 
-  Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight) {
-
-    // Scale option value from 100 to 256
-    int mg = Options[mgOpt] * 256 / 100;
-    int eg = Options[egOpt] * 256 / 100;
+  Weight weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight) {
 
-    return apply_weight(make_score(mg, eg), internalWeight);
+    Weight w = { Options[mgOpt] * mg_value(internalWeight) / 100,
+                 Options[egOpt] * eg_value(internalWeight) / 100 };
+    return w;
   }
 
 
   // Tracing function definitions
 
-  double Tracing::to_cp(Value v) { return double(v) / PawnValueMg; }
+  double Tracing::to_cp(Value v) { return double(v) / PawnValueEg; }
 
   void Tracing::add_term(int idx, Score wScore, Score bScore) {
 
@@ -961,8 +960,8 @@ Value do_evaluate(const Position& pos) {
     switch (idx) {
     case PST: case IMBALANCE: case PAWN: case TOTAL:
         ss << std::setw(20) << name << " |   ---   --- |   ---   --- | "
-           << std::setw(6)  << to_cp(mg_value(wScore - bScore)) << " "
-           << std::setw(6)  << to_cp(eg_value(wScore - bScore)) << " \n";
+           << std::setw(5)  << to_cp(mg_value(wScore - bScore)) << " "
+           << std::setw(5)  << to_cp(eg_value(wScore - bScore)) << " \n";
         break;
     default:
         ss << std::setw(20) << name << " | " << std::noshowpos
@@ -970,9 +969,8 @@ Value do_evaluate(const Position& pos) {
            << std::setw(5)  << to_cp(eg_value(wScore)) << " | "
            << std::setw(5)  << to_cp(mg_value(bScore)) << " "
            << std::setw(5)  << to_cp(eg_value(bScore)) << " | "
-           << std::showpos
-           << std::setw(6)  << to_cp(mg_value(wScore - bScore)) << " "
-           << std::setw(6)  << to_cp(eg_value(wScore - bScore)) << " \n";
+           << std::setw(5)  << to_cp(mg_value(wScore - bScore)) << " "
+           << std::setw(5)  << to_cp(eg_value(wScore - bScore)) << " \n";
     }
   }
 
@@ -981,12 +979,13 @@ Value do_evaluate(const Position& pos) {
     std::memset(terms, 0, sizeof(terms));
 
     Value v = do_evaluate<true>(pos);
+    v = pos.side_to_move() == WHITE ? v : -v; // White's point of view
 
     std::stringstream ss;
-    ss << std::showpoint << std::showpos << std::fixed << std::setprecision(2)
-       << "           Eval term |    White    |    Black    |     Total     \n"
-       << "                     |   MG    EG  |   MG    EG  |   MG     EG   \n"
-       << "---------------------+-------------+-------------+---------------\n";
+    ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2)
+       << "           Eval term |    White    |    Black    |    Total    \n"
+       << "                     |   MG    EG  |   MG    EG  |   MG    EG  \n"
+       << "---------------------+-------------+-------------+-------------\n";
 
     format_row(ss, "Material, PST, Tempo", PST);
     format_row(ss, "Material imbalance", IMBALANCE);
@@ -1001,14 +1000,10 @@ Value do_evaluate(const Position& pos) {
     format_row(ss, "Passed pawns", PASSED);
     format_row(ss, "Space", SPACE);
 
-    ss << "---------------------+-------------+-------------+---------------\n";
+    ss << "---------------------+-------------+-------------+-------------\n";
     format_row(ss, "Total", TOTAL);
 
-    ss << "\nScaling: " << std::noshowpos
-       << std::setw(6) << 100.0 * ei.mi->game_phase() / 128.0 << "% MG, "
-       << std::setw(6) << 100.0 * (1.0 - ei.mi->game_phase() / 128.0) << "% * "
-       << std::setw(6) << (100.0 * sf) / SCALE_FACTOR_NORMAL << "% EG.\n"
-       << "Total evaluation: " << to_cp(v);
+    ss << "\nTotal Evaluation: " << to_cp(v) << " (white side)\n";
 
     return ss.str();
   }