From 3726ad9635d8b937d74d467503f2a9b010517d2e Mon Sep 17 00:00:00 2001 From: Calcitem Date: Fri, 23 Oct 2020 02:01:12 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=B8=85=E7=90=86=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- millgame.vcxproj | 2 - millgame.vcxproj.filters | 6 - src/evaluate.cpp | 37 +--- src/evaluate.h | 2 +- src/movegen.cpp | 96 ---------- src/movepick.cpp | 8 +- src/movepick.h | 29 --- src/option.cpp | 1 - src/position.cpp | 95 +--------- src/position.h | 24 +-- src/rule.h | 1 - src/search.cpp | 354 +---------------------------------- src/search.h | 84 --------- src/thread.cpp | 81 +------- src/thread.h | 27 +-- src/timeman.cpp | 136 -------------- src/timeman.h | 50 ----- src/tt.cpp | 2 +- src/uci.cpp | 62 ++---- src/uci.h | 1 - src/ucioption.cpp | 13 -- src/ui/qt/gamecontroller.cpp | 2 +- 22 files changed, 48 insertions(+), 1065 deletions(-) delete mode 100644 src/timeman.cpp delete mode 100644 src/timeman.h diff --git a/millgame.vcxproj b/millgame.vcxproj index f0c37d6c..86ba55a2 100644 --- a/millgame.vcxproj +++ b/millgame.vcxproj @@ -456,7 +456,6 @@ - @@ -720,7 +719,6 @@ - diff --git a/millgame.vcxproj.filters b/millgame.vcxproj.filters index 0b735fbf..b46fddfe 100644 --- a/millgame.vcxproj.filters +++ b/millgame.vcxproj.filters @@ -120,9 +120,6 @@ Header Files - - Header Files - Qt Files @@ -356,9 +353,6 @@ Source Files - - Source Files - Source Files diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 7db64294..518a8675 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -35,11 +35,6 @@ enum Tracing NO_TRACE, TRACE }; -double to_cp(Value v) -{ - return double(v) / StoneValue; -} - } using namespace Trace; @@ -176,37 +171,15 @@ Value Eval::evaluate(Position &pos) /// a string (suitable for outputting to stdout) that contains the detailed /// descriptions and values of each evaluation term. Useful for debugging. -std::string Eval::trace(const Position &pos) +std::string Eval::trace(Position &pos) { -#if 0 - std::memset(scores, 0, sizeof(scores)); + Value v = Evaluation(pos).value(); - // TODO - //pos.this_thread()->contempt = 0 // TODO: SCORE_ZERO; // Reset any dynamic contempt - - Value v = Evaluation(pos)->value(); - - v = pos.side_to_move() == WHITE ? v : -v; // Trace scores are from white's point of view + v = pos.side_to_move() == BLACK ? v : -v; // Trace scores are from black's point of view std::stringstream ss; - ss << std::showpoint << std::noshowpos << std::fixed << std::setprecision(2) - << " Term | White | Black | Total \n" - << " | MG EG | MG EG | MG EG \n" - << " ------------+-------------+-------------+------------\n" - << " Material | " << Term(MATERIAL) - << " Imbalance | " << Term(IMBALANCE) - << " Mobility | " << Term(MOBILITY) - << " Threats | " << Term(THREAT) - << " Passed | " << Term(PASSED) - << " Space | " << Term(SPACE) - << " Initiative | " << Term(INITIATIVE) - << " ------------+-------------+-------------+------------\n" - << " Total | " << Term(TOTAL); - ss << "\nTotal evaluation: " << to_cp(v) << " (white side)\n"; + ss << "\nTotal evaluation: " << v << " (black side)\n"; return ss.str(); -#endif - //pos = pos; - return ""; -} \ No newline at end of file +} diff --git a/src/evaluate.h b/src/evaluate.h index b33cfa81..c33d834c 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -28,7 +28,7 @@ class Position; namespace Eval { -std::string trace(const Position &pos); +std::string trace(Position &pos); Value evaluate(Position &pos); }; diff --git a/src/movegen.cpp b/src/movegen.cpp index 71129096..43dabb64 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -133,7 +133,6 @@ template<> void MoveList::create() { // Note: Not follow order of MoveDirection array -#if 1 const int moveTable_obliqueLine[SQUARE_NB][MD_NB] = { /* 0 */ {0, 0, 0, 0}, /* 1 */ {0, 0, 0, 0}, @@ -227,101 +226,6 @@ void MoveList::create() /* 38 */ {0, 0, 0, 0}, /* 39 */ {0, 0, 0, 0}, }; -#else - const int moveTable_obliqueLine[Position::N_LOCATIONS][MD_NB] = { - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - - {9, 15, 0, 16}, - {10, 8, 0, 17}, - {11, 9, 0, 18}, - {12, 10, 0, 19}, - {13, 11, 0, 20}, - {14, 12, 0, 21}, - {15, 13, 0, 22}, - {8, 14, 0, 23}, - - {17, 23, 8, 24}, - {18, 16, 9, 25}, - {19, 17, 10, 26}, - {20, 18, 11, 27}, - {21, 19, 12, 28}, - {22, 20, 13, 29}, - {23, 21, 14, 30}, - {16, 22, 15, 31}, - - {25, 31, 16, 0}, - {26, 24, 17, 0}, - {27, 25, 18, 0}, - {28, 26, 19, 0}, - {29, 27, 20, 0}, - {30, 28, 21, 0}, - {31, 29, 22, 0}, - {24, 30, 23, 0}, - - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0} - }; - - const int moveTable_noObliqueLine[Position::N_LOCATIONS][MD_NB] = { - /* 0 */ {0, 0, 0, 0}, - /* 1 */ {0, 0, 0, 0}, - /* 2 */ {0, 0, 0, 0}, - /* 3 */ {0, 0, 0, 0}, - /* 4 */ {0, 0, 0, 0}, - /* 5 */ {0, 0, 0, 0}, - /* 6 */ {0, 0, 0, 0}, - /* 7 */ {0, 0, 0, 0}, - - /* 8 */ {9, 15, 0, 16}, - /* 9 */ {10, 8, 0, 0}, - /* 10 */ {11, 9, 0, 18}, - /* 11 */ {12, 10, 0, 0}, - /* 12 */ {13, 11, 0, 20}, - /* 13 */ {14, 12, 0, 0}, - /* 14 */ {15, 13, 0, 22}, - /* 15 */ {8, 14, 0, 0}, - - /* 16 */ {17, 23, 8, 24}, - /* 17 */ {18, 16, 0, 0}, - /* 18 */ {19, 17, 10, 26}, - /* 19 */ {20, 18, 0, 0}, - /* 20 */ {21, 19, 12, 28}, - /* 21 */ {22, 20, 0, 0}, - /* 22 */ {23, 21, 14, 30}, - /* 23 */ {16, 22, 0, 0}, - - /* 24 */ {25, 31, 16, 0}, - /* 25 */ {26, 24, 0, 0}, - /* 26 */ {27, 25, 18, 0}, - /* 27 */ {28, 26, 0, 0}, - /* 28 */ {29, 27, 20, 0}, - /* 29 */ {30, 28, 0, 0}, - /* 30 */ {31, 29, 22, 0}, - /* 31 */ {24, 30, 0, 0}, - - /* 32 */ {0, 0, 0, 0}, - /* 33 */ {0, 0, 0, 0}, - /* 34 */ {0, 0, 0, 0}, - /* 35 */ {0, 0, 0, 0}, - /* 36 */ {0, 0, 0, 0}, - /* 37 */ {0, 0, 0, 0}, - /* 38 */ {0, 0, 0, 0}, - /* 39 */ {0, 0, 0, 0}, - }; -#endif if (rule->hasObliqueLines) { memcpy(moveTable, moveTable_obliqueLine, sizeof(moveTable)); diff --git a/src/movepick.cpp b/src/movepick.cpp index 36acf273..1b9aa729 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -21,9 +21,6 @@ #include "movepick.h" -// namespace -// { - // partial_insertion_sort() sorts moves in descending order up to and including // a given limit. The order of moves smaller than the limit is left unspecified. void partial_insertion_sort(ExtMove *begin, ExtMove *end, int limit) @@ -38,9 +35,6 @@ void partial_insertion_sort(ExtMove *begin, ExtMove *end, int limit) } } -//} - - /// Constructors of the MovePicker class. As arguments we pass information /// to help it to return the (presumably) good moves first, to decide which /// moves to return (in the quiescence search, for instance, we only want to @@ -180,7 +174,7 @@ Move MovePicker::select(Pred filter) Move MovePicker::next_move() { endMoves = generate(pos, moves); - moveCount = endMoves - moves; + moveCount = int(endMoves - moves); score(); partial_insertion_sort(moves, endMoves, -100); // TODO: limit = -3000 * depth diff --git a/src/movepick.h b/src/movepick.h index c6c70c77..eaffb7a9 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -107,34 +107,6 @@ enum StatsType NoCaptures, Captures }; -/// ButterflyHistory records how often quiet moves have been successful or -/// unsuccessful during the current search, and is used for reduction and move -/// ordering decisions. It uses 2 tables (one for each color) indexed by -/// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards -typedef Stats ButterflyHistory; - -/// LowPlyHistory at higher depths records successful quiet moves on plies 0 to 3 -/// and quiet moves which are/were in the PV (ttPv) -/// It get cleared with each new search and get filled during iterative deepening -constexpr int MAX_LPH = 4; -typedef Stats LowPlyHistory; - -/// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous -/// move, see www.chessprogramming.org/Countermove_Heuristic -typedef Stats CounterMoveHistory; - -/// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type] -typedef Stats CapturePieceToHistory; - -/// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to] -typedef Stats PieceToHistory; - -/// ContinuationHistory is the combined history of a given pair of moves, usually -/// the current one given a previous one. The nested history table is based on -/// PieceToHistory instead of ButterflyBoards. -typedef Stats ContinuationHistory; - - /// MovePicker class is used to pick one pseudo legal move at a time from the /// current position. The most important method is next_move(), which returns a /// new pseudo legal move each time it is called, until there are no moves left, @@ -155,7 +127,6 @@ public: Move next_move(); -//private: template Move select(Pred); template void score(); ExtMove *begin() diff --git a/src/option.cpp b/src/option.cpp index 7f0e0b6e..2e1c8b13 100644 --- a/src/option.cpp +++ b/src/option.cpp @@ -112,4 +112,3 @@ bool GameOptions::getOpeningBook() { return openingBook; } - diff --git a/src/position.cpp b/src/position.cpp index 2952d87c..80684bbe 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -125,25 +125,6 @@ std::ostream &operator<<(std::ostream &os, const Position &pos) } -// Marcel van Kervinck's cuckoo algorithm for fast detection of "upcoming repetition" -// situations. Description of the algorithm in the following paper: -// https://marcelk.net/2013-04-06/paper/upcoming-rep-v2.pdf - -// First and second hash functions for indexing the cuckoo tables -inline int H1(Key h) -{ - return h & 0x1fff; -} -inline int H2(Key h) -{ - return (h >> 16) & 0x1fff; -} - -// Cuckoo tables with Zobrist hashes of valid reversible moves, and the moves themselves -Key cuckoo[8192]; -Move cuckooMove[8192]; - - /// Position::init() initializes at startup the various arrays used to compute /// hash keys. @@ -157,18 +138,11 @@ void Position::init() Zobrist::side = rng.rand() << Zobrist::KEY_MISC_BIT >> Zobrist::KEY_MISC_BIT; - // Prepare the cuckoo tables - std::memset(cuckoo, 0, sizeof(cuckoo)); - std::memset(cuckooMove, 0, sizeof(cuckooMove)); - return; } Position::Position() { - // TODO - //st = &tmpSt; - construct_key(); if (rule == nullptr) { @@ -187,7 +161,7 @@ Position::Position() /// This function is not very robust - make sure that input FENs are correct, /// this is assumed to be the responsibility of the GUI. -Position &Position::set(const string &fenStr, StateInfo *si, Thread *th) +Position &Position::set(const string &fenStr, Thread *th) { /* A FEN string defines a particular position using only the ASCII character set. @@ -220,7 +194,6 @@ Position &Position::set(const string &fenStr, StateInfo *si, Thread *th) */ unsigned char token; - size_t idx; Square sq = SQ_A1; std::istringstream ss(fenStr); @@ -229,9 +202,6 @@ Position &Position::set(const string &fenStr, StateInfo *si, Thread *th) } std::memset(this, 0, sizeof(Position)); - //std::memset(si, 0, sizeof(StateInfo)); - //std::fill_n(&pieceList[0][0], sizeof(pieceList) / sizeof(Square), SQ_NONE); - //st = si; ss >> std::noskipws; @@ -302,7 +272,6 @@ Position &Position::set(const string &fenStr, StateInfo *si, Thread *th) gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == WHITE); thisThread = th; - //set_state(st); assert(pos_is_ok()); out: @@ -310,55 +279,6 @@ out: } -/// Position::set_state() computes the hash keys of the position, and other -/// data that once computed is updated incrementally as moves are made. -/// The function is only used when a new position is set up, and to verify -/// the correctness of the StateInfo data when running in debug mode. - -void Position::set_state(StateInfo *si) const -{ - // TODO -#if 0 - si->key = 0; - - for (Bitboard b = pieces(); b; ) { - Square s = pop_lsb(&b); - Piece pc = piece_on(s); - si->key ^= Zobrist::psq[pc][s]; - } - - if (sideToMove == BLACK) - si->key ^= Zobrist::side; -#endif -} - - - // TODO -#if 0 -/// Position::set() is an overload to initialize the position object with -/// the given endgame code string like "KBPKN". It is mainly a helper to -/// get the material key out of an endgame code. - -Position &Position::set(const string &code, Color c, StateInfo *si) -{ - assert(code[0] == 'K'); - - string sides[] = { code.substr(code.find('K', 1)), // Weak - code.substr(0, std::min(code.find('v'), code.find('K', 1))) }; // Strong - - assert(sides[0].length() > 0 && sides[0].length() < 8); - assert(sides[1].length() > 0 && sides[1].length() < 8); - - std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower); - - string fenStr = "8/" + sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/" - + sides[1] + char(8 - sides[1].length() + '0') + "/8 w - - 0 10"; - - return set(fenStr, si, nullptr); -} -#endif - - /// Position::fen() returns a FEN representation of the position. In case of /// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function. @@ -477,7 +397,7 @@ bool Position::pseudo_legal(const Move m) const /// to a StateInfo object. The move is assumed to be legal. Pseudo-legal /// moves should be filtered out before this function is called. -void Position::do_move(Move m, StateInfo &newSt) +void Position::do_move(Move m) { #if 0 assert(is_ok(m)); @@ -1204,27 +1124,24 @@ inline void Position::set_gameover(Color w, GameOverReason reason) winner = w; } -int Position::update() +void Position::update() { - int ret = -1; int timePoint = -1; time_t *ourSeconds = &elapsedSeconds[sideToMove]; time_t theirSeconds = elapsedSeconds[them]; if (!(phase & PHASE_PLAYING)) { - return -1; + return; } currentTime = time(NULL); if (timePoint >= *ourSeconds) { - *ourSeconds = ret = timePoint; + *ourSeconds = timePoint; startTime = currentTime - (elapsedSeconds[BLACK] + elapsedSeconds[WHITE]); } else { - *ourSeconds = ret = currentTime - startTime - theirSeconds; + *ourSeconds = currentTime - startTime - theirSeconds; } - - return ret; } void Position::update_score() diff --git a/src/position.h b/src/position.h index fd6c8e37..a59d589b 100644 --- a/src/position.h +++ b/src/position.h @@ -42,17 +42,8 @@ struct StateInfo // Not copied when making a move (will be recomputed anyhow) Key key; - Piece capturedPiece; - StateInfo *previous; - int repetition; }; -/// A list to keep track of the position states along the setup moves (from the -/// start position to the position just before the search starts). Needed by -/// 'draw by repetition' detection. Use a std::deque because pointers to -/// elements are not invalidated upon list resizing. -typedef std::unique_ptr> StateListPtr; - /// Position class stores information regarding the board representation as /// pieces, side to move, hash keys, castling info, etc. Important methods are @@ -71,8 +62,7 @@ public: Position &operator=(const Position &) = delete; // FEN string input/output - Position &set(const std::string &fenStr, StateInfo *si, Thread *th); - Position &set(const std::string &code, Color c, StateInfo *si); + Position &set(const std::string &fenStr, Thread *th); const std::string fen() const; // Position representation @@ -87,7 +77,7 @@ public: Piece moved_piece(Move m) const; // Doing and undoing moves - void do_move(Move m, StateInfo &newSt); + void do_move(Move m); void undo_move(Move m); void undo_move(Sanmill::Stack &ss); void do_null_move(); @@ -124,7 +114,6 @@ public: Piece *get_board() const; Square current_square() const; - int get_step() const; enum Phase get_phase() const; enum Action get_action() const; const char *cmd_line() const; @@ -135,7 +124,7 @@ public: bool start(); bool resign(Color loser); bool command(const char *cmd); - int update(); + void update(); void update_score(); bool check_gameover_condition(); void remove_ban_stones(); @@ -181,11 +170,9 @@ public: void put_piece(Piece pc, Square s); bool put_piece(File file, Rank rank); bool put_piece(Square s, bool updateCmdlist = false); - bool undo_put_piece(Square s); bool remove_piece(File file, Rank rank); bool remove_piece(Square s, bool updateCmdlist = false); - bool undo_remove_piece(Square s); bool move_piece(File f1, Rank r1, File f2, Rank r2); bool move_piece(Square from, Square to); @@ -323,10 +310,11 @@ inline bool Position::select_piece(File f, Rank r) return select_piece(make_square(f, r)); } +#if 0 inline void Position::put_piece(Piece pc, Square s) { // TODO: put_piece -#if 0 + board[s] = pc; byTypeBB[ALL_PIECES] |= s; byTypeBB[type_of(pc)] |= s; @@ -334,8 +322,8 @@ inline void Position::put_piece(Piece pc, Square s) index[s] = pieceCount[pc]++; pieceList[pc][index[s]] = s; pieceCount[make_piece(color_of(pc), ALL_PIECES)]++; -#endif } +#endif inline bool Position::put_piece(File f, Rank r) { diff --git a/src/rule.h b/src/rule.h index e3ee539b..09d82009 100644 --- a/src/rule.h +++ b/src/rule.h @@ -44,4 +44,3 @@ extern const struct Rule RULES[N_RULES]; extern const struct Rule *rule; #endif /* RULE_H */ - diff --git a/src/search.cpp b/src/search.cpp index 00eeaeee..b6bb0e40 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -31,7 +31,6 @@ #include "position.h" #include "search.h" #include "thread.h" -#include "timeman.h" #include "tt.h" #include "uci.h" @@ -39,21 +38,6 @@ #include "types.h" #include "option.h" -namespace Search -{ -LimitsType Limits; -} - -namespace Tablebases -{ -int Cardinality; -bool RootInTB; -bool UseRule50; -Depth ProbeDepth; -} - -namespace TB = Tablebases; - using std::string; using Eval::evaluate; using namespace Search; @@ -69,100 +53,6 @@ enum NodeType NonPV, PV }; -// Skill structure is used to implement strength limit -struct Skill -{ - explicit Skill(int l) : level(l) - { - } - bool enabled() const - { - return level < 20; - } - bool time_to_pick(Depth depth) const - { - return depth == 1 + level; - } - Move pick_best(size_t multiPV); - - int level; - Move best = MOVE_NONE; -}; - -// Breadcrumbs are used to mark nodes as being searched by a given thread -struct Breadcrumb -{ - std::atomic thread; - std::atomic key; -}; -std::array breadcrumbs; - -// ThreadHolding structure keeps track of which thread left breadcrumbs at the given -// node for potential reductions. A free node will be marked upon entering the moves -// loop by the constructor, and unmarked upon leaving that loop by the destructor. -struct ThreadHolding -{ - explicit ThreadHolding(Thread *thisThread, Key posKey, int ply) - { - location = ply < 8 ? &breadcrumbs[posKey & (breadcrumbs.size() - 1)] : nullptr; - otherThread = false; - owning = false; - if (location) { - // See if another already marked this location, if not, mark it ourselves - Thread *tmp = (*location).thread.load(std::memory_order_relaxed); - if (tmp == nullptr) { - (*location).thread.store(thisThread, std::memory_order_relaxed); - (*location).key.store(posKey, std::memory_order_relaxed); - owning = true; - } else if (tmp != thisThread - && (*location).key.load(std::memory_order_relaxed) == posKey) - otherThread = true; - } - } - - ~ThreadHolding() - { - if (owning) // Free the marked location - (*location).thread.store(nullptr, std::memory_order_relaxed); - } - - bool marked() - { - return otherThread; - } - -private: - Breadcrumb *location; - bool otherThread, owning; -}; - -template -Value search(Position &pos, Stack *ss, Value alpha, Value beta, Depth depth, bool cutNode); - -// perft() is our utility to verify move generation. All the leaf nodes up -// to the given depth are generated and counted, and the sum is returned. -template -uint64_t perft(Position &pos, Depth depth) -{ - StateInfo st; - uint64_t cnt, nodes = 0; - const bool leaf = (depth == 2); - - for (const auto &m : MoveList(pos)) { - if (Root && depth <= 1) - cnt = 1, nodes++; - else { - pos.do_move(m, st); - cnt = leaf ? MoveList(pos).size() : perft(pos, depth - 1); - nodes += cnt; - pos.undo_move(m); - } - if (Root) - sync_cout << UCI::move(m) << ": " << cnt << sync_endl; - } - return nodes; -} - } // namespace @@ -180,7 +70,6 @@ void Search::clear() { Threads.main()->wait_for_search_finished(); - Time.availableNodes = 0; #ifdef TRANSPOSITION_TABLE_ENABLE TT.clear(); #endif @@ -188,106 +77,6 @@ void Search::clear() } -/// MainThread::search() is started when the program receives the UCI 'go' -/// command. It searches from the root position and outputs the "bestmove". - -int MainThread::search() -{ - if (Limits.perft) { - nodes = perft(*rootPos, Limits.perft); - sync_cout << "\nNodes searched: " << nodes << "\n" << sync_endl; - return 0; - } - - Color us = rootPos->side_to_move(); - Time.init(Limits, us, rootPos->game_ply()); - //TT.new_search(); - - if (rootMoves.empty()) { - rootMoves.emplace_back(MOVE_NONE); - sync_cout << "info depth 0 score " - << UCI::value(rootPos->get_phase() == PHASE_GAMEOVER ? -VALUE_MATE : VALUE_DRAW) // TODO - << sync_endl; - } else { - for (Thread *th : Threads) { - th->bestMoveChanges = 0; - if (th != this) - th->start_searching(); - } - - Thread::search(); // Let's start searching! - } - - // When we reach the maximum depth, we can arrive here without a raise of - // Threads.stop. However, if we are pondering or in an infinite search, - // the UCI protocol states that we shouldn't print the best move before the - // GUI sends a "stop" or "ponderhit" command. We therefore simply wait here - // until the GUI sends one of those commands. - - while (!Threads.stop && (ponder || Limits.infinite)) { - } // Busy wait for a stop or a ponder reset - - // Stop the threads if not already stopped (also raise the stop if - // "ponderhit" just reset Threads.ponder). - Threads.stop = true; - - // Wait until all threads have finished - for (Thread *th : Threads) - if (th != this) - th->wait_for_search_finished(); - - // When playing in 'nodes as time' mode, subtract the searched nodes from - // the available ones before exiting. - if (Limits.npmsec) - Time.availableNodes += Limits.inc[us] - Threads.nodes_searched(); - - Thread *bestThread = this; - - // Check if there are threads with a better score than main thread - if (Options["MultiPV"] == 1 - && !Limits.depth - && !(Skill((int)Options["Skill Level"]).enabled() || Options["UCI_LimitStrength"]) - && rootMoves[0].pv[0] != MOVE_NONE) { - std::map votes; - Value minScore = this->rootMoves[0].score; - - // Find minimum score - for (Thread *th : Threads) - minScore = std::min(minScore, th->rootMoves[0].score); - - // Vote according to score and depth, and select the best thread - for (Thread *th : Threads) { - votes[th->rootMoves[0].pv[0]] += - (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth); - - if (abs(bestThread->rootMoves[0].score) >= VALUE_TB_WIN_IN_MAX_PLY) { - // Make sure we pick the shortest mate / TB conversion or stave off mate the longest - if (th->rootMoves[0].score > bestThread->rootMoves[0].score) - bestThread = th; - } else if (th->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY - || (th->rootMoves[0].score > VALUE_TB_LOSS_IN_MAX_PLY - && votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]])) - bestThread = th; - } - } - - bestPreviousScore = bestThread->rootMoves[0].score; - - // Send again PV info if we have a new best thread - if (bestThread != this) - sync_cout << UCI::pv(bestThread->rootPos, bestThread->completedDepth, -VALUE_INFINITE, VALUE_INFINITE) << sync_endl; - - sync_cout << "bestmove " << UCI::move(bestThread->rootMoves[0].pv[0]); - - if (bestThread->rootMoves[0].pv.size() > 1 /* || bestThread->rootMoves[0].extract_ponder_from_tt(rootPos) */) - std::cout << " ponder " << UCI::move(bestThread->rootMoves[0].pv[1]); - - std::cout << sync_endl; - - return 0; -} - - /// Thread::search() is the main iterative deepening loop. It calls search() /// repeatedly with increasing depth until the allocated thinking time has been /// consumed, the user stops the search, or the maximum search depth is reached. @@ -405,158 +194,17 @@ int Thread::search() } -namespace -{ - -// search<>() is the main search function for both PV and non-PV nodes - -template -Value search(Position &pos, Stack *ss, Value alpha, Value beta, Depth depth, bool cutNode) -{ - //return MTDF(rootPos, ss, value, i, adjustedDepth, bestMove); // TODO; - return VALUE_DRAW; -} - - -// When playing with strength handicap, choose best move among a set of RootMoves -// using a statistical rule dependent on 'level'. Idea by Heinz van Saanen. - -Move Skill::pick_best(size_t multiPV) -{ - - const RootMoves &rootMoves = Threads.main()->rootMoves; - static PRNG rng(now()); // PRNG sequence should be non-deterministic - - // RootMoves are already sorted by score in descending order - Value topScore = rootMoves[0].score; - //int delta = std::min(topScore - rootMoves[multiPV - 1].score, PawnValueMg); - int delta = std::min(topScore - rootMoves[multiPV - 1].score, StoneValue); - int weakness = 120 - 2 * level; - int maxScore = -VALUE_INFINITE; - - // Choose best move. For each move score we add two terms, both dependent on - // weakness. One is deterministic and bigger for weaker levels, and one is - // random. Then we choose the move with the resulting highest score. - for (size_t i = 0; i < multiPV; ++i) { - // This is our magic formula - int push = (weakness * int(topScore - rootMoves[i].score) - + delta * (rng.rand() % weakness)) / 128; - - if (rootMoves[i].score + push >= maxScore) { - maxScore = rootMoves[i].score + push; - best = rootMoves[i].pv[0]; - } - } - - return best; -} - -} // namespace - -/// MainThread::check_time() is used to print debug info and, more importantly, -/// to detect when we are out of available time and thus stop the search. - -void MainThread::check_time() -{ - if (--callsCnt > 0) - return; - - // When using nodes, ensure checking rate is not lower than 0.1% of nodes - callsCnt = Limits.nodes ? std::min(1024, int(Limits.nodes / 1024)) : 1024; - - static TimePoint lastInfoTime = now(); - - TimePoint elapsed = Time.elapsed(); - TimePoint tick = Limits.startTime + elapsed; - - if (tick - lastInfoTime >= 1000) { - lastInfoTime = tick; - dbg_print(); - } - - // We should not stop pondering until told so by the GUI - if (ponder) - return; - - if ((Limits.use_time_management() && (elapsed > Time.maximum() - 10 || stopOnPonderhit)) - || (Limits.movetime && elapsed >= Limits.movetime) - || (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes)) - Threads.stop = true; -} - - -/// UCI::pv() formats PV information according to the UCI protocol. UCI requires -/// that all (if any) unsearched PV lines are sent using a previous search score. - -string UCI::pv(const Position *pos, Depth depth, Value alpha, Value beta) -{ - - std::stringstream ss; - TimePoint elapsed = Time.elapsed() + 1; - const RootMoves &rootMoves = pos->this_thread()->rootMoves; - size_t pvIdx = pos->this_thread()->pvIdx; - size_t multiPV = std::min((size_t)Options["MultiPV"], rootMoves.size()); - uint64_t nodesSearched = Threads.nodes_searched(); - uint64_t tbHits = Threads.tb_hits() + (TB::RootInTB ? rootMoves.size() : 0); - - for (size_t i = 0; i < multiPV; ++i) { - bool updated = rootMoves[i].score != -VALUE_INFINITE; - - if (depth == 1 && !updated) - continue; - - Depth d = updated ? depth : depth - 1; - Value v = updated ? rootMoves[i].score : rootMoves[i].previousScore; - - bool tb = TB::RootInTB && abs(v) < VALUE_MATE_IN_MAX_PLY; - v = tb ? rootMoves[i].tbScore : v; - - if (ss.rdbuf()->in_avail()) // Not at first line - ss << "\n"; - - ss << "info" - << " depth " << d - << " seldepth " << rootMoves[i].selDepth - << " multipv " << i + 1 - << " score " << UCI::value(v); - - if (!tb && i == pvIdx) - ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : ""); - - ss << " nodes " << nodesSearched - << " nps " << nodesSearched * 1000 / elapsed; - -#if 0 - if (elapsed > 1000) // Earlier makes little sense - ss << " hashfull " << TT.hashfull(); -#endif - - ss << " tbhits " << tbHits - << " time " << elapsed - << " pv"; - - for (Move m : rootMoves[i].pv) - ss << " " << UCI::move(m); - } - - return ss.str(); -} - - /////////////////////////////////////////////////////////////////////////////// extern ThreadPool Threads; vector moveHistory; - Value search(Position *pos, Sanmill::Stack &ss, Depth depth, Depth originDepth, Value alpha, Value beta, Move &bestMove) { Value value; Value bestValue = -VALUE_INFINITE; - StateInfo st; // TODO - Depth epsilon; #ifdef TT_MOVE_ENABLE @@ -690,7 +338,7 @@ Value search(Position *pos, Sanmill::Stack &ss, Depth depth, Depth ori ss.push(*(pos)); Color before = pos->sideToMove; Move move = mp.moves[i].move; - pos->do_move(move, st); + pos->do_move(move); Color after = pos->sideToMove; if (gameOptions.getDepthExtension() == true && moveCount == 1) { diff --git a/src/search.h b/src/search.h index 0398e9e6..0dd3ca05 100644 --- a/src/search.h +++ b/src/search.h @@ -32,94 +32,10 @@ #include "stopwatch.h" #endif -class AIAlgorithm; -class Node; -class Position; -class MovePicker; - using namespace std; -using namespace CTSL; namespace Search { -/// Threshold used for countermoves based pruning -constexpr int CounterMovePruneThreshold = 0; - - -/// Stack struct keeps track of the information we need to remember from nodes -/// shallower and deeper in the tree during the search. Each search thread has -/// its own array of Stack objects, indexed by the current ply. - -struct Stack -{ - Move *pv; - PieceToHistory *continuationHistory; - int ply; - Move currentMove; - Move excludedMove; - Move killers[2]; - Value staticEval; - int statScore; - int moveCount; -}; - - -/// RootMove struct is used for moves at the root of the tree. For each root move -/// we store a score and a PV (really a refutation in the case of moves which -/// fail low). Score is normally set at -VALUE_INFINITE for all non-pv moves. - -struct RootMove -{ - explicit RootMove(Move m) : pv(1, m) - { - } - bool operator==(const Move &m) const - { - return pv[0] == m; - } - bool operator<(const RootMove &m) const - { // Sort in descending order - return m.score != score ? m.score < score - : m.previousScore < previousScore; - } - - Value score = -VALUE_INFINITE; - Value previousScore = -VALUE_INFINITE; - int selDepth = 0; - int tbRank = 0; - int bestMoveCount = 0; - Value tbScore; - std::vector pv; -}; - -typedef std::vector RootMoves; - - -/// LimitsType struct stores information sent by GUI about available time to -/// search the current move, maximum depth/time, or if we are in analysis mode. - -struct LimitsType -{ - LimitsType() - { - // Init explicitly due to broken value-initialization of non POD in MSVC - time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] = npmsec = movetime = TimePoint(0); - movestogo = depth = mate = perft = infinite = 0; - nodes = 0; - } - - bool use_time_management() const - { - return !(mate | movetime | depth | nodes | perft | infinite); - } - - std::vector searchmoves; - TimePoint time[COLOR_NB], inc[COLOR_NB], npmsec, movetime, startTime; - int movestogo, depth, mate, perft, infinite; - int64_t nodes; -}; - -extern LimitsType Limits; void init(); void clear(); diff --git a/src/thread.cpp b/src/thread.cpp index 0f72afce..ac077989 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -53,8 +53,6 @@ Thread::Thread(size_t n #endif timeLimit(3600) { - //this->us = color; - wait_for_search_finished(); } @@ -63,27 +61,17 @@ Thread::Thread(size_t n /// for its termination. Thread should be already waiting. Thread::~Thread() -{ - //delete server; - //delete client - +{ assert(!searching); exit = true; +#ifdef HOSTORY_HEURISTIC clearHistoryScore(); +#endif // HOSTORY_HEURISTIC start_searching(); stdThread.join(); } -/// Thread::bestMoveCount(Move move) return best move counter for the given root move - -int Thread::best_move_count(Move move) const -{ - // TODO - - return 0; -} - /// Thread::clear() reset histories, usually before a new game void Thread::clear() @@ -125,24 +113,8 @@ void Thread::wait_for_search_finished() void Thread::idle_loop() { -#ifdef DEBUG_MODE - int iTemp = 0; -#endif - - loggerDebug("Thread %d start\n", us); - bestvalue = lastvalue = VALUE_ZERO; -#if 0 - // If OS already scheduled us on a different group than 0 then don't overwrite - // the choice, eventually we are one of many one-threaded processes running on - // some Windows NUMA hardware, for instance in fishtest. To make it simple, - // just check if running threads are below a threshold, in this case all this - // NUMA machinery is not needed. - if (Options["Threads"] > 8) - WinProcGroup::bindThisThread(idx); -#endif - while (true) { std::unique_lock lk(mutex); searching = false; @@ -183,20 +155,16 @@ void Thread::idle_loop() strCommand = nextMove(); if (strCommand != "" && strCommand != "error!") { emitCommand(); - } else { - int err = 1; } } #ifdef OPENING_BOOK } #endif } - - loggerDebug("Thread %d quit\n", us); } -/////////////// +//////////////////////////////////////////////////////////////////////////// void Thread::setAi(Position *p) { @@ -517,9 +485,6 @@ void Thread::clearTT() } } - - - string Thread::nextMove() { #if 0 @@ -676,42 +641,18 @@ void ThreadPool::clear() { for (Thread *th : *this) th->clear(); - - main()->callsCnt = 0; - main()->bestPreviousScore = VALUE_INFINITE; - main()->previousTimeReduction = 1.0; } /// ThreadPool::start_thinking() wakes up main thread waiting in idle_loop() and /// returns immediately. Main thread will wake up other threads and start the search. -void ThreadPool::start_thinking(Position *pos, StateListPtr &states, - const Search::LimitsType &limits, bool ponderMode) +void ThreadPool::start_thinking(Position *pos, bool ponderMode) { main()->wait_for_search_finished(); -// main()->stopOnPonderhit = stop = false; -// increaseDepth = true; -// main()->ponder = ponderMode; -// Search::Limits = limits; -// Search::RootMoves rootMoves; - -// for (const auto &m : MoveList(*pos)) -// if (limits.searchmoves.empty() -// || std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m)) -// rootMoves.emplace_back(m); - -#ifdef TBPROBE - if (!rootMoves.empty()) - Tablebases::rank_root_moves(pos, rootMoves); -#endif - - // After ownership transfer 'states' becomes empty, so if we stop the search - // and call 'go' again without setting a new position states.get() == NULL. - //assert(states.get() || setupStates.get()); - - //if (states.get()) - // setupStates = std::move(states); // Ownership transfer, states is now empty + main()->stopOnPonderhit = stop = false; + increaseDepth = true; + main()->ponder = ponderMode; // We use Position::set() to set root position across threads. But there are // some StateInfo fields (previous, pliesFromNull, capturedPiece) that cannot @@ -721,14 +662,10 @@ void ThreadPool::start_thinking(Position *pos, StateListPtr &states, //StateInfo tmp = setupStates->back(); for (Thread *th : *this) { - //th->nodes = th->tbHits = th->nmpMinPly = 0; - //th->rootDepth = th->completedDepth = 0; - //th->rootMoves = rootMoves; + // TODO //th->rootPos->set(pos->fen(), &setupStates->back(), th); th->rootPos = pos; } - //setupStates->back() = tmp; - main()->start_searching(); } diff --git a/src/thread.h b/src/thread.h index b9a7f340..5be1fc3e 100644 --- a/src/thread.h +++ b/src/thread.h @@ -64,17 +64,8 @@ public: void idle_loop(); void start_searching(); void wait_for_search_finished(); - int best_move_count(Move move) const; - - size_t pvIdx, pvLast; - uint64_t ttHitAverage; - int selDepth, nmpMinPly; - Color nmpColor; - std::atomic nodes, tbHits, bestMoveChanges; Position *rootPos { nullptr }; - Search::RootMoves rootMoves; - Depth rootDepth, completedDepth; // Mill Game @@ -167,12 +158,6 @@ struct MainThread : public Thread { using Thread::Thread; - int search() /* override */; - void check_time(); - - double previousTimeReduction; - Value bestPreviousScore; - Value iterValue[4]; int callsCnt; bool stopOnPonderhit; std::atomic_bool ponder; @@ -185,7 +170,7 @@ struct MainThread : public Thread struct ThreadPool : public std::vector { - void start_thinking(Position *, StateListPtr &, const Search::LimitsType &, bool = false); + void start_thinking(Position *, bool = false); void clear(); void set(size_t); @@ -193,20 +178,10 @@ struct ThreadPool : public std::vector { return static_cast(front()); } - uint64_t nodes_searched() const - { - return accumulate(&Thread::nodes); - } - uint64_t tb_hits() const - { - return accumulate(&Thread::tbHits); - } std::atomic_bool stop, increaseDepth; private: - StateListPtr setupStates; - uint64_t accumulate(std::atomic Thread:: *member) const { uint64_t sum = 0; diff --git a/src/timeman.cpp b/src/timeman.cpp deleted file mode 100644 index d6aed47e..00000000 --- a/src/timeman.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - Fishmill, a UCI Mill Game playing engine derived from Stockfish - Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad (Stockfish author) - Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad (Stockfish author) - Copyright (C) 2020 Calcitem - - Fishmill 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. - - Fishmill 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. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include -#include -#include - -#include "search.h" -#include "timeman.h" -#include "uci.h" - -TimeManagement Time; // Our global time management object - -namespace -{ - -enum TimeType -{ - OptimumTime, MaxTime -}; - -constexpr int MoveHorizon = 50; // Plan time management at most this many moves ahead -constexpr double MaxRatio = 7.3; // When in trouble, we can step over reserved time with this ratio -constexpr double StealRatio = 0.34; // However we must not steal time from remaining moves over this ratio - - -// move_importance() is a skew-logistic function based on naive statistical -// analysis of "how many games are still undecided after n half-moves". Game -// is considered "undecided" as long as neither side has >275cp advantage. -// Data was extracted from the CCRL game database with some simple filtering criteria. - -double move_importance(int ply) -{ - constexpr double XScale = 6.85; - constexpr double XShift = 64.5; - constexpr double Skew = 0.171; - - return pow((1 + exp((ply - XShift) / XScale)), -Skew) + DBL_MIN; // Ensure non-zero -} - -template -TimePoint remaining(TimePoint myTime, int movesToGo, int ply, TimePoint slowMover) -{ - constexpr double TMaxRatio = (T == OptimumTime ? 1.0 : MaxRatio); - constexpr double TStealRatio = (T == OptimumTime ? 0.0 : StealRatio); - - double moveImportance = (move_importance(ply) * slowMover) / 100.0; - double otherMovesImportance = 0.0; - - for (int i = 1; i < movesToGo; ++i) - otherMovesImportance += move_importance(ply + 2 * i); - - double ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * moveImportance + otherMovesImportance); - double ratio2 = (moveImportance + TStealRatio * otherMovesImportance) / (moveImportance + otherMovesImportance); - - return TimePoint(myTime * std::min(ratio1, ratio2)); // Intel C++ asks for an explicit cast -} - -} // namespace - - -/// init() is called at the beginning of the search and calculates the allowed -/// thinking time out of the time control and current game ply. We support four -/// different kinds of time controls, passed in 'limits': -/// -/// inc == 0 && movestogo == 0 means: x basetime [sudden death!] -/// inc == 0 && movestogo != 0 means: x moves in y minutes -/// inc > 0 && movestogo == 0 means: x basetime + z increment -/// inc > 0 && movestogo != 0 means: x moves in y minutes + z increment - -void TimeManagement::init(Search::LimitsType &limits, Color us, int ply) -{ - TimePoint minThinkingTime = (TimePoint)Options["Minimum Thinking Time"]; - TimePoint moveOverhead = (TimePoint)Options["Move Overhead"]; - TimePoint slowMover = (TimePoint)Options["Slow Mover"]; - TimePoint npmsec = (TimePoint)Options["nodestime"]; - TimePoint hypMyTime; - - // If we have to play in 'nodes as time' mode, then convert from time - // to nodes, and use resulting values in time management formulas. - // WARNING: to avoid time losses, the given npmsec (nodes per millisecond) - // must be much lower than the real engine speed. - if (npmsec) { - if (!availableNodes) // Only once at game start - availableNodes = npmsec * limits.time[us]; // Time is in msec - - // Convert from milliseconds to nodes - limits.time[us] = TimePoint(availableNodes); - limits.inc[us] *= npmsec; - limits.npmsec = npmsec; - } - - startTime = limits.startTime; - optimumTime = maximumTime = std::max(limits.time[us], minThinkingTime); - - const int maxMTG = limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon; - - // We calculate optimum time usage for different hypothetical "moves to go" values - // and choose the minimum of calculated search time values. Usually the greatest - // hypMTG gives the minimum values. - for (int hypMTG = 1; hypMTG <= maxMTG; ++hypMTG) { - // Calculate thinking time for hypothetical "moves to go"-value - hypMyTime = limits.time[us] - + limits.inc[us] * (hypMTG - 1) - - moveOverhead * (2 + std::min(hypMTG, 40)); - - hypMyTime = std::max(hypMyTime, TimePoint(0)); - - TimePoint t1 = minThinkingTime + remaining(hypMyTime, hypMTG, ply, slowMover); - TimePoint t2 = minThinkingTime + remaining(hypMyTime, hypMTG, ply, slowMover); - - optimumTime = std::min(t1, optimumTime); - maximumTime = std::min(t2, maximumTime); - } - - if (Options["Ponder"]) - optimumTime += optimumTime / 4; -} diff --git a/src/timeman.h b/src/timeman.h deleted file mode 100644 index e44a3732..00000000 --- a/src/timeman.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - Fishmill, a UCI Mill Game playing engine derived from Stockfish - Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad (Stockfish author) - Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad (Stockfish author) - Copyright (C) 2020 Calcitem - - Fishmill 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. - - Fishmill 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. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifndef TIMEMAN_H_INCLUDED -#define TIMEMAN_H_INCLUDED - -#include "misc.h" -#include "search.h" -#include "thread.h" - -/// The TimeManagement class computes the optimal time to think depending on -/// the maximum available time, the game move number and other parameters. - -class TimeManagement { -public: - void init(Search::LimitsType& limits, Color us, int ply); - TimePoint optimum() const { return optimumTime; } - TimePoint maximum() const { return maximumTime; } - TimePoint elapsed() const { return Search::Limits.npmsec ? - TimePoint(Threads.nodes_searched()) : now() - startTime; } - - int64_t availableNodes; // When in 'nodes as time' mode - -private: - TimePoint startTime; - TimePoint optimumTime; - TimePoint maximumTime; -}; - -extern TimeManagement Time; - -#endif // #ifndef TIMEMAN_H_INCLUDED diff --git a/src/tt.cpp b/src/tt.cpp index 551ab7e1..1424e2d3 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -67,7 +67,7 @@ Value TranspositionTable::probe(const Key &key, break; case BOUND_UPPER: if (tte.value8 <= alpha) { - return alpha; // TODO: https://github.com/calcitem/NineChess/issues/25 + return alpha; // TODO: https://github.com/calcitem/Sanmill/issues/25 } break; case BOUND_LOWER: diff --git a/src/uci.cpp b/src/uci.cpp index 2f859788..cee51c8d 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -29,7 +29,6 @@ #include "position.h" #include "search.h" #include "thread.h" -#include "timeman.h" #include "tt.h" #include "uci.h" @@ -41,7 +40,7 @@ namespace { // FEN string of the initial position, normal mill game -const char *StartFEN = "********/********/******** b p p 0 12 0 12 0 0 1"; // Chess: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; +const char *StartFEN = "********/********/******** b p p 0 12 0 12 0 0 1"; // position() is called when engine receives the "position" UCI command. @@ -49,7 +48,7 @@ const char *StartFEN = "********/********/******** b p p 0 12 0 12 0 0 1"; // Ch // or the starting position ("startpos") and then makes the moves given in the // following move list ("moves"). -void position(Position *pos, istringstream &is, StateListPtr &states) +void position(Position *pos, istringstream &is) { Move m; string token, fen; @@ -65,13 +64,11 @@ void position(Position *pos, istringstream &is, StateListPtr &states) else return; - states = StateListPtr(new std::deque(1)); // Drop old and create a new one - pos->set(fen, &states->back(), Threads.main()); + pos->set(fen, Threads.main()); // Parse move list (if any) while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE) { - states->emplace_back(); - pos->do_move(m, states->back()); + pos->do_move(m); } } @@ -104,34 +101,10 @@ void setoption(istringstream &is) // the thinking time and other parameters from the input string, then starts // the search. -void go(Position *pos, istringstream &is, StateListPtr &states) +void go(Position *pos) { begin: - Search::LimitsType limits; - string token; - bool ponderMode = false; - - limits.startTime = now(); // As early as possible! - - while (is >> token) - if (token == "searchmoves") // Needs to be the last command on the line - while (is >> token) - limits.searchmoves.push_back(UCI::to_move(pos, token)); - - else if (token == "wtime") is >> limits.time[WHITE]; - else if (token == "btime") is >> limits.time[BLACK]; - else if (token == "winc") is >> limits.inc[WHITE]; - else if (token == "binc") is >> limits.inc[BLACK]; - else if (token == "movestogo") is >> limits.movestogo; - else if (token == "depth") is >> limits.depth; - else if (token == "nodes") is >> limits.nodes; - else if (token == "movetime") is >> limits.movetime; - else if (token == "mate") is >> limits.mate; - else if (token == "perft") is >> limits.perft; - else if (token == "infinite") limits.infinite = 1; - else if (token == "ponder") ponderMode = true; - - Threads.start_thinking(pos, states, limits, ponderMode); + Threads.start_thinking(pos); if (pos->get_phase() == PHASE_GAMEOVER) { @@ -140,7 +113,7 @@ begin: { } - pos->set(StartFEN, &states->back(), Threads.main()); + pos->set(StartFEN, Threads.main()); } goto begin; @@ -151,10 +124,10 @@ begin: // a list of UCI commands is setup according to bench parameters, then // it is run one by one printing a summary at the end. -void bench(Position *pos, istream &args, StateListPtr &states) +void bench(Position *pos, istream &args) { string token; - uint64_t num, nodes = 0, cnt = 1; + uint64_t num, cnt = 1; vector list = setup_bench(pos, args); num = count_if(list.begin(), list.end(), [](string s) { return s.find("go ") == 0 || s.find("eval") == 0; }); @@ -168,13 +141,12 @@ void bench(Position *pos, istream &args, StateListPtr &states) if (token == "go" || token == "eval") { cerr << "\nPosition: " << cnt++ << '/' << num << endl; if (token == "go") { - go(pos, is, states); + go(pos); Threads.main()->wait_for_search_finished(); - nodes += Threads.nodes_searched(); } else sync_cout << "\n" << Eval::trace(*pos) << sync_endl; } else if (token == "setoption") setoption(is); - else if (token == "position") position(pos, is, states); + else if (token == "position") position(pos, is); else if (token == "ucinewgame") { Search::clear(); elapsed = now(); } // Search::clear() may take some while @@ -186,8 +158,7 @@ void bench(Position *pos, istream &args, StateListPtr &states) cerr << "\n===========================" << "\nTotal time (ms) : " << elapsed - << "\nNodes searched : " << nodes - << "\nNodes/second : " << 1000 * nodes / elapsed << endl; + << endl; } } // namespace @@ -204,9 +175,8 @@ void UCI::loop(int argc, char *argv[]) Position *pos = new Position; string token, cmd; - StateListPtr states(new std::deque(1)); - pos->set(StartFEN, &states->back(), Threads.main()); + pos->set(StartFEN, Threads.main()); for (int i = 1; i < argc; ++i) cmd += std::string(argv[i]) + " "; @@ -237,15 +207,15 @@ void UCI::loop(int argc, char *argv[]) << "\nuciok" << sync_endl; else if (token == "setoption") setoption(is); - else if (token == "go") go(pos, is, states); - else if (token == "position") position(pos, is, states); + else if (token == "go") go(pos); + else if (token == "position") position(pos, is); else if (token == "ucinewgame") Search::clear(); else if (token == "isready") sync_cout << "readyok" << sync_endl; // Additional custom non-UCI commands, mainly for debugging. // Do not use these commands during a search! else if (token == "flip") pos->flip(); - else if (token == "bench") bench(pos, is, states); + else if (token == "bench") bench(pos, is); else if (token == "d") sync_cout << &pos << sync_endl; else if (token == "eval") sync_cout << Eval::trace(*pos) << sync_endl; else if (token == "compiler") sync_cout << compiler_info() << sync_endl; diff --git a/src/uci.h b/src/uci.h index b750c2f1..a8e835e1 100644 --- a/src/uci.h +++ b/src/uci.h @@ -73,7 +73,6 @@ void loop(int argc, char* argv[]); std::string value(Value v); std::string square(Square s); std::string move(Move m); -std::string pv(const Position* pos, Depth depth, Value alpha, Value beta); Move to_move(Position* pos, std::string& str); } // namespace UCI diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 332fb3b7..40c55591 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -29,7 +29,6 @@ #include "thread.h" #include "tt.h" #include "uci.h" -//#include "syzygy/tbprobe.h" using std::string; @@ -57,12 +56,6 @@ void on_threads(const Option &o) { Threads.set((size_t)o); } -#ifdef TBPROBE -void on_tb_path(const Option &o) -{ - Tablebases::init(o); -} -#endif /// Our case insensitive less() function as required by UCI protocol @@ -97,12 +90,6 @@ void init(OptionsMap &o) o["UCI_AnalyseMode"] << Option(false); o["UCI_LimitStrength"] << Option(false); o["UCI_Elo"] << Option(1350, 1350, 2850); -#ifdef TBPROBE - o["SyzygyPath"] << Option("", on_tb_path); - o["SyzygyProbeDepth"] << Option(1, 1, 100); - o["Syzygy50MoveRule"] << Option(true); - o["SyzygyProbeLimit"] << Option(7, 0, 7); -#endif } diff --git a/src/ui/qt/gamecontroller.cpp b/src/ui/qt/gamecontroller.cpp index 593570d5..dfa0d4fe 100644 --- a/src/ui/qt/gamecontroller.cpp +++ b/src/ui/qt/gamecontroller.cpp @@ -1048,7 +1048,7 @@ bool GameController::command(const string &cmd, bool update /* = true */) loggerDebug("Game Duration Time: %lldms\n", gameDurationTime); #ifdef TIME_STAT - loggerDebug("Sort Time: %ld + %ld = %ldms\n", + loggerDebug("Sort Time: %I64d + %I64d = %I64dms\n", aiThread[BLACK]->sortTime, aiThread[WHITE]->sortTime, (aiThread[BLACK]->sortTime + aiThread[WHITE]->sortTime)); aiThread[BLACK]->sortTime = aiThread[WHITE]->sortTime = 0;