X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=35a396814d676f4878738150ddd129d20e551bb1;hp=9f617210662d1ead5f8347b3a497976d3f26e7df;hb=96d3b1c92b8db7d2238fc4993a4f3da49f04d614;hpb=07989712afa57e2542835980d8c518d79d90f36b diff --git a/src/search.cpp b/src/search.cpp index 9f617210..35a39681 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -62,10 +62,6 @@ namespace { // Different node types, used as template parameter enum NodeType { Root, PV, NonPV, SplitPointRoot, SplitPointPV, SplitPointNonPV }; - // Lookup table to check if a Piece is a slider and its access function - const bool Slidings[18] = { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1 }; - inline bool piece_is_slider(Piece p) { return Slidings[p]; } - // Dynamic razoring margin based on depth inline Value razor_margin(Depth d) { return Value(512 + 16 * int(d)); } @@ -100,11 +96,11 @@ namespace { Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth); void id_loop(Position& pos); - bool check_is_dangerous(Position& pos, Move move, Value futilityBase, Value beta); - bool yields_to_threat(const Position& pos, Move move, Move threat); Value value_to_tt(Value v, int ply); Value value_from_tt(Value v, int ply); - bool connected_threat(const Position& pos, Move m, Move threat); + bool check_is_dangerous(Position& pos, Move move, Value futilityBase, Value beta); + bool yields_to_threat(const Position& pos, Move move, Move threat); + bool prevents_threat(const Position& pos, Move move, Move threat); string uci_pv(const Position& pos, int depth, Value alpha, Value beta); struct Skill { @@ -487,7 +483,8 @@ namespace { Depth ext, newDepth; Value bestValue, value, ttValue; Value eval, nullValue, futilityValue; - bool inCheck, givesCheck, pvMove, singularExtensionNode; + CheckType givesCheck; + bool inCheck, pvMove, singularExtensionNode; bool captureOrPromotion, dangerous, doFullDepthSearch; int moveCount, playedMoveCount; @@ -819,7 +816,7 @@ split_point_start: // At split points actual search starts from here if (PvNode && dangerous) ext = ONE_PLY; - else if (givesCheck && pos.see_sign(move) >= 0) + else if (givesCheck && (givesCheck == DISCO_CHECK || pos.see_sign(move) >= 0)) ext = ONE_PLY / 2; // Singular extension search. If all moves but one fail low on a search of @@ -861,7 +858,7 @@ split_point_start: // At split points actual search starts from here // Move count based pruning if ( depth < 16 * ONE_PLY && moveCount >= FutilityMoveCounts[depth] - && (!threatMove || !connected_threat(pos, move, threatMove))) + && (!threatMove || !prevents_threat(pos, move, threatMove))) { if (SpNode) sp->mutex.lock(); @@ -886,6 +883,7 @@ split_point_start: // At split points actual search starts from here // Prune moves with negative SEE at low depths if ( predictedDepth < 2 * ONE_PLY + && givesCheck != DISCO_CHECK && pos.see_sign(move) < 0) { if (SpNode) @@ -1020,8 +1018,12 @@ split_point_start: // At split points actual search starts from here && depth >= Threads.min_split_depth() && bestValue < beta && Threads.available_slave_exists(thisThread)) + { bestValue = Threads.split(pos, ss, alpha, beta, bestValue, &bestMove, depth, threatMove, moveCount, mp, NT); + if (bestValue >= beta) + break; + } } if (SpNode) @@ -1102,11 +1104,13 @@ split_point_start: // At split points actual search starts from here Key posKey; Move ttMove, move, bestMove; Value bestValue, value, ttValue, futilityValue, futilityBase; - bool givesCheck, enoughMaterial, evasionPrunable; + CheckType givesCheck; + bool enoughMaterial, evasionPrunable, fromNull; Depth ttDepth; ss->currentMove = bestMove = MOVE_NONE; ss->ply = (ss-1)->ply + 1; + fromNull = (ss-1)->currentMove == MOVE_NULL; // Check for an instant draw or maximum ply reached if (pos.is_draw() || ss->ply > MAX_PLY) @@ -1144,7 +1148,12 @@ split_point_start: // At split points actual search starts from here } else { - if (tte) + if (fromNull) + { + ss->staticEval = bestValue = -(ss-1)->staticEval; + ss->evalMargin = VALUE_ZERO; + } + else if (tte) { assert(tte->static_value() != VALUE_NONE || Threads.size() > 1); @@ -1192,6 +1201,7 @@ split_point_start: // At split points actual search starts from here if ( !PvNode && !InCheck && !givesCheck + && !fromNull && move != ttMove && enoughMaterial && type_of(move) != PROMOTION @@ -1227,6 +1237,7 @@ split_point_start: // At split points actual search starts from here if ( !PvNode && (!InCheck || evasionPrunable) && move != ttMove + && givesCheck != DISCO_CHECK && type_of(move) != PROMOTION && pos.see_sign(move) < 0) continue; @@ -1363,32 +1374,30 @@ split_point_start: // At split points actual search starts from here assert(is_ok(move)); assert(is_ok(threat)); + assert(color_of(pos.piece_on(from_sq(threat))) == ~pos.side_to_move()); - Square t1 = to_sq(move); - Square f1 = from_sq(move); - Square t2 = to_sq(threat); - Square f2 = from_sq(threat); - - // We are suposed to be called upon returning from a null search - assert(color_of(pos.piece_on(f2)) == ~pos.side_to_move()); + Square mfrom = from_sq(move); + Square mto = to_sq(move); + Square tfrom = from_sq(threat); + Square tto = to_sq(threat); // The piece is the same or threat's destination was vacated by the move - if (t1 == f2 || t2 == f1) + if (mto == tfrom || tto == mfrom) return true; // Threat moves through the vacated square - if (between_bb(f2, t2) & f1) + if (between_bb(tfrom, tto) & mfrom) return true; // Threat's destination is defended by the move's piece - Bitboard t1_att = pos.attacks_from(pos.piece_on(t1), t1, pos.pieces() ^ f2); - if (t1_att & t2) + Bitboard matt = pos.attacks_from(pos.piece_on(mto), mto, pos.pieces() ^ tfrom); + if (matt & tto) return true; // Threat gives a discovered check through the move's checking piece - if (t1_att & pos.king_square(pos.side_to_move())) + if (matt & pos.king_square(pos.side_to_move())) { - assert(between_bb(t1, pos.king_square(pos.side_to_move())) & f2); + assert(between_bb(mto, pos.king_square(pos.side_to_move())) & tfrom); return true; } @@ -1396,27 +1405,28 @@ split_point_start: // At split points actual search starts from here } - // connected_threat() tests whether it is safe to forward prune a move or if - // is somehow connected to the threat move returned by null search. + // prevents_threat() tests whether a move is able to defend against the so + // called threat move (the best move returned from a null search that fails + // low). In this case will not be pruned. - bool connected_threat(const Position& pos, Move m, Move threat) { + bool prevents_threat(const Position& pos, Move move, Move threat) { - assert(is_ok(m)); + assert(is_ok(move)); assert(is_ok(threat)); - assert(!pos.is_capture_or_promotion(m)); - assert(!pos.is_passed_pawn_push(m)); + assert(!pos.is_capture_or_promotion(move)); + assert(!pos.is_passed_pawn_push(move)); - Square mfrom = from_sq(m); - Square mto = to_sq(m); + Square mfrom = from_sq(move); + Square mto = to_sq(move); Square tfrom = from_sq(threat); Square tto = to_sq(threat); - // Case 1: Don't prune moves which move the threatened piece + // Don't prune moves of the threatened piece if (mfrom == tto) return true; - // Case 2: If the threatened piece has value less than or equal to the - // value of the threatening piece, don't prune moves which defend it. + // If the threatened piece has value less than or equal to the value of the + // threat piece, don't prune moves which defend it. if ( pos.is_capture(threat) && ( PieceValue[MG][pos.piece_on(tfrom)] >= PieceValue[MG][pos.piece_on(tto)] || type_of(pos.piece_on(tfrom)) == KING)) @@ -1438,11 +1448,8 @@ split_point_start: // At split points actual search starts from here return true; } - // Case 3: If the moving piece in the threatened move is a slider, don't - // prune safe moves which block its ray. - if ( piece_is_slider(pos.piece_on(tfrom)) - && (between_bb(tfrom, tto) & mto) - && pos.see_sign(m) >= 0) + // Don't prune safe moves which block the threat path + if ((between_bb(tfrom, tto) & mto) && pos.see_sign(move) >= 0) return true; return false;