From 6596dc9516c34701297ad78bfcc9790b0f422627 Mon Sep 17 00:00:00 2001 From: Joona Kiiski Date: Sun, 12 Dec 2010 11:54:50 +0200 Subject: [PATCH] Selective checks at qsearch After 5821 games Mod- Orig: 1014 - 869 - 3938 ELO +8 (+- 3.6) LOS 97% Signed-off-by: Marco Costalba --- src/search.cpp | 116 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 106 insertions(+), 10 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index b6493837..6f1f5761 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1448,6 +1448,89 @@ split_point_start: // At split points actual search starts from here return bestValue; } + Bitboard attacks(const Piece P, const Square sq, const Bitboard occ) + { + switch(P) + { + case WP: + case BP: + case WN: + case BN: + case WK: + case BK: + return StepAttackBB[P][sq]; + case WB: + case BB: + return bishop_attacks_bb(sq, occ); + case WR: + case BR: + return rook_attacks_bb(sq, occ); + case WQ: + case BQ: + return bishop_attacks_bb(sq, occ) | rook_attacks_bb(sq, occ); + default: + assert(false); + return 0ULL; + } + } + + bool check_is_useless(Position &pos, Move move, Value eval, Value futilityBase, Value beta, Value *bValue) + { + Value bestValue = *bValue; + + /// Rule 1. Using checks to reposition pieces when close to beta + if (eval + PawnValueMidgame / 4 < beta) + { + if (eval + PawnValueMidgame / 4 > bestValue) + bestValue = eval + PawnValueMidgame / 4; + } + else + return false; + + Square from = move_from(move); + Square to = move_to(move); + Color oppColor = opposite_color(pos.side_to_move()); + Square oppKing = pos.king_square(oppColor); + + Bitboard occ = pos.occupied_squares() & ~(1ULL << from) & ~(1ULL <= beta && pos.see_sign(make_move(from, victimSq)) >= 0) + return false; + + if (futilityValue > bestValue) + bestValue = futilityValue; + } + + *bValue = bestValue; + return true; + } // qsearch() is the quiescence search function, which is called by the main // search function when the remaining depth is zero (or, to be more precise, @@ -1466,7 +1549,7 @@ split_point_start: // At split points actual search starts from here StateInfo st; Move ttMove, move; Value bestValue, value, evalMargin, futilityValue, futilityBase; - bool isCheck, deepChecks, enoughMaterial, moveIsCheck, evasionPrunable; + bool isCheck, enoughMaterial, moveIsCheck, evasionPrunable; const TTEntry* tte; Value oldAlpha = alpha; @@ -1476,25 +1559,32 @@ split_point_start: // At split points actual search starts from here if (pos.is_draw() || ply >= PLY_MAX - 1) return VALUE_DRAW; + // Decide whether or not to include checks + isCheck = pos.is_check(); + + Depth d; + if (isCheck || depth >= -ONE_PLY) + d = DEPTH_ZERO; + else + d = DEPTH_ZERO - ONE_PLY; + // Transposition table lookup. At PV nodes, we don't use the TT for // pruning, but only for move ordering. tte = TT.retrieve(pos.get_key()); ttMove = (tte ? tte->move() : MOVE_NONE); - if (!PvNode && tte && ok_to_use_TT(tte, depth, beta, ply)) + if (!PvNode && tte && ok_to_use_TT(tte, d, beta, ply)) { ss->bestMove = ttMove; // Can be MOVE_NONE return value_from_tt(tte->value(), ply); } - isCheck = pos.is_check(); - // Evaluate the position statically if (isCheck) { bestValue = futilityBase = -VALUE_INFINITE; ss->eval = evalMargin = VALUE_NONE; - deepChecks = enoughMaterial = false; + enoughMaterial = false; } else { @@ -1522,9 +1612,6 @@ split_point_start: // At split points actual search starts from here if (PvNode && bestValue > alpha) alpha = bestValue; - // If we are near beta then try to get a cutoff pushing checks a bit further - deepChecks = (depth == -ONE_PLY && bestValue >= beta - PawnValueMidgame / 8); - // Futility pruning parameters, not needed when in check futilityBase = ss->eval + evalMargin + FutilityMarginQS; enoughMaterial = pos.non_pawn_material(pos.side_to_move()) > RookValueMidgame; @@ -1534,7 +1621,7 @@ 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 == 0 or depth == -ONE_PLY // and we are near beta) will be generated. - MovePicker mp = MovePicker(pos, ttMove, deepChecks ? DEPTH_ZERO : depth, H); + MovePicker mp = MovePicker(pos, ttMove, d, H); CheckInfo ci(pos); // Loop through the moves until no moves remain or a beta cutoff occurs @@ -1580,6 +1667,16 @@ split_point_start: // At split points actual search starts from here && pos.see_sign(move) < 0) continue; + // Don't search useless checks + if ( !PvNode + && !isCheck + && move != ttMove + && !move_is_promotion(move) + && !pos.move_is_capture(move) + && moveIsCheck + && check_is_useless(pos, move, ss->eval, futilityBase, beta, &bestValue)) + continue; + // Update current move ss->currentMove = move; @@ -1608,7 +1705,6 @@ split_point_start: // At split points actual search starts from here return value_mated_in(ply); // Update transposition table - Depth d = (depth == DEPTH_ZERO ? DEPTH_ZERO : DEPTH_ZERO - ONE_PLY); ValueType vt = (bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT); TT.store(pos.get_key(), value_to_tt(bestValue, ply), vt, d, ss->bestMove, ss->eval, evalMargin); -- 2.39.2