]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Retire move.cpp
[stockfish] / src / search.cpp
index d93fbdf79635d3b14a854fa979e87babb802df7c..88160ef2529df13179ce9cb8839090ec2aa9fa2d 100644 (file)
@@ -146,10 +146,10 @@ namespace {
     typedef std::vector<RootMove> Base;
 
     RootMoveList(Position& pos, Move searchMoves[]);
-    void set_non_pv_scores(const Position& pos);
+    void set_non_pv_scores(const Position& pos, Move ttm, SearchStack* ss);
 
     void sort() { insertion_sort<RootMove, Base::iterator>(begin(), end()); }
-    void sort_multipv(int n) { insertion_sort<RootMove, Base::iterator>(begin(), begin() + n + 1); }
+    void sort_multipv(int n) { insertion_sort<RootMove, Base::iterator>(begin(), begin() + n); }
   };
 
 
@@ -161,13 +161,19 @@ namespace {
   // operator<<() that will use it to properly format castling moves.
   enum set960 {};
 
-  std::ostream& operator<< (std::ostream& os, const set960& m) {
+  std::ostream& operator<< (std::ostream& os, const set960& f) {
 
-    os.iword(0) = int(m);
+    os.iword(0) = int(f);
     return os;
   }
 
 
+  // Overload operator << for moves to make it easier to print moves in
+  // coordinate notation compatible with UCI protocol.
+
+  std::ostream& operator<<(std::ostream& os, Move m);
+
+
   /// Adjustments
 
   // Step 6. Razoring
@@ -304,7 +310,7 @@ namespace {
   bool connected_threat(const Position& pos, Move m, Move threat);
   Value refine_eval(const TTEntry* tte, Value defaultEval, int ply);
   void update_history(const Position& pos, Move move, Depth depth, Move movesSearched[], int moveCount);
-  void update_killers(Move m, SearchStack* ss);
+  void update_killers(Move m, Move killers[]);
   void update_gains(const Position& pos, Move move, Value before, Value after);
 
   int current_search_time();
@@ -364,12 +370,12 @@ void init_search() {
 /// perft() is our utility to verify move generation is bug free. All the legal
 /// moves up to given depth are generated and counted and the sum returned.
 
-int perft(Position& pos, Depth depth)
+int64_t perft(Position& pos, Depth depth)
 {
     MoveStack mlist[MOVES_MAX];
     StateInfo st;
     Move m;
-    int sum = 0;
+    int64_t sum = 0;
 
     // Generate all legal moves
     MoveStack* last = generate_moves(pos, mlist);
@@ -513,6 +519,9 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
               << move_to_san(pos, ponderMove) // Works also with MOVE_NONE
               << endl;
 
+      // Return from think() with unchanged position
+      pos.undo_move(bestMove);
+
       LogFile.close();
   }
 
@@ -674,13 +683,15 @@ namespace {
   Value root_search(Position& pos, SearchStack* ss, Value alpha,
                     Value beta, Depth depth, RootMoveList& rml) {
     StateInfo st;
+    Move movesSearched[MOVES_MAX];
     CheckInfo ci(pos);
     int64_t nodes;
     Move move;
     Depth ext, newDepth;
     Value value, oldAlpha;
-    bool isCheck, moveIsCheck, captureOrPromotion, dangerous;
-    int researchCountFH, researchCountFL;
+    RootMoveList::iterator rm;
+    bool isCheck, moveIsCheck, captureOrPromotion, dangerous, isPvMove;
+    int moveCount, researchCountFH, researchCountFL;
 
     researchCountFH = researchCountFL = 0;
     oldAlpha = alpha;
@@ -709,14 +720,15 @@ namespace {
     while (1)
     {
         // Sort the moves before to (re)search
-        rml.set_non_pv_scores(pos);
+        rml.set_non_pv_scores(pos, rml[0].pv[0], ss);
         rml.sort();
+        moveCount = 0;
 
         // Step 10. Loop through all moves in the root move list
-        for (int i = 0; i < (int)rml.size() && !StopRequest; i++)
+        for (rm = rml.begin(); rm != rml.end() && !StopRequest; ++rm)
         {
             // This is used by time management
-            FirstRootMove = (i == 0);
+            FirstRootMove = (rm == rml.begin());
 
             // Save the current node count before the move is searched
             nodes = pos.nodes_searched();
@@ -733,11 +745,13 @@ namespace {
 
             // Pick the next root move, and print the move and the move number to
             // the standard output.
-            move = ss->currentMove = rml[i].pv[0];
+            move = ss->currentMove = rm->pv[0];
+            movesSearched[moveCount++] = move;
+            isPvMove = (moveCount <= MultiPV);
 
             if (current_search_time() >= 1000)
                 cout << "info currmove " << move
-                     << " currmovenumber " << i + 1 << endl;
+                     << " currmovenumber " << moveCount << endl;
 
             moveIsCheck = pos.move_is_check(move);
             captureOrPromotion = pos.move_is_capture_or_promotion(move);
@@ -759,9 +773,8 @@ namespace {
                 pos.do_move(move, st, ci, moveIsCheck);
 
                 // Step extra. pv search
-                // We do pv search for first moves (i < MultiPV)
-                // and for fail high research (value > alpha)
-                if (i < MultiPV || value > alpha)
+                // We do pv search for PV moves and when failing high
+                if (isPvMove || value > alpha)
                 {
                     // Aspiration window is disabled in multi-pv case
                     if (MultiPV > 1)
@@ -781,7 +794,7 @@ namespace {
                         && !captureOrPromotion
                         && !move_is_castle(move))
                     {
-                        ss->reduction = reduction<PV>(depth, i - MultiPV + 2);
+                        ss->reduction = reduction<PV>(depth, moveCount - MultiPV + 1);
                         if (ss->reduction)
                         {
                             assert(newDepth-ss->reduction >= ONE_PLY);
@@ -816,11 +829,18 @@ namespace {
                 // We are failing high and going to do a research. It's important to update
                 // the score before research in case we run out of time while researching.
                 ss->bestMove = move;
-                rml[i].pv_score = value;
-                rml[i].extract_pv_from_tt(pos);
+                rm->pv_score = value;
+                rm->extract_pv_from_tt(pos);
+
+                // Update killers and history only for non capture moves that fails high
+                if (!pos.move_is_capture_or_promotion(move))
+                {
+                    update_history(pos, move, depth, movesSearched, moveCount);
+                    update_killers(move, ss->killers);
+                }
 
                 // Inform GUI that PV has changed
-                cout << rml[i].pv_info_to_uci(pos, alpha, beta) << endl;
+                cout << rm->pv_info_to_uci(pos, alpha, beta) << endl;
 
                 // Prepare for a research after a fail high, each time with a wider window
                 beta = Min(beta + AspirationDelta * (1 << researchCountFH), VALUE_INFINITE);
@@ -837,32 +857,32 @@ namespace {
                 break;
 
             // Remember searched nodes counts for this move
-            rml[i].nodes += pos.nodes_searched() - nodes;
+            rm->nodes += pos.nodes_searched() - nodes;
 
             assert(value >= -VALUE_INFINITE && value <= VALUE_INFINITE);
             assert(value < beta);
 
             // Step 17. Check for new best move
-            if (value <= alpha && i >= MultiPV)
-                rml[i].pv_score = -VALUE_INFINITE;
+            if (!isPvMove && value <= alpha)
+                rm->pv_score = -VALUE_INFINITE;
             else
             {
                 // PV move or new best move!
 
                 // Update PV
                 ss->bestMove = move;
-                rml[i].pv_score = value;
-                rml[i].extract_pv_from_tt(pos);
+                rm->pv_score = value;
+                rm->extract_pv_from_tt(pos);
 
                 // We record how often the best move has been changed in each
                 // iteration. This information is used for time managment: When
                 // the best move changes frequently, we allocate some more time.
-                if (MultiPV == 1 && i > 0)
+                if (!isPvMove && MultiPV == 1)
                     BestMoveChangesByIteration[Iteration]++;
 
                 // Inform GUI that PV has changed, in case of multi-pv UCI protocol
                 // requires we send all the PV lines properly sorted.
-                rml.sort_multipv(i);
+                rml.sort_multipv(moveCount);
 
                 for (int j = 0; j < Min(MultiPV, (int)rml.size()); j++)
                     cout << rml[j].pv_info_to_uci(pos, alpha, beta, j) << endl;
@@ -875,7 +895,7 @@ namespace {
                         alpha = value;
                 }
                 else // Set alpha equal to minimum score among the PV lines
-                    alpha = rml[Min(i, MultiPV - 1)].pv_score;
+                    alpha = rml[Min(moveCount, MultiPV) - 1].pv_score; // FIXME why moveCount?
 
             } // PV move or new best move
 
@@ -1384,7 +1404,7 @@ split_point_start: // At split points actual search starts from here
             && !pos.move_is_capture_or_promotion(move))
         {
             update_history(pos, move, depth, movesSearched, moveCount);
-            update_killers(move, ss);
+            update_killers(move, ss->killers);
         }
     }
 
@@ -1903,13 +1923,13 @@ split_point_start: // At split points actual search starts from here
   // update_killers() add a good move that produced a beta-cutoff
   // among the killer moves of that ply.
 
-  void update_killers(Move m, SearchStack* ss) {
+  void update_killers(Move m, Move killers[]) {
 
-    if (m == ss->killers[0])
+    if (m == killers[0])
         return;
 
-    ss->killers[1] = ss->killers[0];
-    ss->killers[0] = m;
+    killers[1] = killers[0];
+    killers[0] = m;
   }
 
 
@@ -2682,11 +2702,11 @@ split_point_start: // At split points actual search starts from here
   // This is the second order score that is used to compare the moves when
   // the first order pv scores of both moves are equal.
 
-  void RootMoveList::set_non_pv_scores(const Position& pos)
+  void RootMoveList::set_non_pv_scores(const Position& pos, Move ttm, SearchStack* ss)
   {
       Move move;
       Value score = VALUE_ZERO;
-      MovePicker mp(pos, MOVE_NONE, ONE_PLY, H);
+      MovePicker mp(pos, ttm, ONE_PLY, H, ss);
 
       while ((move = mp.get_next_move()) != MOVE_NONE)
           for (Base::iterator it = begin(); it != end(); ++it)
@@ -2697,4 +2717,35 @@ split_point_start: // At split points actual search starts from here
               }
   }
 
+  // Overload operator << to make it easier to print moves in coordinate notation
+  // (g1f3, a7a8q, etc.). The only special case is castling moves, where we
+  // print in the e1g1 notation in normal chess mode, and in e1h1 notation in
+  // Chess960 mode.
+
+  std::ostream& operator<<(std::ostream& os, Move m) {
+
+    Square from = move_from(m);
+    Square to = move_to(m);
+    bool chess960 = (os.iword(0) != 0); // See set960()
+
+    if (m == MOVE_NONE)
+        return os << "(none)";
+
+    if (m == MOVE_NULL)
+        return os << "0000";
+
+    if (move_is_short_castle(m) && !chess960)
+        return os << (from == SQ_E1 ? "e1g1" : "e8g8");
+
+    if (move_is_long_castle(m) && !chess960)
+        return os << (from == SQ_E1 ? "e1c1" : "e8c8");
+
+    os << square_to_string(from) << square_to_string(to);
+
+    if (move_is_promotion(m))
+        os << char(tolower(piece_type_to_char(move_promotion_piece(m))));
+
+    return os;
+  }
+
 } // namespace