X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=5e22ec4e806f769114521142a6ee249992a6bf32;hp=e8760b7372bb13a8edefa5155da39a1bfb854544;hb=67338e6f322b8f8ec0d897815e16a87937efc9b0;hpb=72d8d27234260df70b630b1606574b0f92b998f8 diff --git a/src/search.cpp b/src/search.cpp index e8760b73..5e22ec4e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1,7 +1,7 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) - Copyright (C) 2008-2010 Marco Costalba, Joona Kiiski, Tord Romstad + Copyright (C) 2008-2012 Marco Costalba, Joona Kiiski, Tord Romstad Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -46,9 +46,9 @@ namespace Search { Position RootPosition; } +using std::string; using std::cout; using std::endl; -using std::string; using namespace Search; namespace { @@ -67,7 +67,6 @@ namespace { RootMove(){} RootMove(Move m) { - nodes = 0; score = prevScore = -VALUE_INFINITE; pv.push_back(m); pv.push_back(MOVE_NONE); @@ -79,7 +78,6 @@ namespace { void extract_pv_from_tt(Position& pos); void insert_pv_in_tt(Position& pos); - int64_t nodes; Value score; Value prevScore; std::vector pv; @@ -149,7 +147,7 @@ namespace { TimeManager TimeMgr; int BestMoveChanges; int SkillLevel; - bool SkillLevelEnabled; + bool SkillLevelEnabled, Chess960; History H; @@ -190,50 +188,28 @@ namespace { MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, Stack* ss, Value b) : MovePicker(p, ttm, d, h, ss, b), mp(ss->sp->mp) {} - Move get_next_move() { return mp->get_next_move(); } + Move next_move() { return mp->next_move(); } 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) { // Test for a pawn pushed to 7th or a passed pawn move - if (type_of(pos.piece_on(move_from(m))) == PAWN) + if (type_of(pos.piece_on(from_sq(m))) == PAWN) { Color c = pos.side_to_move(); - if ( relative_rank(c, move_to(m)) == RANK_7 - || pos.pawn_is_passed(c, move_to(m))) + if ( relative_rank(c, to_sq(m)) == RANK_7 + || pos.pawn_is_passed(c, to_sq(m))) return true; } // Test for a capture that triggers a pawn endgame if ( captureOrPromotion - && type_of(pos.piece_on(move_to(m))) != PAWN + && type_of(pos.piece_on(to_sq(m))) != PAWN && ( pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) - - PieceValueMidgame[pos.piece_on(move_to(m))] == VALUE_ZERO) + - PieceValueMidgame[pos.piece_on(to_sq(m))] == VALUE_ZERO) && !is_special(m)) return true; @@ -276,22 +252,22 @@ void Search::init() { int64_t Search::perft(Position& pos, Depth depth) { StateInfo st; - int64_t sum = 0; + int64_t cnt = 0; MoveList ml(pos); // At the last ply just return the number of moves (leaf nodes) - if (depth <= ONE_PLY) + if (depth == ONE_PLY) return ml.size(); CheckInfo ci(pos); for ( ; !ml.end(); ++ml) { pos.do_move(ml.move(), st, ci, pos.move_gives_check(ml.move(), ci)); - sum += perft(pos, depth - ONE_PLY); + cnt += perft(pos, depth - ONE_PLY); pos.undo_move(ml.move()); } - return sum; + return cnt; } @@ -304,6 +280,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(); @@ -313,25 +290,17 @@ void Search::think() { // Populate RootMoves with all the legal moves (default) or, if a SearchMoves // 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())) + if (SearchMoves.empty() || 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["OwnBook"]) { - if (Options["Book File"].value() != book.name()) - book.open(Options["Book File"].value()); - - Move bookMove = book.probe(pos, Options["Best Book Move"].value()); + Move bookMove = book.probe(pos, Options["Book File"], Options["Best Book Move"]); - if ( bookMove != MOVE_NONE - && std::count(RootMoves.begin(), RootMoves.end(), bookMove)) + if (bookMove && count(RootMoves.begin(), RootMoves.end(), bookMove)) { - std::swap(RootMoves[0], *std::find(RootMoves.begin(), RootMoves.end(), bookMove)); - goto finish; + std::swap(RootMoves[0], *find(RootMoves.begin(), RootMoves.end(), bookMove)); + goto finalize; } } @@ -339,24 +308,24 @@ void Search::think() { read_evaluation_uci_options(pos.side_to_move()); Threads.read_uci_options(); - TT.set_size(Options["Hash"].value()); - if (Options["Clear Hash"].value()) + TT.set_size(Options["Hash"]); + if (Options["Clear Hash"]) { - Options["Clear Hash"].set_value("false"); + Options["Clear Hash"] = false; TT.clear(); } - UCIMultiPV = Options["MultiPV"].value(); - SkillLevel = Options["Skill Level"].value(); + UCIMultiPV = Options["MultiPV"]; + SkillLevel = Options["Skill Level"]; // Do we have to play with skill handicap? In this case enable MultiPV that // we will use behind the scenes to retrieve a set of possible moves. SkillLevelEnabled = (SkillLevel < 20); MultiPV = (SkillLevelEnabled ? std::max(UCIMultiPV, (size_t)4) : UCIMultiPV); - if (Options["Use Search Log"].value()) + if (Options["Use Search Log"]) { - Log log(Options["Search Log Filename"].value()); + Log log(Options["Search Log Filename"]); log << "\nSearching: " << pos.to_fen() << "\ninfinite: " << Limits.infinite << " ponder: " << Limits.ponder @@ -386,11 +355,11 @@ void Search::think() { Threads.set_timer(0); Threads.set_size(1); - if (Options["Use Search Log"].value()) + if (Options["Use Search Log"]) { int e = elapsed_time(); - Log log(Options["Search Log Filename"].value()); + Log log(Options["Search Log Filename"]); log << "Nodes: " << pos.nodes_searched() << "\nNodes/second: " << (e > 0 ? pos.nodes_searched() * 1000 / e : 0) << "\nBest move: " << move_to_san(pos, RootMoves[0].pv[0]); @@ -401,7 +370,7 @@ void Search::think() { pos.undo_move(RootMoves[0].pv[0]); } -finish: +finalize: // When we reach max depth we arrive here even without a StopRequest, but if // we are pondering or in infinite search, we shouldn't print the best move @@ -409,15 +378,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; } @@ -429,7 +392,7 @@ namespace { void id_loop(Position& pos) { - Stack ss[PLY_MAX_PLUS_2]; + Stack ss[MAX_PLY_PLUS_2]; int depth, prevBestMoveChanges; Value bestValue, alpha, beta, delta; bool bestMoveNeverChanged = true; @@ -440,10 +403,10 @@ namespace { bestValue = delta = -VALUE_INFINITE; ss->currentMove = MOVE_NULL; // Hack to skip update gains - // Handle the special case of a mate/stalemate position + // Handle the special case of a mated/stalemate position if (RootMoves.empty()) { - cout << "info depth 0" + cout << "info depth 0 score " << score_to_uci(pos.in_check() ? -VALUE_MATE : VALUE_DRAW) << endl; RootMoves.push_back(MOVE_NONE); @@ -451,7 +414,7 @@ namespace { } // Iterative deepening loop until requested to stop or target depth reached - while (!Signals.stop && ++depth <= PLY_MAX && (!Limits.maxDepth || depth <= Limits.maxDepth)) + while (!Signals.stop && ++depth <= MAX_PLY && (!Limits.maxDepth || depth <= Limits.maxDepth)) { // Save last iteration's scores before first PV line is searched and all // the move scores but the (new) PV are set to -VALUE_INFINITE. @@ -506,7 +469,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; @@ -542,7 +505,7 @@ namespace { if (SkillLevelEnabled && depth == 1 + SkillLevel) skillBest = do_skill_level(); - if (Options["Use Search Log"].value()) + if (Options["Use Search Log"]) pv_info_to_log(pos, depth, bestValue, elapsed_time(), &RootMoves[0].pv[0]); // Filter out startup noise when monitoring best move stability @@ -599,7 +562,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)); } } @@ -618,13 +581,12 @@ namespace { const bool SpNode = (NT == SplitPointPV || NT == SplitPointNonPV || NT == SplitPointRoot); const bool RootNode = (NT == Root || NT == SplitPointRoot); - assert(alpha >= -VALUE_INFINITE && alpha <= VALUE_INFINITE); - assert(beta > alpha && beta <= VALUE_INFINITE); - assert(PvNode || alpha == beta - 1); + assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE); + assert(PvNode == (alpha != beta - 1)); + assert(depth > DEPTH_ZERO); assert(pos.thread() >= 0 && pos.thread() < Threads.size()); Move movesSearched[MAX_MOVES]; - int64_t nodes; StateInfo st; const TTEntry *tte; Key posKey; @@ -667,14 +629,19 @@ namespace { // Step 2. Check for aborted search and immediate draw if (( Signals.stop || pos.is_draw() - || ss->ply > PLY_MAX) && !RootNode) + || ss->ply > MAX_PLY) && !RootNode) return VALUE_DRAW; - // Step 3. Mate distance pruning + // Step 3. Mate distance pruning. Even if we mate at the next move our score + // would be at best mate_in(ss->ply+1), but if alpha is already bigger because + // a shorter mate was found upward in the tree then there is no need to search + // further, we will never beat current alpha. Same logic but with reversed signs + // applies also in the opposite condition of being mated instead of giving mate, + // in this case return a fail-high score. if (!RootNode) { - alpha = std::max(value_mated_in(ss->ply), alpha); - beta = std::min(value_mate_in(ss->ply+1), beta); + alpha = std::max(mated_in(ss->ply), alpha); + beta = std::min(mate_in(ss->ply+1), beta); if (alpha >= beta) return alpha; } @@ -683,7 +650,7 @@ namespace { // We don't want the score of a partial search to overwrite a previous full search // TT value, so we use a different position key in case of an excluded move. excludedMove = ss->excludedMove; - posKey = excludedMove ? pos.get_exclusion_key() : pos.get_key(); + posKey = excludedMove ? pos.exclusion_key() : pos.key(); tte = TT.probe(posKey); ttMove = RootNode ? RootMoves[PVIdx].pv[0] : tte ? tte->move() : MOVE_NONE; @@ -731,10 +698,10 @@ namespace { if ( (move = (ss-1)->currentMove) != MOVE_NULL && (ss-1)->eval != VALUE_NONE && ss->eval != VALUE_NONE - && pos.captured_piece_type() == PIECE_TYPE_NONE + && pos.captured_piece_type() == NO_PIECE_TYPE && !is_special(move)) { - Square to = move_to(move); + Square to = to_sq(move); H.update_gain(pos.piece_on(to), to, -(ss-1)->eval - ss->eval); } @@ -744,7 +711,7 @@ namespace { && !inCheck && refinedValue + razor_margin(depth) < beta && ttMove == MOVE_NONE - && abs(beta) < VALUE_MATE_IN_PLY_MAX + && abs(beta) < VALUE_MATE_IN_MAX_PLY && !pos.has_pawn_on_7th(pos.side_to_move())) { Value rbeta = beta - razor_margin(depth); @@ -763,7 +730,7 @@ namespace { && depth < RazorDepth && !inCheck && refinedValue - futility_margin(depth, 0) >= beta - && abs(beta) < VALUE_MATE_IN_PLY_MAX + && abs(beta) < VALUE_MATE_IN_MAX_PLY && pos.non_pawn_material(pos.side_to_move())) return refinedValue - futility_margin(depth, 0); @@ -773,7 +740,7 @@ namespace { && depth > ONE_PLY && !inCheck && refinedValue >= beta - && abs(beta) < VALUE_MATE_IN_PLY_MAX + && abs(beta) < VALUE_MATE_IN_MAX_PLY && pos.non_pawn_material(pos.side_to_move())) { ss->currentMove = MOVE_NULL; @@ -795,7 +762,7 @@ namespace { if (nullValue >= beta) { // Do not return unproven mate scores - if (nullValue >= VALUE_MATE_IN_PLY_MAX) + if (nullValue >= VALUE_MATE_IN_MAX_PLY) nullValue = beta; if (depth < 6 * ONE_PLY) @@ -836,7 +803,7 @@ namespace { && !inCheck && !ss->skipNullMove && excludedMove == MOVE_NONE - && abs(beta) < VALUE_MATE_IN_PLY_MAX) + && abs(beta) < VALUE_MATE_IN_MAX_PLY) { Value rbeta = beta + 200; Depth rdepth = depth - ONE_PLY - 3 * ONE_PLY; @@ -846,7 +813,7 @@ namespace { MovePicker mp(pos, ttMove, H, pos.captured_piece_type()); CheckInfo ci(pos); - while ((move = mp.get_next_move()) != MOVE_NONE) + while ((move = mp.next_move()) != MOVE_NONE) if (pos.pl_move_is_legal(move, ci.pinned)) { pos.do_move(move, st, ci, pos.move_gives_check(move, ci)); @@ -897,7 +864,7 @@ split_point_start: // At split points actual search starts from here // Step 11. Loop through moves // Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs while ( bestValue < beta - && (move = mp.get_next_move()) != MOVE_NONE + && (move = mp.next_move()) != MOVE_NONE && !thread.cutoff_occurred()) { assert(is_ok(move)); @@ -908,7 +875,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 +892,11 @@ 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; } @@ -985,7 +949,7 @@ split_point_start: // At split points actual search starts from here && !dangerous && move != ttMove && !is_castle(move) - && (bestValue > VALUE_MATED_IN_PLY_MAX || bestValue == -VALUE_INFINITE)) + && (bestValue > VALUE_MATED_IN_MAX_PLY || bestValue == -VALUE_INFINITE)) { // Move count based pruning if ( moveCount >= futility_move_count(depth) @@ -1002,7 +966,7 @@ split_point_start: // At split points actual search starts from here // but fixing this made program slightly weaker. Depth predictedDepth = newDepth - reduction(depth, moveCount); futilityValue = futilityBase + futility_margin(predictedDepth, moveCount) - + H.gain(pos.piece_on(move_from(move)), move_to(move)); + + H.gain(pos.piece_on(from_sq(move)), to_sq(move)); if (futilityValue < beta) { @@ -1094,8 +1058,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); - rm.nodes += pos.nodes_searched() - nodes; + RootMove& rm = *find(RootMoves.begin(), RootMoves.end(), move); // PV move or new best move ? if (isPvMove || value > alpha) @@ -1154,7 +1117,7 @@ split_point_start: // At split points actual search starts from here // harmless because return value is discarded anyhow in the parent nodes. // If we are in a singular extension search then return a fail low score. if (!moveCount) - return excludedMove ? oldAlpha : inCheck ? value_mated_in(ss->ply) : VALUE_DRAW; + return excludedMove ? oldAlpha : inCheck ? mated_in(ss->ply) : VALUE_DRAW; // If we have pruned all the moves without searching return a fail-low score if (bestValue == -VALUE_INFINITE) @@ -1175,7 +1138,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]) { @@ -1185,13 +1150,13 @@ split_point_start: // At split points actual search starts from here // Increase history value of the cut-off move Value bonus = Value(int(depth) * int(depth)); - H.add(pos.piece_on(move_from(move)), move_to(move), bonus); + H.add(pos.piece_on(from_sq(move)), to_sq(move), bonus); // Decrease history of all the other played non-capture moves for (int i = 0; i < playedMoveCount - 1; i++) { Move m = movesSearched[i]; - H.add(pos.piece_on(move_from(m)), move_to(m), -bonus); + H.add(pos.piece_on(from_sq(m)), to_sq(m), -bonus); } } } @@ -1220,10 +1185,9 @@ split_point_start: // At split points actual search starts from here const bool PvNode = (NT == PV); assert(NT == PV || NT == NonPV); - assert(alpha >= -VALUE_INFINITE && alpha <= VALUE_INFINITE); - assert(beta >= -VALUE_INFINITE && beta <= VALUE_INFINITE); - assert(PvNode || alpha == beta - 1); - assert(depth <= 0); + assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE); + assert(PvNode == (alpha != beta - 1)); + assert(depth <= DEPTH_ZERO); assert(pos.thread() >= 0 && pos.thread() < Threads.size()); StateInfo st; @@ -1239,7 +1203,7 @@ split_point_start: // At split points actual search starts from here ss->ply = (ss-1)->ply + 1; // Check for an instant draw or maximum ply reached - if (pos.is_draw() || ss->ply > PLY_MAX) + if (pos.is_draw() || ss->ply > MAX_PLY) return VALUE_DRAW; // Decide whether or not to include checks, this fixes also the type of @@ -1250,7 +1214,7 @@ split_point_start: // At split points actual search starts from here // Transposition table lookup. At PV nodes, we don't use the TT for // pruning, but only for move ordering. - tte = TT.probe(pos.get_key()); + tte = TT.probe(pos.key()); ttMove = (tte ? tte->move() : MOVE_NONE); if (!PvNode && tte && can_return_tt(tte, ttDepth, beta, ss->ply)) @@ -1282,7 +1246,7 @@ split_point_start: // At split points actual search starts from here if (bestValue >= beta) { if (!tte) - TT.store(pos.get_key(), value_to_tt(bestValue, ss->ply), VALUE_TYPE_LOWER, DEPTH_NONE, MOVE_NONE, ss->eval, evalMargin); + TT.store(pos.key(), value_to_tt(bestValue, ss->ply), VALUE_TYPE_LOWER, DEPTH_NONE, MOVE_NONE, ss->eval, evalMargin); return bestValue; } @@ -1298,12 +1262,12 @@ split_point_start: // At split points actual search starts from here // to search the moves. Because the depth is <= 0 here, only captures, // queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will // be generated. - MovePicker mp(pos, ttMove, depth, H, move_to((ss-1)->currentMove)); + MovePicker mp(pos, ttMove, depth, H, to_sq((ss-1)->currentMove)); CheckInfo ci(pos); // Loop through the moves until no moves remain or a beta cutoff occurs while ( bestValue < beta - && (move = mp.get_next_move()) != MOVE_NONE) + && (move = mp.next_move()) != MOVE_NONE) { assert(is_ok(move)); @@ -1319,7 +1283,7 @@ split_point_start: // At split points actual search starts from here && !pos.is_passed_pawn_push(move)) { futilityValue = futilityBase - + PieceValueEndgame[pos.piece_on(move_to(move))] + + PieceValueEndgame[pos.piece_on(to_sq(move))] + (is_enpassant(move) ? PawnValueEndgame : VALUE_ZERO); if (futilityValue < beta) @@ -1340,7 +1304,7 @@ split_point_start: // At split points actual search starts from here // Detect non-capture evasions that are candidate to be pruned evasionPrunable = !PvNode && inCheck - && bestValue > VALUE_MATED_IN_PLY_MAX + && bestValue > VALUE_MATED_IN_MAX_PLY && !pos.is_capture(move) && !pos.can_castle(pos.side_to_move()); @@ -1396,14 +1360,14 @@ split_point_start: // At split points actual search starts from here // All legal moves have been searched. A special case: If we're in check // and no legal moves were found, it is checkmate. if (inCheck && bestValue == -VALUE_INFINITE) - return value_mated_in(ss->ply); + return mated_in(ss->ply); // Plies to mate from the root // Update transposition table move = bestValue <= oldAlpha ? MOVE_NONE : ss->bestMove; vt = bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT; - TT.store(pos.get_key(), value_to_tt(bestValue, ss->ply), vt, ttDepth, move, ss->eval, evalMargin); + TT.store(pos.key(), value_to_tt(bestValue, ss->ply), vt, ttDepth, move, ss->eval, evalMargin); assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); @@ -1423,8 +1387,8 @@ split_point_start: // At split points actual search starts from here Color them; Value futilityValue, bv = *bestValue; - from = move_from(move); - to = move_to(move); + from = from_sq(move); + to = to_sq(move); them = flip(pos.side_to_move()); ksq = pos.king_square(them); kingAtt = pos.attacks_from(ksq); @@ -1484,14 +1448,14 @@ split_point_start: // At split points actual search starts from here assert(is_ok(m2)); // Case 1: The moving piece is the same in both moves - f2 = move_from(m2); - t1 = move_to(m1); + f2 = from_sq(m2); + t1 = to_sq(m1); if (f2 == t1) return true; // Case 2: The destination square for m2 was vacated by m1 - t2 = move_to(m2); - f1 = move_from(m1); + t2 = to_sq(m2); + f1 = from_sq(m1); if (t2 == f1) return true; @@ -1521,30 +1485,31 @@ 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. + // "plies to mate from the current position". 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) { - if (v >= VALUE_MATE_IN_PLY_MAX) + if (v >= VALUE_MATE_IN_MAX_PLY) return v + ply; - if (v <= VALUE_MATED_IN_PLY_MAX) + if (v <= VALUE_MATED_IN_MAX_PLY) return v - ply; return v; } - // value_from_tt() is the inverse of value_to_tt(): It adjusts a mate score from - // the transposition table to a mate score corrected for the current ply. + // value_from_tt() is the inverse of value_to_tt(): It adjusts a mate score + // from the transposition table (where refers to the plies to mate/be mated + // from current position) to "plies to mate/be mated from the root". Value value_from_tt(Value v, int ply) { - if (v >= VALUE_MATE_IN_PLY_MAX) + if (v >= VALUE_MATE_IN_MAX_PLY) return v - ply; - if (v <= VALUE_MATED_IN_PLY_MAX) + if (v <= VALUE_MATED_IN_MAX_PLY) return v + ply; return v; @@ -1563,10 +1528,10 @@ split_point_start: // At split points actual search starts from here Square mfrom, mto, tfrom, tto; - mfrom = move_from(m); - mto = move_to(m); - tfrom = move_from(threat); - tto = move_to(threat); + mfrom = from_sq(m); + mto = to_sq(m); + tfrom = from_sq(threat); + tto = to_sq(threat); // Case 1: Don't prune moves which move the threatened piece if (mfrom == tto) @@ -1599,8 +1564,8 @@ split_point_start: // At split points actual search starts from here Value v = value_from_tt(tte->value(), ply); return ( tte->depth() >= depth - || v >= std::max(VALUE_MATE_IN_PLY_MAX, beta) - || v < std::min(VALUE_MATED_IN_PLY_MAX, beta)) + || v >= std::max(VALUE_MATE_IN_MAX_PLY, beta) + || v < std::min(VALUE_MATED_IN_MAX_PLY, beta)) && ( ((tte->type() & VALUE_TYPE_LOWER) && v >= beta) || ((tte->type() & VALUE_TYPE_UPPER) && v < beta)); @@ -1632,9 +1597,9 @@ split_point_start: // At split points actual search starts from here static int searchStartTime; if (reset) - searchStartTime = get_system_time(); + searchStartTime = system_time(); - return get_system_time() - searchStartTime; + return system_time() - searchStartTime; } @@ -1649,10 +1614,10 @@ split_point_start: // At split points actual search starts from here std::stringstream s; - if (abs(v) < VALUE_MATE - PLY_MAX * ONE_PLY) - s << " score cp " << int(v) * 100 / int(PawnValueMidgame); // Scale to centipawns + if (abs(v) < VALUE_MATE_IN_MAX_PLY) + s << "cp " << v * 100 / int(PawnValueMidgame); else - s << " score mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2; + s << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2; s << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : ""); @@ -1681,21 +1646,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; + + for (int j = 0; RootMoves[i].pv[j] != MOVE_NONE; j++) + s << " " << move_to_uci(RootMoves[i].pv[j], Chess960); - cout << "info" - << " depth " << d + cout << "info depth " << d << " seldepth " << selDepth - << (i == PVIdx ? score_to_uci(s, alpha, beta) : score_to_uci(s)) + << " score " << (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; } } @@ -1727,9 +1691,9 @@ split_point_start: // At split points actual search starts from here std::stringstream s; - if (v >= VALUE_MATE_IN_PLY_MAX) + if (v >= VALUE_MATE_IN_MAX_PLY) s << "#" << (VALUE_MATE - v + 1) / 2; - else if (v <= VALUE_MATED_IN_PLY_MAX) + else if (v <= VALUE_MATED_IN_MAX_PLY) s << "-#" << (VALUE_MATE + v) / 2; else s << std::setprecision(2) << std::fixed << std::showpos @@ -1743,14 +1707,13 @@ split_point_start: // At split points actual search starts from here const int64_t K = 1000; const int64_t M = 1000000; - StateInfo state[PLY_MAX_PLUS_2], *st = state; + StateInfo state[MAX_PLY_PLUS_2], *st = state; Move* m = pv; string san, padding; 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); @@ -1785,7 +1748,7 @@ split_point_start: // At split points actual search starts from here while (m != pv) pos.undo_move(*--m); - Log l(Options["Search Log Filename"].value()); + Log l(Options["Search Log Filename"]); l << s.str() << endl; } @@ -1800,7 +1763,7 @@ split_point_start: // At split points actual search starts from here static RKISS rk; // PRNG sequence should be not deterministic - for (int i = abs(get_system_time() % 50); i > 0; i--) + for (int i = abs(system_time() % 50); i > 0; i--) rk.rand(); // RootMoves are already sorted by score in descending order @@ -1842,7 +1805,7 @@ split_point_start: // At split points actual search starts from here void RootMove::extract_pv_from_tt(Position& pos) { - StateInfo state[PLY_MAX_PLUS_2], *st = state; + StateInfo state[MAX_PLY_PLUS_2], *st = state; TTEntry* tte; int ply = 1; Move m = pv[0]; @@ -1853,11 +1816,11 @@ split_point_start: // At split points actual search starts from here pv.push_back(m); pos.do_move(m, *st++); - while ( (tte = TT.probe(pos.get_key())) != NULL + while ( (tte = TT.probe(pos.key())) != NULL && tte->move() != MOVE_NONE && pos.is_pseudo_legal(tte->move()) && pos.pl_move_is_legal(tte->move(), pos.pinned_pieces()) - && ply < PLY_MAX + && ply < MAX_PLY && (!pos.is_draw() || ply < 2)) { pv.push_back(tte->move()); @@ -1876,7 +1839,7 @@ split_point_start: // At split points actual search starts from here void RootMove::insert_pv_in_tt(Position& pos) { - StateInfo state[PLY_MAX_PLUS_2], *st = state; + StateInfo state[MAX_PLY_PLUS_2], *st = state; TTEntry* tte; Key k; Value v, m = VALUE_NONE; @@ -1885,7 +1848,7 @@ split_point_start: // At split points actual search starts from here assert(pv[ply] != MOVE_NONE && pos.is_pseudo_legal(pv[ply])); do { - k = pos.get_key(); + k = pos.key(); tte = TT.probe(k); // Don't overwrite existing correct entries @@ -1952,7 +1915,7 @@ void Thread::idle_loop(SplitPoint* sp) { assert(!do_terminate); // Copy split point position and search stack and call search() - Stack ss[PLY_MAX_PLUS_2]; + Stack ss[MAX_PLY_PLUS_2]; SplitPoint* tsp = splitPoint; Position pos(*tsp->pos, threadID); @@ -2003,12 +1966,10 @@ void do_timer_event() { static int lastInfoTime; int e = elapsed_time(); - if (get_system_time() - lastInfoTime >= 1000 || !lastInfoTime) + if (system_time() - lastInfoTime >= 1000 || !lastInfoTime) { - lastInfoTime = get_system_time(); - - dbg_print_mean(); - dbg_print_hit_rate(); + lastInfoTime = system_time(); + dbg_print(); } if (Limits.ponder)