X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=639cd02a4067d1e3c3df4c30236dacb44234a729;hp=e8760b7372bb13a8edefa5155da39a1bfb854544;hb=b5f6c2241b3ad688fb85ea8203a9254aff842f07;hpb=72d8d27234260df70b630b1606574b0f92b998f8 diff --git a/src/search.cpp b/src/search.cpp index e8760b73..639cd02a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -46,9 +46,9 @@ namespace Search { Position RootPosition; } +using std::string; using std::cout; using std::endl; -using std::string; using namespace Search; namespace { @@ -149,7 +149,7 @@ namespace { TimeManager TimeMgr; int BestMoveChanges; int SkillLevel; - bool SkillLevelEnabled; + bool SkillLevelEnabled, Chess960; History H; @@ -194,28 +194,6 @@ namespace { MovePicker* mp; }; - // Overload operator<<() to make it easier to print moves in a coordinate - // notation compatible with UCI protocol. - std::ostream& operator<<(std::ostream& os, Move m) { - - bool chess960 = (os.iword(0) != 0); // See set960() - return os << move_to_uci(m, chess960); - } - - // When formatting a move for std::cout we must know if we are in Chess960 or - // not. To keep using the handy operator<<() on the move the trick is to embed - // this flag in the stream itself. Function-like named enum set960 is used as - // a custom manipulator and the stream internal general-purpose array, accessed - // through ios_base::iword(), is used to pass the flag to the move's operator<< - // that will read it to properly format castling moves. - enum set960 {}; - - std::ostream& operator<<(std::ostream& os, const set960& f) { - - os.iword(0) = f; - return os; - } - // is_dangerous() checks whether a move belongs to some classes of known // 'dangerous' moves so that we avoid to prune it. FORCE_INLINE bool is_dangerous(const Position& pos, Move m, bool captureOrPromotion) { @@ -304,6 +282,7 @@ void Search::think() { static Book book; // Defined static to initialize the PRNG only once Position& pos = RootPosition; + Chess960 = pos.is_chess960(); elapsed_time(true); TimeMgr.init(Limits, pos.startpos_ply_counter()); TT.new_search(); @@ -314,12 +293,9 @@ void Search::think() { // is given, with the subset of legal moves to search. for (MoveList ml(pos); !ml.end(); ++ml) if ( SearchMoves.empty() - || std::count(SearchMoves.begin(), SearchMoves.end(), ml.move())) + || count(SearchMoves.begin(), SearchMoves.end(), ml.move())) RootMoves.push_back(RootMove(ml.move())); - // Set output stream mode: normal or chess960. Castling notation is different - cout << set960(pos.is_chess960()); - if (Options["OwnBook"].value()) { if (Options["Book File"].value() != book.name()) @@ -328,9 +304,9 @@ void Search::think() { Move bookMove = book.probe(pos, Options["Best Book Move"].value()); if ( bookMove != MOVE_NONE - && std::count(RootMoves.begin(), RootMoves.end(), bookMove)) + && count(RootMoves.begin(), RootMoves.end(), bookMove)) { - std::swap(RootMoves[0], *std::find(RootMoves.begin(), RootMoves.end(), bookMove)); + std::swap(RootMoves[0], *find(RootMoves.begin(), RootMoves.end(), bookMove)); goto finish; } } @@ -409,15 +385,9 @@ finish: if (!Signals.stop && (Limits.ponder || Limits.infinite)) Threads.wait_for_stop_or_ponderhit(); - // Could be MOVE_NONE when searching on a stalemate position - cout << "bestmove " << RootMoves[0].pv[0]; - - // UCI protol is not clear on allowing sending an empty ponder move, instead - // it is clear that ponder move is optional. So skip it if empty. - if (RootMoves[0].pv[1] != MOVE_NONE) - cout << " ponder " << RootMoves[0].pv[1]; - - cout << endl; + // Best move could be MOVE_NONE when searching on a stalemate position + cout << "bestmove " << move_to_uci(RootMoves[0].pv[0], Chess960) + << " ponder " << move_to_uci(RootMoves[0].pv[1], Chess960) << endl; } @@ -506,7 +476,7 @@ namespace { // If search has been stopped exit the aspiration window loop. // Sorting and writing PV back to TT is safe becuase RootMoves - // is still valid, although refers to previous iteration. + // is still valid, although refers to previous iteration. if (Signals.stop) break; @@ -599,7 +569,7 @@ namespace { if (skillBest == MOVE_NONE) // Still unassigned ? skillBest = do_skill_level(); - std::swap(RootMoves[0], *std::find(RootMoves.begin(), RootMoves.end(), skillBest)); + std::swap(RootMoves[0], *find(RootMoves.begin(), RootMoves.end(), skillBest)); } } @@ -908,7 +878,7 @@ split_point_start: // At split points actual search starts from here // At root obey the "searchmoves" option and skip moves not listed in Root // Move List, as a consequence any illegal move is also skipped. In MultiPV // mode we also skip PV moves which have been already searched. - if (RootNode && !std::count(RootMoves.begin() + PVIdx, RootMoves.end(), move)) + if (RootNode && !count(RootMoves.begin() + PVIdx, RootMoves.end(), move)) continue; // At PV and SpNode nodes we want all moves to be legal since the beginning @@ -925,14 +895,12 @@ split_point_start: // At split points actual search starts from here if (RootNode) { - // This is used by time management Signals.firstRootMove = (moveCount == 1); - nodes = pos.nodes_searched(); if (pos.thread() == 0 && elapsed_time() > 2000) cout << "info depth " << depth / ONE_PLY - << " currmove " << move + << " currmove " << move_to_uci(move, Chess960) << " currmovenumber " << moveCount + PVIdx << endl; } @@ -1094,7 +1062,7 @@ split_point_start: // At split points actual search starts from here // be trusted, and we don't update the best move and/or PV. if (RootNode && !Signals.stop) { - RootMove& rm = *std::find(RootMoves.begin(), RootMoves.end(), move); + RootMove& rm = *find(RootMoves.begin(), RootMoves.end(), move); rm.nodes += pos.nodes_searched() - nodes; // PV move or new best move ? @@ -1175,7 +1143,9 @@ split_point_start: // At split points actual search starts from here TT.store(posKey, value_to_tt(bestValue, ss->ply), vt, depth, move, ss->eval, ss->evalMargin); // Update killers and history for non capture cut-off moves - if (bestValue >= beta && !pos.is_capture_or_promotion(move)) + if ( bestValue >= beta + && !pos.is_capture_or_promotion(move) + && !inCheck) { if (move != ss->killers[0]) { @@ -1521,8 +1491,8 @@ split_point_start: // At split points actual search starts from here // value_to_tt() adjusts a mate score from "plies to mate from the root" to - // "plies to mate from the current ply". Non-mate scores are unchanged. - // The function is called before storing a value to the transposition table. + // "plies to mate from the current ply". Non-mate scores are unchanged. The + // function is called before storing a value to the transposition table. Value value_to_tt(Value v, int ply) { @@ -1681,21 +1651,20 @@ split_point_start: // At split points actual search starts from here continue; int d = (updated ? depth : depth - 1); - Value s = (updated ? RootMoves[i].score : RootMoves[i].prevScore); + Value v = (updated ? RootMoves[i].score : RootMoves[i].prevScore); + std::stringstream s; - cout << "info" - << " depth " << d + for (int j = 0; RootMoves[i].pv[j] != MOVE_NONE; j++) + s << " " << move_to_uci(RootMoves[i].pv[j], Chess960); + + cout << "info depth " << d << " seldepth " << selDepth - << (i == PVIdx ? score_to_uci(s, alpha, beta) : score_to_uci(s)) + << (i == PVIdx ? score_to_uci(v, alpha, beta) : score_to_uci(v)) << " nodes " << pos.nodes_searched() << " nps " << (t > 0 ? pos.nodes_searched() * 1000 / t : 0) << " time " << t - << " multipv " << i + 1 << " pv"; - - for (int j = 0; RootMoves[i].pv[j] != MOVE_NONE; j++) - cout << " " << RootMoves[i].pv[j]; - - cout << endl; + << " multipv " << i + 1 + << " pv" << s.str() << endl; } } @@ -1749,8 +1718,7 @@ split_point_start: // At split points actual search starts from here size_t length; std::stringstream s; - s << set960(pos.is_chess960()) - << std::setw(2) << depth + s << std::setw(2) << depth << std::setw(8) << score_to_string(value) << std::setw(8) << time_to_string(time);