diff --git a/src/movepick.cpp b/src/movepick.cpp index bdc0e4affdb..96315a190f7 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -110,7 +110,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, int th, const CapturePieceTo assert(!pos.checkers()); stage = PROBCUT_TT - + !(ttm && pos.capture_stage(ttm) && pos.pseudo_legal(ttm) && pos.see_ge(ttm, threshold)); + + !(ttm && pos.capture_stage(ttm) && pos.pseudo_legal(ttm) && pos.see(ttm) >= threshold); } // Assigns a numerical value to each move in a list, used for sorting. @@ -238,7 +238,7 @@ Move MovePicker::next_move(bool skipQuiets) { case GOOD_CAPTURE : if (select([&]() { // Move losing capture to endBadCaptures to be tried later - return pos.see_ge(*cur, -cur->value / 18) ? true + return pos.see(*cur) >= (-cur->value / 18) ? true : (*endBadCaptures++ = *cur, false); })) return *(cur - 1); @@ -305,7 +305,7 @@ Move MovePicker::next_move(bool skipQuiets) { return select([]() { return true; }); case PROBCUT : - return select([&]() { return pos.see_ge(*cur, threshold); }); + return select([&]() { return pos.see(*cur) >= threshold; }); case QCAPTURE : return select([]() { return true; }); diff --git a/src/position.cpp b/src/position.cpp index d374b1c070a..b28d582d7e4 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1022,9 +1022,9 @@ Key Position::key_after(Move m) const { } -// Tests if the SEE (Static Exchange Evaluation) -// value of move is greater or equal to the given threshold. We'll use an -// algorithm similar to alpha-beta pruning with a null window. +// Tests if the SEE (Static Exchange Evaluation) value of a move is +// greater or equal to the given threshold. We will use an algorithm +// similar to alpha-beta pruning with a null window. bool Position::see_ge(Move m, int threshold) const { assert(m.is_ok()); diff --git a/src/position.h b/src/position.h index 064dd5fa918..d7da6f8770a 100644 --- a/src/position.h +++ b/src/position.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "bitboard.h" #include "nnue/nnue_accumulator.h" @@ -32,6 +33,7 @@ namespace Stockfish { +class Position; class TranspositionTable; // StateInfo struct stores information needed to restore a Position object to @@ -73,6 +75,12 @@ struct StateInfo { using StateListPtr = std::unique_ptr>; +/// A temporary type to get a nice syntax for SEE comparisons. Never use this type +/// directly or assign a value to a variable of this type, instead use the syntax +/// "if (pos.see(move) >= threshold) ..." and similar for other comparisons. +typedef std::pair SEE; + + // Position class stores information regarding the board representation as // pieces, side to move, hash keys, castling info, etc. Important methods are // do_move() and undo_move(), used by the search to update node info when @@ -144,6 +152,7 @@ class Position { // Static Exchange Evaluation bool see_ge(Move m, int threshold = 0) const; + inline const SEE see(Move m) const { return SEE(*this, m); } // Accessing hash keys Key key() const; @@ -359,6 +368,14 @@ inline void Position::do_move(Move m, StateInfo& newSt) { do_move(m, newSt, give inline StateInfo* Position::state() const { return st; } +// Syntactic sugar around Position::see_ge(), so that we can use the more readable +// pos.see(move) >= threshold instead of pos.see_ge(move, threshold), and similar +// readable code for the three other comparison operators. +inline bool operator>=(const SEE& s, Value threshold) { return s.first.see_ge(s.second, threshold);} +inline bool operator> (const SEE& s, Value threshold) { return (s >= threshold + 1); } +inline bool operator< (const SEE& s, Value threshold) { return !(s >= threshold); } +inline bool operator<=(const SEE& s, Value threshold) { return !(s >= threshold + 1); } + } // namespace Stockfish #endif // #ifndef POSITION_H_INCLUDED diff --git a/src/search.cpp b/src/search.cpp index 5f87f28fded..dd27bbab744 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -986,7 +986,7 @@ Value Search::Worker::search( // SEE based pruning for captures and checks (~11 Elo) int seeHist = std::clamp(captHist / 32, -182 * depth, 166 * depth); - if (!pos.see_ge(move, -168 * depth - seeHist)) + if (pos.see(move) < -168 * depth - seeHist) continue; } else @@ -1019,7 +1019,7 @@ Value Search::Worker::search( lmrDepth = std::max(lmrDepth, 0); // Prune moves with negative SEE (~4 Elo) - if (!pos.see_ge(move, -24 * lmrDepth * lmrDepth)) + if (pos.see(move) < -24 * lmrDepth * lmrDepth) continue; } } @@ -1566,7 +1566,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) // If static eval is much lower than alpha and move is // not winning material, we can prune this move. (~2 Elo) - if (futilityBase <= alpha && !pos.see_ge(move, 1)) + if (futilityBase <= alpha && pos.see(move) <= 0) { bestValue = std::max(bestValue, futilityBase); continue; @@ -1574,7 +1574,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) // If static exchange evaluation is much worse than what // is needed to not fall below alpha, we can prune this move. - if (futilityBase > alpha && !pos.see_ge(move, (alpha - futilityBase) * 4)) + if (futilityBase > alpha && pos.see(move) < (alpha - futilityBase) * 4) { bestValue = alpha; continue; @@ -1591,7 +1591,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) continue; // Do not search moves with bad enough SEE values (~5 Elo) - if (!pos.see_ge(move, -83)) + if (pos.see(move) < -83) continue; }