- // Print the best move and the ponder move to the standard output
- if (pv[0] == MOVE_NONE)
- {
- pv[0] = rml.move(0);
- pv[1] = MOVE_NONE;
- }
-
- assert(pv[0] != MOVE_NONE);
-
- cout << "bestmove " << pv[0];
-
- if (pv[1] != MOVE_NONE)
- cout << " ponder " << pv[1];
-
- cout << endl;
-
- if (UseLogFile)
- {
- if (dbg_show_mean)
- dbg_print_mean(LogFile);
-
- if (dbg_show_hit_rate)
- dbg_print_hit_rate(LogFile);
-
- LogFile << "\nNodes: " << ThreadsMgr.nodes_searched()
- << "\nNodes/second: " << nps()
- << "\nBest move: " << move_to_san(p, pv[0]);
-
- StateInfo st;
- p.do_move(pv[0], st);
- LogFile << "\nPonder move: "
- << move_to_san(p, pv[1]) // Works also with MOVE_NONE
- << endl;
- }
- return rml.move_score(0);
- }
-
-
- // root_search() is the function which searches the root node. It is
- // similar to search_pv except that it uses a different move ordering
- // scheme, prints some information to the standard output and handles
- // the fail low/high loops.
-
- Value root_search(Position& pos, SearchStack* ss, Move* pv, RootMoveList& rml, Value* alphaPtr, Value* betaPtr) {
-
- StateInfo st;
- CheckInfo ci(pos);
- int64_t nodes;
- Move move;
- Depth depth, ext, newDepth;
- Value value, evalMargin, alpha, beta;
- bool isCheck, moveIsCheck, captureOrPromotion, dangerous;
- int researchCountFH, researchCountFL;
-
- researchCountFH = researchCountFL = 0;
- alpha = *alphaPtr;
- beta = *betaPtr;
- isCheck = pos.is_check();
- depth = (Iteration - 2) * ONE_PLY + InitialDepth;
-
- // Step 1. Initialize node (polling is omitted at root)
- ss->currentMove = ss->bestMove = MOVE_NONE;
-
- // Step 2. Check for aborted search (omitted at root)
- // Step 3. Mate distance pruning (omitted at root)
- // Step 4. Transposition table lookup (omitted at root)
-
- // Step 5. Evaluate the position statically
- // At root we do this only to get reference value for child nodes
- ss->eval = isCheck ? VALUE_NONE : evaluate(pos, evalMargin);
-
- // Step 6. Razoring (omitted at root)
- // Step 7. Static null move pruning (omitted at root)
- // Step 8. Null move search with verification search (omitted at root)
- // Step 9. Internal iterative deepening (omitted at root)
-
- // Step extra. Fail low loop
- // We start with small aspiration window and in case of fail low, we research
- // with bigger window until we are not failing low anymore.
- while (1)
- {
- // Sort the moves before to (re)search
- rml.score_moves(pos);
- rml.sort();
-
- // Step 10. Loop through all moves in the root move list
- for (int i = 0; i < rml.move_count() && !AbortSearch; i++)
- {
- // This is used by time management
- FirstRootMove = (i == 0);
-
- // Save the current node count before the move is searched
- nodes = ThreadsMgr.nodes_searched();
-
- // Pick the next root move, and print the move and the move number to
- // the standard output.
- move = ss->currentMove = rml.move(i);
-
- if (current_search_time() >= 1000)
- cout << "info currmove " << move
- << " currmovenumber " << i + 1 << endl;
-
- moveIsCheck = pos.move_is_check(move);
- captureOrPromotion = pos.move_is_capture_or_promotion(move);
+ // Start with a small aspiration window and, in case of fail high/low,
+ // research with bigger window until not failing high/low anymore.
+ do {
+ // Search starts from ss+1 to allow referencing (ss-1). This is
+ // needed by update_gains() and ss copy when splitting at Root.
+ value = search<Root>(pos, ss+1, alpha, beta, depth * ONE_PLY);
+
+ // Bring to front the best move. It is critical that sorting is
+ // done with a stable algorithm because all the values but the first
+ // and eventually the new best one are set to -VALUE_INFINITE and
+ // we want to keep the same order for all the moves but the new
+ // PV that goes to the front. Note that in case of MultiPV search
+ // the already searched PV lines are preserved.
+ sort<RootMove>(Rml.begin() + MultiPVIdx, Rml.end());
+
+ // In case we have found an exact score and we are going to leave
+ // the fail high/low loop then reorder the PV moves, otherwise
+ // leave the last PV move in its position so to be searched again.
+ // Of course this is needed only in MultiPV search.
+ if (MultiPVIdx && value > alpha && value < beta)
+ sort<RootMove>(Rml.begin(), Rml.begin() + MultiPVIdx);
+
+ // Write PV back to transposition table in case the relevant entries
+ // have been overwritten during the search.
+ for (int i = 0; i <= MultiPVIdx; i++)
+ Rml[i].insert_pv_in_tt(pos);
+
+ // If search has been stopped exit the aspiration window loop,
+ // note that sorting and writing PV back to TT is safe becuase
+ // Rml is still valid, although refers to the previous iteration.
+ if (StopRequest)
+ break;