]> git.sesse.net Git - stockfish/blobdiff - src/evaluate.cpp
Refactor Position::pinned_pieces() to use templates
[stockfish] / src / evaluate.cpp
index 19fcd5f815c68b7822696a8ad04bb1f6623220d9..a7e5f2d5b8ccf333c8daf583c664946d2c816a8b 100644 (file)
@@ -1,13 +1,14 @@
 /*
-  Glaurung, a UCI chess playing engine.
-  Copyright (C) 2004-2008 Tord Romstad
+  Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+  Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+  Copyright (C) 2008 Marco Costalba
 
-  Glaurung is free software: you can redistribute it and/or modify
+  Stockfish is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
 
-  Glaurung is distributed in the hope that it will be useful,
+  Stockfish is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
@@ -270,7 +271,7 @@ namespace {
                                     EvalInfo &ei);
 
   inline Value apply_weight(Value v, int w);
-  Value scale_by_game_phase(Value mv, Value ev, Phase ph, ScaleFactor sf[]);
+  Value scale_by_game_phase(Value mv, Value ev, Phase ph, const ScaleFactor sf[]);
 
   int count_1s_8bit(Bitboard b);
 
@@ -322,8 +323,8 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) {
   ei.egValue += apply_weight(ei.pi->eg_value(), WeightPawnStructureEndgame);
 
   // Initialize king attack bitboards and king attack zones for both sides
-  ei.attackedBy[WHITE][KING] = pos.king_attacks(pos.king_square(WHITE));
-  ei.attackedBy[BLACK][KING] = pos.king_attacks(pos.king_square(BLACK));
+  ei.attackedBy[WHITE][KING] = pos.piece_attacks<KING>(pos.king_square(WHITE));
+  ei.attackedBy[BLACK][KING] = pos.piece_attacks<KING>(pos.king_square(BLACK));
   ei.kingZone[WHITE] = ei.attackedBy[BLACK][KING] | (ei.attackedBy[BLACK][KING] >> 8);
   ei.kingZone[BLACK] = ei.attackedBy[WHITE][KING] | (ei.attackedBy[WHITE][KING] << 8);
 
@@ -337,20 +338,20 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) {
   for (Color c = WHITE; c <= BLACK; c++)
   {
     // Knights
-    for (int i = 0; i < pos.knight_count(c); i++)
-        evaluate_knight(pos, pos.knight_list(c, i), c, ei);
+    for (int i = 0; i < pos.piece_count(c, KNIGHT); i++)
+        evaluate_knight(pos, pos.piece_list(c, KNIGHT, i), c, ei);
 
     // Bishops
-    for (int i = 0; i < pos.bishop_count(c); i++)
-        evaluate_bishop(pos, pos.bishop_list(c, i), c, ei);
+    for (int i = 0; i < pos.piece_count(c, BISHOP); i++)
+        evaluate_bishop(pos, pos.piece_list(c, BISHOP, i), c, ei);
 
     // Rooks
-    for (int i = 0; i < pos.rook_count(c); i++)
-        evaluate_rook(pos, pos.rook_list(c, i), c, ei);
+    for (int i = 0; i < pos.piece_count(c, ROOK); i++)
+        evaluate_rook(pos, pos.piece_list(c, ROOK, i), c, ei);
 
     // Queens
-    for(int i = 0; i < pos.queen_count(c); i++)
-        evaluate_queen(pos, pos.queen_list(c, i), c, ei);
+    for(int i = 0; i < pos.piece_count(c, QUEEN); i++)
+        evaluate_queen(pos, pos.piece_list(c, QUEEN, i), c, ei);
 
     // Special pattern: trapped bishops on a7/h7/a2/h2
     Bitboard b = pos.bishops(c) & MaskA7H7[c];
@@ -427,7 +428,7 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) {
       {
           // Check for KBP vs KB with only a single pawn that is almost
           // certainly a draw or at least two pawns.
-          bool one_pawn = (pos.pawn_count(WHITE) + pos.pawn_count(BLACK) == 1);
+          bool one_pawn = (pos.piece_count(WHITE, PAWN) + pos.piece_count(BLACK, PAWN) == 1);
           sf = one_pawn ? ScaleFactor(8) : ScaleFactor(32);
       }
       else
@@ -456,22 +457,18 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) {
 /// we should add scores from the pawn and material hash tables?
 
 Value quick_evaluate(const Position &pos) {
-  Color stm;
-  Value mgValue, egValue;
-  ScaleFactor factor[2] = {SCALE_FACTOR_NORMAL, SCALE_FACTOR_NORMAL};
-  Phase phase;
 
   assert(pos.is_ok());
 
-  stm = pos.side_to_move();
+  static const
+  ScaleFactor sf[2] = {SCALE_FACTOR_NORMAL, SCALE_FACTOR_NORMAL};  
 
-  mgValue = pos.mg_value();
-  egValue = pos.eg_value();
-  phase = pos.game_phase();
-
-  Value value = scale_by_game_phase(mgValue, egValue, phase, factor);
+  Value mgv = pos.mg_value();
+  Value egv = pos.eg_value();
+  Phase ph = pos.game_phase();
+  Color stm = pos.side_to_move();
 
-  return Sign[stm] * value;
+  return Sign[stm] * scale_by_game_phase(mgv, egv, ph, sf);
 }
 
 
@@ -505,9 +502,11 @@ void init_eval(int threads) {
 /// quit_eval() releases heap-allocated memory at program termination.
 
 void quit_eval() {
-  for(int i = 0; i < THREAD_MAX; i++) {
-    delete PawnTable[i];
-    delete MaterialTable[i];
+
+  for (int i = 0; i < THREAD_MAX; i++)
+  {
+      delete PawnTable[i];
+      delete MaterialTable[i];
   }
 }
 
@@ -546,11 +545,11 @@ namespace {
     // King attack
     if (b & ei.kingZone[us])
     {
-      ei.kingAttackersCount[us]++;
-      ei.kingAttackersWeight[us] += AttackWeight;
-      Bitboard bb = (b & ei.attackedBy[them][KING]);
-      if (bb)
-          ei.kingZoneAttacksCount[us] += count_1s_max_15(bb);
+        ei.kingAttackersCount[us]++;
+        ei.kingAttackersWeight[us] += AttackWeight;
+        Bitboard bb = (b & ei.attackedBy[them][KING]);
+        if (bb)
+            ei.kingAdjacentZoneAttacksCount[us] += count_1s_max_15(bb);
     }
 
     // Mobility
@@ -571,7 +570,7 @@ namespace {
     if (v && (p.pawn_attacks(them, s) & p.pawns(us)))
     {
         bonus += v / 2;
-        if (   p.knight_count(them) == 0
+        if (   p.piece_count(them, KNIGHT) == 0
             && (SquaresByColorBB[square_color(s)] & p.bishops(them)) == EmptyBoardBB)
             bonus += v;
     }
@@ -586,7 +585,7 @@ namespace {
 
   void evaluate_knight(const Position &p, Square s, Color us, EvalInfo &ei) {
 
-    Bitboard b = p.knight_attacks(s);
+    Bitboard b = p.piece_attacks<KNIGHT>(s);
     ei.attackedBy[us][KNIGHT] |= b;
 
     // King attack, mobility and outposts
@@ -681,7 +680,7 @@ namespace {
 
   void evaluate_queen(const Position &p, Square s, Color us, EvalInfo &ei) {
 
-    Bitboard b = p.queen_attacks(s);
+    Bitboard b = p.piece_attacks<QUEEN>(s);
     ei.attackedBy[us][QUEEN] |= b;
 
     // King attack and mobility
@@ -699,6 +698,10 @@ namespace {
     }
   }
 
+  inline Bitboard shiftRowsDown(const Bitboard& b, int num) {
+
+    return b >> (num << 3);
+  }
 
   // evaluate_king() assigns bonuses and penalties to a king of a given
   // color on a given square.
@@ -707,32 +710,37 @@ namespace {
 
     int shelter = 0, sign = Sign[us];
 
-    // King shelter.
-    if(relative_rank(us, s) <= RANK_4) {
-      Bitboard pawns = p.pawns(us) & this_and_neighboring_files_bb(s);
-      Rank r = square_rank(s);
-      for(int i = 0; i < 3; i++)
-        shelter += count_1s_8bit(pawns >> ((r+(i+1)*sign) * 8)) * (64>>i);
-      ei.mgValue += sign * Value(shelter);
+    // King shelter
+    if (relative_rank(us, s) <= RANK_4)
+    {
+        Bitboard pawns = p.pawns(us) & this_and_neighboring_files_bb(s);
+        Rank r = square_rank(s);
+        for (int i = 1; i < 4; i++)
+            shelter += count_1s_8bit(shiftRowsDown(pawns, r+i*sign)) * (128>>i);
+
+        ei.mgValue += sign * Value(shelter);
     }
 
     // King safety.  This is quite complicated, and is almost certainly far
     // from optimally tuned.
     Color them = opposite_color(us);
-    if(p.queen_count(them) >= 1 && ei.kingAttackersCount[them] >= 2
-       && p.non_pawn_material(them) >= QueenValueMidgame + RookValueMidgame
-       && ei.kingZoneAttacksCount[them]) {
 
+    if (   p.piece_count(them, QUEEN) >= 1
+        && ei.kingAttackersCount[them] >= 2
+        && p.non_pawn_material(them) >= QueenValueMidgame + RookValueMidgame
+        && ei.kingAdjacentZoneAttacksCount[them])
+    {
       // Is it the attackers turn to move?
       bool sente = (them == p.side_to_move());
 
       // Find the attacked squares around the king which has no defenders
-      // apart from the king itself:
+      // apart from the king itself
       Bitboard undefended =
-        ei.attacked_by(them) & ~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)
-        & ei.attacked_by(us, KING);
+             ei.attacked_by(them)       & ~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)
+          & ei.attacked_by(us, KING);
+
       Bitboard occ = p.occupied_squares(), b, b2;
 
       // Initialize the 'attackUnits' variable, which is used later on as an
@@ -741,113 +749,134 @@ namespace {
       // undefended squares around the king, the square of the king, and the
       // quality of the pawn shelter.
       int attackUnits =
-        Min((ei.kingAttackersCount[them] * ei.kingAttackersWeight[them]) / 2, 25)
-        + (ei.kingZoneAttacksCount[them] + count_1s_max_15(undefended)) * 3
-        + InitKingDanger[relative_square(us, s)] - shelter / 32;
+            Min((ei.kingAttackersCount[them] * ei.kingAttackersWeight[them]) / 2, 25)
+          + (ei.kingAdjacentZoneAttacksCount[them] + count_1s_max_15(undefended)) * 3
+          + InitKingDanger[relative_square(us, s)] - shelter / 32;
 
-      // Analyse safe queen contact checks:
+      // Analyse safe queen contact checks
       b = undefended & ei.attacked_by(them, QUEEN) & ~p.pieces_of_color(them);
-      if(b) {
+      if (b)
+      {
         Bitboard attackedByOthers =
-          ei.attacked_by(them, PAWN) | ei.attacked_by(them, KNIGHT)
-          | ei.attacked_by(them, BISHOP) | ei.attacked_by(them, ROOK);
+              ei.attacked_by(them, PAWN)   | ei.attacked_by(them, KNIGHT)
+            | ei.attacked_by(them, BISHOP) | ei.attacked_by(them, ROOK);
+
         b &= attackedByOthers;
-        if(b) {
+        if (b)
+        {
           // The bitboard b now contains the squares available for safe queen
           // contact checks.
           int count = count_1s_max_15(b);
-          attackUnits += QueenContactCheckBonus * count * (sente? 2 : 1);
+          attackUnits += QueenContactCheckBonus * count * (sente ? 2 : 1);
 
           // Is there a mate threat?
-          if(QueenContactMates && !p.is_check()) {
+          if (QueenContactMates && !p.is_check())
+          {
             Bitboard escapeSquares =
-              p.king_attacks(s) & ~p.pieces_of_color(us) & ~attackedByOthers;
-            while(b) {
-              Square from, to = pop_1st_bit(&b);
-              if(!(escapeSquares
-                   & ~queen_attacks_bb(to, occ & clear_mask_bb(s)))) {
-                // We have a mate, unless the queen is pinned or there
-                // is an X-ray attack through the queen.
-                for(int i = 0; i < p.queen_count(them); i++) {
-                  from = p.queen_list(them, i);
-                  if(bit_is_set(p.queen_attacks(from), to)
-                     && !bit_is_set(p.pinned_pieces(them), from)
-                     && !(rook_attacks_bb(to, occ & clear_mask_bb(from))
-                          & p.rooks_and_queens(us))
-                     && !(rook_attacks_bb(to, occ & clear_mask_bb(from))
-                          & p.rooks_and_queens(us)))
-                    ei.mateThreat[them] = make_move(from, to);
+                p.piece_attacks<KING>(s) & ~p.pieces_of_color(us) & ~attackedByOthers;
+
+            while (b)
+            {
+                Square from, to = pop_1st_bit(&b);
+                if (!(escapeSquares & ~queen_attacks_bb(to, occ & ClearMaskBB[s])))
+                {
+                    // We have a mate, unless the queen is pinned or there
+                    // is an X-ray attack through the queen.
+                    for (int i = 0; i < p.piece_count(them, QUEEN); i++)
+                    {
+                        from = p.piece_list(them, QUEEN, i);
+                        if (    bit_is_set(p.piece_attacks<QUEEN>(from), to)
+                            && !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);
+                    }
                 }
-              }
             }
           }
         }
       }
-
       // Analyse safe rook contact checks:
-      if(RookContactCheckBonus) {
-        b = undefended & ei.attacked_by(them, ROOK) & ~p.pieces_of_color(them);
-        if(b) {
-          Bitboard attackedByOthers =
-            ei.attacked_by(them, PAWN) | ei.attacked_by(them, KNIGHT)
-            | ei.attacked_by(them, BISHOP) | ei.attacked_by(them, QUEEN);
-          b &= attackedByOthers;
-          if(b) {
-            int count = count_1s_max_15(b);
-            attackUnits += (RookContactCheckBonus * count * (sente? 2 : 1));
+      if (RookContactCheckBonus)
+      {
+          b = undefended & ei.attacked_by(them, ROOK) & ~p.pieces_of_color(them);
+          if (b)
+          {
+              Bitboard attackedByOthers =
+                    ei.attacked_by(them, PAWN)   | ei.attacked_by(them, KNIGHT)
+                  | ei.attacked_by(them, BISHOP) | ei.attacked_by(them, QUEEN);
+
+              b &= attackedByOthers;
+              if (b)
+              {
+                  int count = count_1s_max_15(b);
+                  attackUnits += (RookContactCheckBonus * count * (sente? 2 : 1));
+              }
           }
-        }
       }
-
       // Analyse safe distance checks:
-      if(QueenCheckBonus > 0 || RookCheckBonus > 0) {
-        b = p.rook_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
+      if (QueenCheckBonus > 0 || RookCheckBonus > 0)
+      {
+          b = p.piece_attacks<ROOK>(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
 
-        // Queen checks
-        b2 = b & ei.attacked_by(them, QUEEN);
-        if(b2) attackUnits += QueenCheckBonus * count_1s_max_15(b2);
+          // Queen checks
+          b2 = b & ei.attacked_by(them, QUEEN);
+          if( b2)
+              attackUnits += QueenCheckBonus * count_1s_max_15(b2);
 
-        // Rook checks
-        b2 = b & ei.attacked_by(them, ROOK);
-        if(b2) attackUnits += RookCheckBonus * count_1s_max_15(b2);
+          // Rook checks
+          b2 = b & ei.attacked_by(them, ROOK);
+          if (b2)
+              attackUnits += RookCheckBonus * count_1s_max_15(b2);
       }
-      if(QueenCheckBonus > 0 || BishopCheckBonus > 0) {
-        b = p.bishop_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
-        // Queen checks
-        b2 = b & ei.attacked_by(them, QUEEN);
-        if(b2) attackUnits += QueenCheckBonus * count_1s_max_15(b2);
-
-        // Bishop checks
-        b2 = b & ei.attacked_by(them, BISHOP);
-        if(b2) attackUnits += BishopCheckBonus * count_1s_max_15(b2);
+      if (QueenCheckBonus > 0 || BishopCheckBonus > 0)
+      {
+          b = p.piece_attacks<BISHOP>(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
+
+          // Queen checks
+          b2 = b & ei.attacked_by(them, QUEEN);
+          if (b2)
+              attackUnits += QueenCheckBonus * count_1s_max_15(b2);
+
+          // Bishop checks
+          b2 = b & ei.attacked_by(them, BISHOP);
+          if (b2)
+              attackUnits += BishopCheckBonus * count_1s_max_15(b2);
       }
-      if(KnightCheckBonus > 0) {
-        b = p.knight_attacks(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
-        // Knight checks
-        b2 = b & ei.attacked_by(them, KNIGHT);
-        if(b2) attackUnits += KnightCheckBonus * count_1s_max_15(b2);
+      if (KnightCheckBonus > 0)
+      {
+          b = p.piece_attacks<KNIGHT>(s) & ~p.pieces_of_color(them) & ~ei.attacked_by(us);
+
+          // Knight checks
+          b2 = b & ei.attacked_by(them, KNIGHT);
+          if (b2)
+              attackUnits += KnightCheckBonus * count_1s_max_15(b2);
       }
 
       // Analyse discovered checks (only for non-pawns right now, consider
       // adding pawns later).
-      if(DiscoveredCheckBonus) {
+      if (DiscoveredCheckBonus)
+      {
         b = p.discovered_check_candidates(them) & ~p.pawns();
-        if(b)
-          attackUnits +=
-            DiscoveredCheckBonus * count_1s_max_15(b) * (sente? 2 : 1);
+        if (b)
+          attackUnits += DiscoveredCheckBonus * count_1s_max_15(b) * (sente? 2 : 1);
       }
 
       // Has a mate threat been found?  We don't do anything here if the
       // side with the mating move is the side to move, because in that
       // case the mating side will get a huge bonus at the end of the main
       // evaluation function instead.
-      if(ei.mateThreat[them] != MOVE_NONE)
-        attackUnits += MateThreatBonus;
+      if (ei.mateThreat[them] != MOVE_NONE)
+          attackUnits += MateThreatBonus;
 
       // Ensure that attackUnits is between 0 and 99, in order to avoid array
       // out of bounds errors:
-      if(attackUnits < 0) attackUnits = 0;
-      if(attackUnits >= 100) attackUnits = 99;
+      if (attackUnits < 0)
+          attackUnits = 0;
+
+      if (attackUnits >= 100)
+          attackUnits = 99;
 
       // Finally, extract the king safety score from the SafetyTable[] array.
       // Add the score to the evaluation, and also to ei.futilityMargin.  The
@@ -856,9 +885,11 @@ namespace {
       // capturing a single attacking piece can therefore result in a score
       // change far bigger than the value of the captured piece.
       Value v = apply_weight(SafetyTable[attackUnits], WeightKingSafety[us]);
+
       ei.mgValue -= sign * v;
-      if(us == p.side_to_move())
-        ei.futilityMargin += v;
+
+      if (us == p.side_to_move())
+          ei.futilityMargin += v;
     }
   }
 
@@ -964,7 +995,7 @@ 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
-             && pos.knight_count(them) == 1)
+             && pos.piece_count(them, KNIGHT) == 1)
             ebonus += ebonus / 4;
           else if(pos.rooks_and_queens(them))
             ebonus -= ebonus / 4;
@@ -1081,7 +1112,7 @@ namespace {
   // score, based on game phase.  It also scales the return value by a
   // ScaleFactor array.
 
-  Value scale_by_game_phase(Value mv, Value ev, Phase ph, ScaleFactor sf[]) {
+  Value scale_by_game_phase(Value mv, Value ev, Phase ph, const ScaleFactor sf[]) {
 
     assert(mv > -VALUE_INFINITE && mv < VALUE_INFINITE);
     assert(ev > -VALUE_INFINITE && ev < VALUE_INFINITE);