]> git.sesse.net Git - stockfish/blobdiff - src/evaluate.cpp
Mobility is zero for a pinned piece
[stockfish] / src / evaluate.cpp
index 6a6f98732d8bd87b777aaf881ae86d63d431c7f0..a01a3c2c08c4b4089296129a0291734b548af04b 100644 (file)
@@ -272,11 +272,11 @@ namespace {
   uint8_t BitCount8Bit[256];
 
   // Function prototypes
-  void evaluate_knight(const Position &p, Square s, Color us, EvalInfo &ei);
-  void evaluate_bishop(const Position &p, Square s, Color us, EvalInfo &ei);
-  void evaluate_rook(const Position &p, Square s, Color us, EvalInfo &ei);
-  void evaluate_queen(const Position &p, Square s, Color us, EvalInfo &ei);
-  void evaluate_king(const Position &p, Square s, Color us, EvalInfo &ei);
+  void evaluate_knight(const Position& p, Square s, Color us, Bitboard pinned, EvalInfo& ei);
+  void evaluate_bishop(const Position& p, Square s, Color us, Bitboard pinned, EvalInfo& ei);
+  void evaluate_rook(const Position& p, Square s, Color us, Bitboard pinned, EvalInfo& ei);
+  void evaluate_queen(const Position& p, Square s, Color us, Bitboard pinned, EvalInfo& ei);
+  void evaluate_king(const Position& p, Square s, Color us, EvalInfo& ei);
 
   void evaluate_passed_pawns(const Position &pos, EvalInfo &ei);
   void evaluate_trapped_bishop_a7h7(const Position &pos, Square s, Color us,
@@ -352,21 +352,23 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) {
   // Evaluate pieces
   for (Color c = WHITE; c <= BLACK; c++)
   {
+    Bitboard pinned = pos.pinned_pieces(c);
+
     // Knights
     for (int i = 0; i < pos.piece_count(c, KNIGHT); i++)
-        evaluate_knight(pos, pos.piece_list(c, KNIGHT, i), c, ei);
+        evaluate_knight(pos, pos.piece_list(c, KNIGHT, i), c, pinned, ei);
 
     // Bishops
     for (int i = 0; i < pos.piece_count(c, BISHOP); i++)
-        evaluate_bishop(pos, pos.piece_list(c, BISHOP, i), c, ei);
+        evaluate_bishop(pos, pos.piece_list(c, BISHOP, i), c, pinned, ei);
 
     // Rooks
     for (int i = 0; i < pos.piece_count(c, ROOK); i++)
-        evaluate_rook(pos, pos.piece_list(c, ROOK, i), c, ei);
+        evaluate_rook(pos, pos.piece_list(c, ROOK, i), c, pinned, ei);
 
     // Queens
     for(int i = 0; i < pos.piece_count(c, QUEEN); i++)
-        evaluate_queen(pos, pos.piece_list(c, QUEEN, i), c, ei);
+        evaluate_queen(pos, pos.piece_list(c, QUEEN, i), c, pinned, ei);
 
     // Special pattern: trapped bishops on a7/h7/a2/h2
     Bitboard b = pos.bishops(c) & MaskA7H7[c];
@@ -483,7 +485,7 @@ Value quick_evaluate(const Position &pos) {
   assert(pos.is_ok());
 
   static const
-  ScaleFactor sf[2] = {SCALE_FACTOR_NORMAL, SCALE_FACTOR_NORMAL};  
+  ScaleFactor sf[2] = {SCALE_FACTOR_NORMAL, SCALE_FACTOR_NORMAL};
 
   Value mgv = pos.mg_value();
   Value egv = pos.eg_value();
@@ -559,37 +561,53 @@ namespace {
 
   // evaluate_common() computes terms common to all pieces attack
 
-  int evaluate_common(const Position&p, const Bitboard& b, Color us, EvalInfo& ei,
-                       int AttackWeight, const Value* mgBonus, const Value* egBonus,
-                       Square s = SQ_NONE, const Value* OutpostBonus = NULL) {
+  template<PieceType Piece>
+  int evaluate_common(const Position& p, const Bitboard& b, Color us, Bitboard pinned, EvalInfo& ei, Square s = SQ_NONE) {
+
+    static const int AttackWeight[] = { 0, 0, KnightAttackWeight, BishopAttackWeight, RookAttackWeight, QueenAttackWeight };
+    static const Value* MgBonus[] = { 0, 0, MidgameKnightMobilityBonus, MidgameBishopMobilityBonus, MidgameRookMobilityBonus, MidgameQueenMobilityBonus };
+    static const Value* EgBonus[] = { 0, 0, EndgameKnightMobilityBonus, EndgameBishopMobilityBonus, EndgameRookMobilityBonus, EndgameQueenMobilityBonus };
+    static const Value* OutpostBonus[] = { 0, 0, KnightOutpostBonus, BishopOutpostBonus, 0, 0 };
 
+    int mob;
     Color them = opposite_color(us);
 
+    // Update attack info
+    ei.attackedBy[us][Piece] |= b;
+
     // King attack
     if (b & ei.kingZone[us])
     {
         ei.kingAttackersCount[us]++;
-        ei.kingAttackersWeight[us] += AttackWeight;
+        ei.kingAttackersWeight[us] += AttackWeight[Piece];
         Bitboard bb = (b & ei.attackedBy[them][KING]);
         if (bb)
             ei.kingAdjacentZoneAttacksCount[us] += count_1s_max_15(bb);
     }
 
-    // Remove squares protected by enemy pawns
-    Bitboard bb = (b & ~ei.attackedBy[them][PAWN]);
+    if (pinned && bit_is_set(pinned, s))
+        mob = 0;
+    else
+    {
+        // Remove squares protected by enemy pawns
+        Bitboard bb = (b & ~ei.attackedBy[them][PAWN]);
+
+        // Mobility
+        mob = (Piece != QUEEN ? count_1s_max_15(bb & ~p.pieces_of_color(us))
+                              : count_1s(bb & ~p.pieces_of_color(us)));
 
-    // Mobility
-    int mob = count_1s_max_15(bb & ~p.pieces_of_color(us));
-    ei.mgMobility += Sign[us] * mgBonus[mob];
-    ei.egMobility += Sign[us] * egBonus[mob];
+        ei.mgMobility += Sign[us] * MgBonus[Piece][mob];
+        ei.egMobility += Sign[us] * EgBonus[Piece][mob];
+    }
 
     // Bishop and Knight outposts
-    if (!OutpostBonus || !p.square_is_weak(s, them))
+    if (  (Piece != BISHOP && Piece != KNIGHT) // compile time condition
+        || !p.square_is_weak(s, them))
         return mob;
 
     // Initial bonus based on square
     Value v, bonus;
-    v = bonus = OutpostBonus[relative_square(us, s)];
+    v = bonus = OutpostBonus[Piece][relative_square(us, s)];
 
     // Increase bonus if supported by pawn, especially if the opponent has
     // no minor piece which can exchange the outpost piece
@@ -609,42 +627,34 @@ namespace {
   // evaluate_knight() assigns bonuses and penalties to a knight of a given
   // color on a given square.
 
-  void evaluate_knight(const Position &p, Square s, Color us, EvalInfo &ei) {
+  void evaluate_knight(const Position& p, Square s, Color us, Bitboard pinned, EvalInfo& ei) {
 
-    Bitboard b = p.piece_attacks<KNIGHT>(s);
-    ei.attackedBy[us][KNIGHT] |= b;
-
-    // King attack, mobility and outposts
-    evaluate_common(p, b, us, ei, KnightAttackWeight, MidgameKnightMobilityBonus,
-                    EndgameKnightMobilityBonus, s, KnightOutpostBonus);
+    // Attacks, mobility and outposts
+    evaluate_common<KNIGHT>(p, p.piece_attacks<KNIGHT>(s), us, pinned, ei, s);
   }
 
 
   // evaluate_bishop() assigns bonuses and penalties to a bishop of a given
   // color on a given square.
 
-  void evaluate_bishop(const Position &p, Square s, Color us, EvalInfo &ei) {
+  void evaluate_bishop(const Position& p, Square s, Color us, Bitboard pinned, EvalInfo& ei) {
 
     Bitboard b = bishop_attacks_bb(s, p.occupied_squares() & ~p.queens(us));
-    ei.attackedBy[us][BISHOP] |= b;
 
-    // King attack, mobility and outposts
-    evaluate_common(p, b, us, ei, BishopAttackWeight, MidgameBishopMobilityBonus,
-                    EndgameBishopMobilityBonus, s, BishopOutpostBonus);
+    // Attacks, mobility and outposts
+    evaluate_common<BISHOP>(p, b, us, pinned, ei, s);
   }
 
 
   // evaluate_rook() assigns bonuses and penalties to a rook of a given
   // color on a given square.
 
-  void evaluate_rook(const Position &p, Square s, Color us, EvalInfo &ei) {
+  void evaluate_rook(const Position& p, Square s, Color us, Bitboard pinned, EvalInfo& ei) {
 
     Bitboard b = rook_attacks_bb(s, p.occupied_squares() & ~p.rooks_and_queens(us));
-    ei.attackedBy[us][ROOK] |= b;
 
-    // King attack and mobility
-    int mob = evaluate_common(p, b, us, ei, RookAttackWeight, MidgameRookMobilityBonus,
-                              EndgameRookMobilityBonus);
+    // Attacks and mobility
+    int mob = evaluate_common<ROOK>(p, b, us, pinned, ei);
 
     // Rook on 7th rank
     Color them = opposite_color(us);
@@ -703,14 +713,10 @@ namespace {
   // evaluate_queen() assigns bonuses and penalties to a queen of a given
   // color on a given square.
 
-  void evaluate_queen(const Position &p, Square s, Color us, EvalInfo &ei) {
-
-    Bitboard b = p.piece_attacks<QUEEN>(s);
-    ei.attackedBy[us][QUEEN] |= b;
+  void evaluate_queen(const Position& p, Square s, Color us, Bitboard pinned, EvalInfo& ei) {
 
-    // King attack and mobility
-    evaluate_common(p, b, us, ei, QueenAttackWeight, MidgameQueenMobilityBonus,
-                    EndgameQueenMobilityBonus);
+    // Attacks and mobility
+    evaluate_common<QUEEN>(p, p.piece_attacks<QUEEN>(s), us, pinned, ei);
 
     // Queen on 7th rank
     Color them = opposite_color(us);
@@ -731,7 +737,7 @@ namespace {
   // evaluate_king() assigns bonuses and penalties to a king of a given
   // color on a given square.
 
-  void evaluate_king(const Position &p, Square s, Color us, EvalInfo &ei) {
+  void evaluate_king(const Position& p, Square s, Color us, EvalInfo& ei) {
 
     int shelter = 0, sign = Sign[us];
 
@@ -814,7 +820,7 @@ namespace {
                             && !bit_is_set(p.pinned_pieces(them), from)
                             && !(rook_attacks_bb(to, occ & ClearMaskBB[from]) & p.rooks_and_queens(us))
                             && !(rook_attacks_bb(to, occ & ClearMaskBB[from]) & p.rooks_and_queens(us)))
-                            
+
                             ei.mateThreat[them] = make_move(from, to);
                     }
                 }
@@ -932,50 +938,53 @@ namespace {
             Value ebonus = Value(10 + r * r * 10);
 
             // Adjust bonus based on king proximity
-            ebonus -= Value(square_distance(ourKingSq, blockSq) * 3 * tr);
-            ebonus -= Value(square_distance(ourKingSq, blockSq + pawn_push(us)) * 1 * tr);
-            ebonus += Value(square_distance(theirKingSq, blockSq) * 6 * tr);
-
-            // If the pawn is free to advance, increase bonus
-            if (pos.square_is_empty(blockSq))
+            if (tr != 0)
             {
-                b2 = squares_in_front_of(us, s);
-                b3 = b2 & ei.attacked_by(them);
-                b4 = b2 & ei.attacked_by(us);
+                ebonus -= Value(square_distance(ourKingSq, blockSq) * 3 * tr);
+                ebonus -= Value(square_distance(ourKingSq, blockSq + pawn_push(us)) * 1 * tr);
+                ebonus += Value(square_distance(theirKingSq, blockSq) * 6 * tr);
 
-                // If there is an enemy rook or queen attacking the pawn from behind,
-                // add all X-ray attacks by the rook or queen.
-                if (    bit_is_set(ei.attacked_by(them,ROOK) | ei.attacked_by(them,QUEEN),s)
-                    && (squares_behind(us, s) & pos.rooks_and_queens(them)))
-                    b3 = b2;
-
-                if ((b2 & pos.pieces_of_color(them)) == EmptyBoardBB)
+                // If the pawn is free to advance, increase bonus
+                if (pos.square_is_empty(blockSq))
                 {
-                    // There are no enemy pieces in the pawn's path! Are any of the
-                    // squares in the pawn's path attacked by the enemy?
-                    if (b3 == EmptyBoardBB)
-                        // No enemy attacks, huge bonus!
-                        ebonus += Value(tr * (b2 == b4 ? 17 : 15));
+                    b2 = squares_in_front_of(us, s);
+                    b3 = b2 & ei.attacked_by(them);
+                    b4 = b2 & ei.attacked_by(us);
+
+                    // If there is an enemy rook or queen attacking the pawn from behind,
+                    // add all X-ray attacks by the rook or queen.
+                    if (    bit_is_set(ei.attacked_by(them,ROOK) | ei.attacked_by(them,QUEEN),s)
+                        && (squares_behind(us, s) & pos.rooks_and_queens(them)))
+                        b3 = b2;
+
+                    if ((b2 & pos.pieces_of_color(them)) == EmptyBoardBB)
+                    {
+                        // There are no enemy pieces in the pawn's path! Are any of the
+                        // squares in the pawn's path attacked by the enemy?
+                        if (b3 == EmptyBoardBB)
+                            // No enemy attacks, huge bonus!
+                            ebonus += Value(tr * (b2 == b4 ? 17 : 15));
+                        else
+                            // OK, there are enemy attacks. Are those squares which are
+                            // attacked by the enemy also attacked by us?  If yes, big bonus
+                            // (but smaller than when there are no enemy attacks), if no,
+                            // somewhat smaller bonus.
+                            ebonus += Value(tr * ((b3 & b4) == b3 ? 13 : 8));
+                    }
                     else
-                        // OK, there are enemy attacks. Are those squares which are
-                        // attacked by the enemy also attacked by us?  If yes, big bonus
-                        // (but smaller than when there are no enemy attacks), if no,
-                        // somewhat smaller bonus.
-                        ebonus += Value(tr * ((b3 & b4) == b3 ? 13 : 8));
-                }
-                else
-                {
-                    // There are some enemy pieces in the pawn's path. While this is
-                    // sad, we still assign a moderate bonus if all squares in the path
-                    // which are either occupied by or attacked by enemy pieces are
-                    // also attacked by us.
-                    if (((b3 | (b2 & pos.pieces_of_color(them))) & ~b4) == EmptyBoardBB)
-                        ebonus += Value(tr * 6);
+                    {
+                        // There are some enemy pieces in the pawn's path. While this is
+                        // sad, we still assign a moderate bonus if all squares in the path
+                        // which are either occupied by or attacked by enemy pieces are
+                        // also attacked by us.
+                        if (((b3 | (b2 & pos.pieces_of_color(them))) & ~b4) == EmptyBoardBB)
+                            ebonus += Value(tr * 6);
+                    }
+                    // At last, add a small bonus when there are no *friendly* pieces
+                    // in the pawn's path.
+                    if ((b2 & pos.pieces_of_color(us)) == EmptyBoardBB)
+                        ebonus += Value(tr);
                 }
-                // At last, add a small bonus when there are no *friendly* pieces
-                // in the pawn's path.
-                if ((b2 & pos.pieces_of_color(us)) == EmptyBoardBB)
-                    ebonus += Value(tr);
             }
 
             // If the pawn is supported by a friendly pawn, increase bonus
@@ -1018,8 +1027,8 @@ namespace {
             // value if the other side has a rook or queen.
             if (square_file(s) == FILE_A || square_file(s) == FILE_H)
             {
-                if(   pos.non_pawn_material(them) == KnightValueMidgame // FIXME should be <= ???
-                   && pos.piece_count(them, KNIGHT) == 1)
+                if(   pos.non_pawn_material(them) <= KnightValueMidgame
+                   && pos.piece_count(them, KNIGHT) <= 1)
                     ebonus += ebonus / 4;
                 else if(pos.rooks_and_queens(them))
                     ebonus -= ebonus / 4;
@@ -1067,14 +1076,13 @@ namespace {
 
   void evaluate_trapped_bishop_a7h7(const Position &pos, Square s, Color us,
                                     EvalInfo &ei) {
-
     assert(square_is_ok(s));
     assert(pos.piece_on(s) == bishop_of_color(us));
 
     Square b6 = relative_square(us, (square_file(s) == FILE_A) ? SQ_B6 : SQ_G6);
     Square b8 = relative_square(us, (square_file(s) == FILE_A) ? SQ_B8 : SQ_G8);
 
-    if (   pos.piece_on(b6) == pawn_of_color(opposite_color(us))
+    if (   pos.piece_on(b6) == piece_of_color_and_type(opposite_color(us), PAWN)
         && pos.see(s, b6) < 0
         && pos.see(s, b8) < 0)
     {
@@ -1091,38 +1099,40 @@ namespace {
 
   void evaluate_trapped_bishop_a1h1(const Position &pos, Square s, Color us,
                                     EvalInfo &ei) {
-    Piece pawn = pawn_of_color(us);
+    Piece pawn = piece_of_color_and_type(us, PAWN);
     Square b2, b3, c3;
 
     assert(Chess960);
     assert(square_is_ok(s));
     assert(pos.piece_on(s) == bishop_of_color(us));
 
-    if(square_file(s) == FILE_A) {
-      b2 = relative_square(us, SQ_B2);
-      b3 = relative_square(us, SQ_B3);
-      c3 = relative_square(us, SQ_C3);
+    if (square_file(s) == FILE_A)
+    {
+        b2 = relative_square(us, SQ_B2);
+        b3 = relative_square(us, SQ_B3);
+        c3 = relative_square(us, SQ_C3);
     }
-    else {
-      b2 = relative_square(us, SQ_G2);
-      b3 = relative_square(us, SQ_G3);
-      c3 = relative_square(us, SQ_F3);
+    else
+    {
+        b2 = relative_square(us, SQ_G2);
+        b3 = relative_square(us, SQ_G3);
+        c3 = relative_square(us, SQ_F3);
     }
 
-    if(pos.piece_on(b2) == pawn) {
-      Value penalty;
+    if (pos.piece_on(b2) == pawn)
+    {
+        Value penalty;
 
-      if(!pos.square_is_empty(b3))
-        penalty = 2*TrappedBishopA1H1Penalty;
-      else if(pos.piece_on(c3) == pawn)
-        penalty = TrappedBishopA1H1Penalty;
-      else
-        penalty = TrappedBishopA1H1Penalty / 2;
+        if (!pos.square_is_empty(b3))
+            penalty = 2*TrappedBishopA1H1Penalty;
+        else if (pos.piece_on(c3) == pawn)
+            penalty = TrappedBishopA1H1Penalty;
+        else
+            penalty = TrappedBishopA1H1Penalty / 2;
 
-      ei.mgValue -= Sign[us] * penalty;
-      ei.egValue -= Sign[us] * penalty;
+        ei.mgValue -= Sign[us] * penalty;
+        ei.egValue -= Sign[us] * penalty;
     }
-
   }
 
 
@@ -1138,31 +1148,32 @@ namespace {
     Color them = opposite_color(us);
 
     // Find the safe squares for our pieces inside the area defined by
-    // SpaceMask[us].  A square is unsafe it is attacked by an enemy
+    // SpaceMask[us]. A square is unsafe it is attacked by an enemy
     // pawn, or if it is undefended and attacked by an enemy piece.
 
-    Bitboard safeSquares =
-      SpaceMask[us] & ~pos.pawns(us) & ~ei.attacked_by(them, PAWN)
-      & ~(~ei.attacked_by(us) & ei.attacked_by(them));
+    Bitboard safeSquares =   SpaceMask[us]
+                          & ~pos.pawns(us)
+                          & ~ei.attacked_by(them, PAWN)
+                          & ~(~ei.attacked_by(us) & ei.attacked_by(them));
 
     // Find all squares which are at most three squares behind some friendly
     // pawn.
     Bitboard behindFriendlyPawns = pos.pawns(us);
-    if(us == WHITE) {
-      behindFriendlyPawns |= (behindFriendlyPawns >> 8);
-      behindFriendlyPawns |= (behindFriendlyPawns >> 16);
+    if (us == WHITE)
+    {
+        behindFriendlyPawns |= (behindFriendlyPawns >> 8);
+        behindFriendlyPawns |= (behindFriendlyPawns >> 16);
     }
-    else {
-      behindFriendlyPawns |= (behindFriendlyPawns << 8);
-      behindFriendlyPawns |= (behindFriendlyPawns << 16);
+    else
+    {
+        behindFriendlyPawns |= (behindFriendlyPawns << 8);
+        behindFriendlyPawns |= (behindFriendlyPawns << 16);
     }
 
-    int space =
-      count_1s_max_15(safeSquares)
-      + count_1s_max_15(behindFriendlyPawns & safeSquares);
+    int space =  count_1s_max_15(safeSquares)
+               + count_1s_max_15(behindFriendlyPawns & safeSquares);
 
-    ei.mgValue += Sign[us] *
-      apply_weight(Value(space * ei.mi->space_weight()), WeightSpace);
+    ei.mgValue += Sign[us] * apply_weight(Value(space * ei.mi->space_weight()), WeightSpace);
   }
 
 
@@ -1203,6 +1214,7 @@ namespace {
   // an UCI-configurable weight with an internal weight.
 
   int compute_weight(int uciWeight, int internalWeight) {
+
     uciWeight = (uciWeight * 0x100) / 100;
     return (uciWeight * internalWeight) / 0x100;
   }
@@ -1255,5 +1267,4 @@ namespace {
             SafetyTable[i] = Value(peak);
     }
   }
-
 }