X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=eb19b51d9c994c5d11e8c9c7abfb195806e475af;hp=6d75cc3de34b7ee44021fd6b78b330791a8fb807;hb=9ba7f701ead00fd4a59841d457d15a15d3b84378;hpb=79b1a7417ffad171327a65ff80af7950f12fddfa diff --git a/src/search.cpp b/src/search.cpp index 6d75cc3d..eb19b51d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -203,8 +203,8 @@ namespace { // Extensions. Configurable UCI options // Array index 0 is used at non-PV nodes, index 1 at PV nodes. - Depth CheckExtension[2], SingleEvasionExtension[2], PawnPushTo7thExtension[2]; - Depth PassedPawnExtension[2], PawnEndgameExtension[2], MateThreatExtension[2]; + Depth CheckExtension[2], PawnPushTo7thExtension[2], PassedPawnExtension[2]; + Depth PawnEndgameExtension[2], MateThreatExtension[2]; // Minimum depth for use of singular extension const Depth SingularExtensionDepth[2] = { 8 * ONE_PLY /* non-PV */, 6 * ONE_PLY /* PV */}; @@ -233,11 +233,6 @@ namespace { template inline Depth reduction(Depth d, int mn) { return (Depth) ReductionMatrix[PV][Min(d / 2, 63)][Min(mn, 63)]; } - // Common adjustments - - // Search depth at iteration 1 - const Depth InitialDepth = ONE_PLY; - // Easy move margin. An easy move candidate must be at least this much // better than the second best move. const Value EasyMoveMargin = Value(0x200); @@ -294,7 +289,7 @@ namespace { } template - Depth extension(const Position& pos, Move m, bool captureOrPromotion, bool moveIsCheck, bool singleEvasion, bool mateThreat, bool* dangerous); + Depth extension(const Position& pos, Move m, bool captureOrPromotion, bool moveIsCheck, bool mateThreat, bool* dangerous); bool check_is_dangerous(Position &pos, Move move, Value futilityBase, Value beta, Value *bValue); bool connected_moves(const Position& pos, Move m1, Move m2); @@ -307,6 +302,7 @@ namespace { void update_history(const Position& pos, Move move, Depth depth, Move movesSearched[], int moveCount); void update_killers(Move m, Move killers[]); void update_gains(const Position& pos, Move move, Value before, Value after); + void qsearch_scoring(Position& pos, MoveStack* mlist, MoveStack* last); int current_search_time(); std::string value_to_uci(Value v); @@ -329,8 +325,8 @@ namespace { // before to search them. template<> struct MovePickerExt : public MovePicker { - MovePickerExt(const Position& p, Move, Depth d, const History& h, SearchStack* ss, Value b) - : MovePicker(p, Rml[0].pv[0], d, h, ss, b), firstCall(true) { + MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss, Value b) + : MovePicker(p, ttm, d, h, ss, b), firstCall(true) { Move move; Value score = VALUE_ZERO; @@ -359,7 +355,6 @@ namespace { return rm != Rml.end() ? rm->pv[0] : MOVE_NONE; } - int number_of_evasions() const { return (int)Rml.size(); } RootMoveList::iterator rm; bool firstCall; @@ -505,8 +500,6 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[ CheckExtension[1] = Options["Check Extension (PV nodes)"].value(); CheckExtension[0] = Options["Check Extension (non-PV nodes)"].value(); - SingleEvasionExtension[1] = Options["Single Evasion Extension (PV nodes)"].value(); - SingleEvasionExtension[0] = Options["Single Evasion Extension (non-PV nodes)"].value(); PawnPushTo7thExtension[1] = Options["Pawn Push to 7th Extension (PV nodes)"].value(); PawnPushTo7thExtension[0] = Options["Pawn Push to 7th Extension (non-PV nodes)"].value(); PassedPawnExtension[1] = Options["Passed Pawn Extension (PV nodes)"].value(); @@ -656,7 +649,7 @@ namespace { cout << "info depth " << iteration << endl; Rml.bestMoveChanges = researchCountFL = researchCountFH = 0; - depth = (iteration - 2) * ONE_PLY + InitialDepth; + depth = (iteration - 1) * ONE_PLY; // Calculate dynamic aspiration window based on previous iterations if (MultiPV == 1 && iteration >= 6 && abs(bestValues[iteration - 1]) < VALUE_KNOWN_WIN) @@ -791,9 +784,9 @@ namespace { ValueType vt; Value bestValue, value, oldAlpha; Value refinedValue, nullValue, futilityBase, futilityValueScaled; // Non-PV specific - bool isPvMove, isCheck, singleEvasion, singularExtensionNode, moveIsCheck, captureOrPromotion, dangerous; + bool isPvMove, isCheck, singularExtensionNode, moveIsCheck, captureOrPromotion, dangerous; bool mateThreat = false; - int moveCount = 0; + int moveCount = 0, playedMoveCount = 0; int threadID = pos.thread(); SplitPoint* sp = NULL; @@ -995,7 +988,6 @@ split_point_start: // At split points actual search starts from here MovePickerExt mp(pos, ttMove, depth, H, ss, (PvNode ? -VALUE_INFINITE : beta)); CheckInfo ci(pos); ss->bestMove = MOVE_NONE; - singleEvasion = !SpNode && isCheck && mp.number_of_evasions() == 1; futilityBase = ss->eval + ss->evalMargin; singularExtensionNode = !Root && !SpNode @@ -1027,7 +1019,7 @@ split_point_start: // At split points actual search starts from here else if (move == excludedMove) continue; else - movesSearched[moveCount++] = move; + moveCount++; if (Root) { @@ -1057,7 +1049,7 @@ split_point_start: // At split points actual search starts from here captureOrPromotion = pos.move_is_capture_or_promotion(move); // Step 11. Decide the new search depth - ext = extension(pos, move, captureOrPromotion, moveIsCheck, singleEvasion, mateThreat, &dangerous); + ext = extension(pos, move, captureOrPromotion, moveIsCheck, mateThreat, &dangerous); // Singular extension search. If all moves but one fail low on a search of (alpha-s, beta-s), // and just one fails high on (alpha, beta), then that move is singular and should be extended. @@ -1142,6 +1134,9 @@ split_point_start: // At split points actual search starts from here // Step 13. Make the move pos.do_move(move, st, ci, moveIsCheck); + if (!SpNode && !captureOrPromotion) + movesSearched[playedMoveCount++] = move; + // Step extra. pv search (only in PV nodes) // The first move in list is the expected PV if (isPvMove) @@ -1321,7 +1316,7 @@ split_point_start: // At split points actual search starts from here if ( bestValue >= beta && !pos.move_is_capture_or_promotion(move)) { - update_history(pos, move, depth, movesSearched, moveCount); + update_history(pos, move, depth, movesSearched, playedMoveCount); update_killers(move, ss->killers); } } @@ -1524,6 +1519,26 @@ split_point_start: // At split points actual search starts from here } + // qsearch_scoring() scores each move of a list using a qsearch() evaluation, + // it is used in RootMoveList to get an initial scoring. + void qsearch_scoring(Position& pos, MoveStack* mlist, MoveStack* last) { + + SearchStack ss[PLY_MAX_PLUS_2]; + StateInfo st; + + memset(ss, 0, 4 * sizeof(SearchStack)); + ss[0].eval = ss[0].evalMargin = VALUE_NONE; + + for (MoveStack* cur = mlist; cur != last; cur++) + { + ss[0].currentMove = cur->move; + pos.do_move(cur->move, st); + cur->score = -qsearch(pos, ss+1, -VALUE_INFINITE, VALUE_INFINITE, DEPTH_ZERO, 1); + pos.undo_move(cur->move); + } + } + + // check_is_dangerous() tests if a checking move can be pruned in qsearch(). // bestValue is updated only when returning false because in that case move // will be pruned. @@ -1684,22 +1699,19 @@ split_point_start: // At split points actual search starts from here // extended, as example because the corresponding UCI option is set to zero, // the move is marked as 'dangerous' so, at least, we avoid to prune it. template - Depth extension(const Position& pos, Move m, bool captureOrPromotion, bool moveIsCheck, - bool singleEvasion, bool mateThreat, bool* dangerous) { + Depth extension(const Position& pos, Move m, bool captureOrPromotion, + bool moveIsCheck, bool mateThreat, bool* dangerous) { assert(m != MOVE_NONE); Depth result = DEPTH_ZERO; - *dangerous = moveIsCheck | singleEvasion | mateThreat; + *dangerous = moveIsCheck | mateThreat; if (*dangerous) { if (moveIsCheck && pos.see_sign(m) >= 0) result += CheckExtension[PvNode]; - if (singleEvasion) - result += SingleEvasionExtension[PvNode]; - if (mateThreat) result += MateThreatExtension[PvNode]; } @@ -1833,8 +1845,7 @@ split_point_start: // At split points actual search starts from here assert(m != move); - if (!pos.move_is_capture_or_promotion(m)) - H.update(pos.piece_on(move_from(m)), move_to(m), -bonus); + H.update(pos.piece_on(move_from(m)), move_to(m), -bonus); } } @@ -1844,11 +1855,11 @@ split_point_start: // At split points actual search starts from here void update_killers(Move m, Move killers[]) { - if (m == killers[0]) - return; - - killers[1] = killers[0]; - killers[0] = m; + if (m != killers[0]) + { + killers[1] = killers[0]; + killers[0] = m; + } } @@ -2562,19 +2573,15 @@ split_point_start: // At split points actual search starts from here void RootMoveList::init(Position& pos, Move searchMoves[]) { - SearchStack ss[PLY_MAX_PLUS_2]; MoveStack mlist[MOVES_MAX]; - StateInfo st; Move* sm; - // Initialize search stack - memset(ss, 0, PLY_MAX_PLUS_2 * sizeof(SearchStack)); - ss[0].eval = ss[0].evalMargin = VALUE_NONE; - bestMoveChanges = 0; clear(); + bestMoveChanges = 0; - // Generate all legal moves + // Generate all legal moves and score them MoveStack* last = generate(pos, mlist); + qsearch_scoring(pos, mlist, last); // Add each move to the RootMoveList's vector for (MoveStack* cur = mlist; cur != last; cur++) @@ -2586,16 +2593,11 @@ split_point_start: // At split points actual search starts from here if (searchMoves[0] && *sm != cur->move) continue; - // Find a quick score for the move and add to the list - pos.do_move(cur->move, st); - RootMove rm; - rm.pv[0] = ss[0].currentMove = cur->move; + rm.pv[0] = cur->move; rm.pv[1] = MOVE_NONE; - rm.pv_score = -qsearch(pos, ss+1, -VALUE_INFINITE, VALUE_INFINITE, DEPTH_ZERO, 1); + rm.pv_score = Value(cur->score); push_back(rm); - - pos.undo_move(cur->move); } sort(); }