From 9f94d2280110a1ba5eb9eb15b0756883037a817d Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sat, 2 Feb 2013 06:44:20 +0100 Subject: [PATCH] Restore "fail-low of reduced" and close regression This reverts "Threat Extensions" and is the last of this revert series. In single-thread tests we should now be on par with 2.3.1 --- src/search.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index c516f3c4..e8809f14 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -99,6 +99,7 @@ namespace { Value value_to_tt(Value v, int ply); Value value_from_tt(Value v, int ply); bool check_is_dangerous(Position& pos, Move move, Value futilityBase, Value beta); + bool allows_move(const Position& pos, Move first, Move second); bool prevents_move(const Position& pos, Move first, Move second); string uci_pv(const Position& pos, int depth, Value alpha, Value beta); @@ -692,9 +693,21 @@ namespace { return nullValue; } else + { // The null move failed low, which means that we may be faced with - // some kind of threat. + // some kind of threat. If the previous move was reduced, check if + // the move that refuted the null move was somehow connected to the + // move which was reduced. If a connection is found, return a fail + // low score (which will cause the reduced move to fail high in the + // parent node, which will trigger a re-search with full depth). threatMove = (ss+1)->currentMove; + + if ( depth < 5 * ONE_PLY + && (ss-1)->reduction + && threatMove != MOVE_NONE + && allows_move(pos, (ss-1)->currentMove, threatMove)) + return beta - 1; + } } // Step 9. ProbCut (is omitted in PV nodes) @@ -847,12 +860,13 @@ split_point_start: // At split points actual search starts from here && !inCheck && !dangerous && move != ttMove - && (!threatMove || !prevents_move(pos, move, threatMove)) && (bestValue > VALUE_MATED_IN_MAX_PLY || ( bestValue == -VALUE_INFINITE && alpha > VALUE_MATED_IN_MAX_PLY))) { // Move count based pruning - if (depth < 16 * ONE_PLY && moveCount >= FutilityMoveCounts[depth]) + if ( depth < 16 * ONE_PLY + && moveCount >= FutilityMoveCounts[depth] + && (!threatMove || !prevents_move(pos, move, threatMove))) { if (SpNode) sp->mutex.lock(); @@ -1352,6 +1366,47 @@ split_point_start: // At split points actual search starts from here } + // allows_move() tests whether the move at previous ply (first) somehow makes a + // second move possible, for instance if the moving piece is the same in both + // moves. Normally the second move is the threat move (the best move returned + // from a null search that fails low). + + bool allows_move(const Position& pos, Move first, Move second) { + + assert(is_ok(first)); + assert(is_ok(second)); + assert(color_of(pos.piece_on(from_sq(second))) == ~pos.side_to_move()); + assert(color_of(pos.piece_on(to_sq(first))) == ~pos.side_to_move()); + + Square m1from = from_sq(first); + Square m2from = from_sq(second); + Square m1to = to_sq(first); + Square m2to = to_sq(second); + + // The piece is the same or second's destination was vacated by the first move + if (m1to == m2from || m2to == m1from) + return true; + + // Second one moves through the square vacated by first one + if (between_bb(m2from, m2to) & m1from) + return true; + + // Second's destination is defended by the first move's piece + Bitboard m1att = pos.attacks_from(pos.piece_on(m1to), m1to, pos.pieces() ^ m2from); + if (m1att & m2to) + return true; + + // Second move gives a discovered check through the first's checking piece + if (m1att & pos.king_square(pos.side_to_move())) + { + assert(between_bb(m1to, pos.king_square(pos.side_to_move())) & m2from); + return true; + } + + return false; + } + + // prevents_move() tests whether a move (first) is able to defend against an // opponent's move (second). In this case will not be pruned. Normally the // second move is the threat move (the best move returned from a null search -- 2.39.2