X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=d19c9a9015423192991319e4e6b910db955c4e8e;hp=c05bbd4c54d12a790ab38bc1f9be8a7a4bf34662;hb=13d1776a983c8b6b8ee2ed83ef7d2a4a5caf93a9;hpb=18860cce406f9646cb6af218c2b23f51d2e47b8d diff --git a/src/search.cpp b/src/search.cpp index c05bbd4c..d19c9a90 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -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. @@ -22,7 +23,6 @@ //// #include -#include #include #include #include @@ -70,16 +70,16 @@ namespace { public: RootMoveList(Position &pos, Move searchMoves[]); - Move get_move(int moveNum) const; - Value get_move_score(int moveNum) const; - void set_move_score(int moveNum, Value score); - void set_move_nodes(int moveNum, int64_t nodes); + inline Move get_move(int moveNum) const; + inline Value get_move_score(int moveNum) const; + inline void set_move_score(int moveNum, Value score); + inline void set_move_nodes(int moveNum, int64_t nodes); void set_move_pv(int moveNum, const Move pv[]); - Move get_move_pv(int moveNum, int i) const; - int64_t get_move_cumulative_nodes(int moveNum) const; - int move_count() const; + inline Move get_move_pv(int moveNum, int i) const; + inline int64_t get_move_cumulative_nodes(int moveNum) const; + inline int move_count() const; Move scan_for_easy_move() const; - void sort(); + inline void sort(); void sort_multipv(int n); private: @@ -153,6 +153,12 @@ namespace { Depth RazorDepth = 4*OnePly; Value RazorMargin = Value(0x300); + // Last seconds noise filtering (LSN) + bool UseLSNFiltering = false; + bool looseOnTime = false; + int LSNTime = 4 * 1000; // In milliseconds + Value LSNValue = Value(0x200); + // Extensions. Array index 0 is used at non-PV nodes, index 1 at PV nodes. Depth CheckExtension[2] = {OnePly, OnePly}; Depth SingleReplyExtension[2] = {OnePly / 2, OnePly / 2}; @@ -221,7 +227,7 @@ namespace { /// Functions - void id_loop(const Position &pos, Move searchMoves[]); + Value id_loop(const Position &pos, Move searchMoves[]); Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml); Value search_pv(Position &pos, SearchStack ss[], Value alpha, Value beta, Depth depth, int ply, int threadID); @@ -296,7 +302,7 @@ History H; // Should be made local? //// Functions //// -/// think() is the external interface to Glaurung's search, and is called when +/// think() is the external interface to Stockfish's search, and is called when /// the program receives the UCI 'go' command. It initializes various /// search-related global variables, and calls root_search() @@ -395,6 +401,10 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, RazorDepth = (get_option_value_int("Maximum Razoring Depth") + 1) * OnePly; RazorMargin = value_from_centipawns(get_option_value_int("Razoring Margin")); + UseLSNFiltering = get_option_value_bool("LSN filtering"); + LSNTime = get_option_value_int("LSN Time Margin (sec)") * 1000; + LSNValue = value_from_centipawns(get_option_value_int("LSN Value Margin")); + MinimumSplitDepth = get_option_value_int("Minimum Split Depth") * OnePly; MaxThreadsPerSplitPoint = get_option_value_int("Maximum Number of Threads per Split Point"); @@ -417,7 +427,7 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, int myTime = time[side_to_move]; int myIncrement = increment[side_to_move]; int oppTime = time[1 - side_to_move]; - + TimeAdvantage = myTime - oppTime; if(!movesToGo) { // Sudden death time control @@ -469,7 +479,21 @@ void think(const Position &pos, bool infinite, bool ponder, int side_to_move, // We're ready to start thinking. Call the iterative deepening loop // function: - id_loop(pos, searchMoves); + if (!looseOnTime) + { + Value v = id_loop(pos, searchMoves); + looseOnTime = ( UseLSNFiltering + && myTime < LSNTime + && myIncrement == 0 + && v < -LSNValue); + } + else + { + looseOnTime = false; // reset for next match + while (SearchStartTime + myTime + 1000 > get_system_time()) + ; // wait here + id_loop(pos, searchMoves); // to fail gracefully + } if(UseLogFile) LogFile.close(); @@ -571,7 +595,7 @@ namespace { // been consumed, the user stops the search, or the maximum search depth is // reached. - void id_loop(const Position &pos, Move searchMoves[]) { + Value id_loop(const Position &pos, Move searchMoves[]) { Position p(pos); SearchStack ss[PLY_MAX_PLUS_2]; @@ -695,6 +719,7 @@ namespace { LogFile << "Ponder move: " << move_to_san(p, ss[0].pv[1]) << '\n'; LogFile << std::endl; } + return rml.get_move_score(0); } @@ -906,6 +931,7 @@ namespace { { assert(move_is_ok(move)); + bool fewMoves = (depth <= OnePly && mp.number_of_moves() < 4); bool singleReply = (pos.is_check() && mp.number_of_moves() == 1); bool moveIsCheck = pos.move_is_check(move, dcCandidates); bool moveIsCapture = pos.move_is_capture(move); @@ -917,7 +943,7 @@ namespace { PawnValueMidgame : pos.midgame_value_of_piece_on(move_to(move)); // Decide the new search depth - Depth ext = extension(pos, move, true, moveIsCheck, singleReply, mateThreat); + Depth ext = extension(pos, move, true, moveIsCheck, singleReply || fewMoves, mateThreat); Depth newDepth = depth - OnePly + ext; // Make and search the move @@ -1123,9 +1149,8 @@ namespace { } } // Null move search not allowed, try razoring - else if ( depth < RazorDepth - && approximateEval < beta - RazorMargin - && evaluate(pos, ei, threadID) < beta - RazorMargin) + else if ( (approximateEval < beta - RazorMargin && depth < RazorDepth) + ||(approximateEval < beta - PawnValueMidgame && depth <= OnePly)) { Value v = qsearch(pos, ss, beta-1, beta, Depth(0), ply, threadID); if (v < beta) @@ -2136,62 +2161,70 @@ namespace { // search. void poll() { - int t, data; - static int lastInfoTime; - t = current_search_time(); + static int lastInfoTime; + int t = current_search_time(); // Poll for input - data = Bioskey(); - if(data) { - char input[256]; - if(fgets(input, 255, stdin) == NULL) - strncpy(input, "quit\n", 5); - if(strncmp(input, "quit", 4) == 0) { - AbortSearch = true; - PonderSearch = false; - Quit = true; - } - else if(strncmp(input, "stop", 4) == 0) { - AbortSearch = true; - PonderSearch = false; - } - else if(strncmp(input, "ponderhit", 9) == 0) - ponderhit(); - } + if (Bioskey()) + { + // We are line oriented, don't read single chars + std::string command; + if (!std::getline(std::cin, command)) + command = "quit"; - // Print search information - if(t < 1000) - lastInfoTime = 0; - else if(lastInfoTime > t) - // HACK: Must be a new search where we searched less than - // NodesBetweenPolls nodes during the first second of search. - lastInfoTime = 0; - else if(t - lastInfoTime >= 1000) { - lastInfoTime = t; - lock_grab(&IOLock); - std::cout << "info nodes " << nodes_searched() << " nps " << nps() - << " time " << t << " hashfull " << TT.full() << std::endl; - lock_release(&IOLock); - if(ShowCurrentLine) - Threads[0].printCurrentLine = true; + if (command == "quit") + { + AbortSearch = true; + PonderSearch = false; + Quit = true; + } + else if(command == "stop") + { + AbortSearch = true; + PonderSearch = false; + } + else if(command == "ponderhit") + ponderhit(); } + // Print search information + if (t < 1000) + lastInfoTime = 0; + + else if (lastInfoTime > t) + // HACK: Must be a new search where we searched less than + // NodesBetweenPolls nodes during the first second of search. + lastInfoTime = 0; + else if (t - lastInfoTime >= 1000) + { + lastInfoTime = t; + lock_grab(&IOLock); + if (dbg_show_mean) + dbg_print_mean(); + + if (dbg_show_hit_rate) + dbg_print_hit_rate(); + + std::cout << "info nodes " << nodes_searched() << " nps " << nps() + << " time " << t << " hashfull " << TT.full() << std::endl; + lock_release(&IOLock); + if (ShowCurrentLine) + Threads[0].printCurrentLine = true; + } // Should we stop the search? - if(!PonderSearch && Iteration >= 2 && - (!InfiniteSearch && (t > AbsoluteMaxSearchTime || - (RootMoveNumber == 1 && - t > MaxSearchTime + ExtraSearchTime) || - (!FailHigh && !fail_high_ply_1() && !Problem && - t > 6*(MaxSearchTime + ExtraSearchTime))))) - AbortSearch = true; + if (PonderSearch) + return; - if(!PonderSearch && ExactMaxTime && t >= ExactMaxTime) - AbortSearch = true; + bool overTime = t > AbsoluteMaxSearchTime + || (RootMoveNumber == 1 && t > MaxSearchTime + ExtraSearchTime) + || ( !FailHigh && !fail_high_ply_1() && !Problem + && t > 6*(MaxSearchTime + ExtraSearchTime)); - if(!PonderSearch && Iteration >= 3 && MaxNodes - && nodes_searched() >= MaxNodes) - AbortSearch = true; + if ( (Iteration >= 2 && (!InfiniteSearch && overTime)) + || (ExactMaxTime && t >= ExactMaxTime) + || (Iteration >= 3 && MaxNodes && nodes_searched() >= MaxNodes)) + AbortSearch = true; }