1
0
Fork 0

Cleanup movepicker.

pull/3604/head
Tomasz Sobczyk 2021-07-06 13:02:44 +02:00
parent 8fc297c506
commit f5a98be462
4 changed files with 427 additions and 178 deletions

112
src/history.h 100644
View File

@ -0,0 +1,112 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Stockfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HISTORY_H_INCLUDED
#define HISTORY_H_INCLUDED
#include <array>
#include <limits>
#include <type_traits>
#include "types.h"
namespace Stockfish {
/// StatsEntry stores the stat table value. It is usually a number but could
/// be a move or even a nested history. We use a class instead of naked value
/// to directly call history update operator<<() on the entry so to use stats
/// tables at caller sites as simple multi-dim arrays.
template<typename T, int D>
class StatsEntry {
T entry;
public:
void operator=(const T& v) { entry = v; }
T* operator&() { return &entry; }
T* operator->() { return &entry; }
operator const T&() const { return entry; }
void operator<<(int bonus) {
assert(abs(bonus) <= D); // Ensure range is [-D, D]
static_assert(D <= std::numeric_limits<T>::max(), "D overflows T");
entry += bonus - entry * abs(bonus) / D;
assert(abs(entry) <= D);
}
};
/// Stats is a generic N-dimensional array used to store various statistics.
/// The first template parameter T is the base type of the array, the second
/// template parameter D limits the range of updates in [-D, D] when we update
/// values with the << operator, while the last parameters (Size and Sizes)
/// encode the dimensions of the array.
template <typename T, int D, int Size, int... Sizes>
struct Stats : public std::array<Stats<T, D, Sizes...>, Size>
{
using Self = Stats<T, D, Size, Sizes...>;
void fill(const T& v) {
// For standard-layout 'this' points to first struct member
assert(std::is_standard_layout<Self>::value);
typedef StatsEntry<T, D> entry;
entry* p = reinterpret_cast<entry*>(this);
std::fill(p, p + sizeof(*this) / sizeof(entry), v);
}
};
template <typename T, int D, int Size>
struct Stats<T, D, Size> : public std::array<StatsEntry<T, D>, Size> {};
/// In stats table, D=0 means that the template parameter is not used
enum StatsParams { NOT_USED = 0 };
enum StatsType { NoCaptures, Captures };
/// ButterflyHistory records how often quiet moves have been successful or
/// unsuccessful during the current search, and is used for reduction and move
/// ordering decisions. It uses 2 tables (one for each color) indexed by
/// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards
using ButterflyHistory = Stats< int16_t, 13365, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)>;
/// At higher depths LowPlyHistory records successful quiet moves near the root
/// and quiet moves which are/were in the PV (ttPv). It is cleared with each new
/// search and filled during iterative deepening.
constexpr int MAX_LPH = 4;
using LowPlyHistory = Stats< int16_t, 10692, MAX_LPH, int(SQUARE_NB) * int(SQUARE_NB)>;
/// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous
/// move, see www.chessprogramming.org/Countermove_Heuristic
using CounterMoveHistory = Stats< Move, NOT_USED, PIECE_NB, SQUARE_NB>;
/// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
using CapturePieceToHistory = Stats< int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB>;
/// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
using PieceToHistory = Stats< int16_t, 29952, PIECE_NB, SQUARE_NB>;
/// ContinuationHistory is the combined history of a given pair of moves, usually
/// the current one given a previous one. The nested history table is based on
/// PieceToHistory instead of ButterflyBoards.
using ContinuationHistory = Stats<PieceToHistory, NOT_USED, PIECE_NB, SQUARE_NB>;
}
#endif // #ifndef HISTORY_H_INCLUDED

View File

@ -24,13 +24,6 @@ namespace Stockfish {
namespace {
enum Stages {
MAIN_TT, CAPTURE_INIT, GOOD_CAPTURE, REFUTATION, QUIET_INIT, QUIET, BAD_CAPTURE,
EVASION_TT, EVASION_INIT, EVASION,
PROBCUT_TT, PROBCUT_INIT, PROBCUT,
QSEARCH_TT, QCAPTURE_INIT, QCAPTURE, QCHECK_INIT, QCHECK
};
// partial_insertion_sort() sorts moves in descending order up to and including
// a given limit. The order of moves smaller than the limit is left unspecified.
void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) {
@ -55,74 +48,110 @@ namespace {
/// search captures, promotions, and some checks) and how important good move
/// ordering is at the current node.
MovePicker::MovePicker(const Position& p, Move ttm) :
pos(p),
ttMove(ttm) {
}
/// MovePicker constructor for the main search
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const LowPlyHistory* lp,
const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, const Move* killers, int pl)
: pos(p), mainHistory(mh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch),
ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) {
MovePicker_Main::MovePicker_Main(const Position& p,
Move ttm,
Depth d,
const ButterflyHistory* mh,
const LowPlyHistory* lp,
const CapturePieceToHistory* cph,
const PieceToHistory** ch,
Move cm,
const Move* killers,
int pl) :
MovePicker(p, ttm),
mainHistory(mh),
lowPlyHistory(lp),
captureHistory(cph),
continuationHistory(ch),
refutations{ { killers[0], 0 }, { killers[1], 0 }, { cm, 0 } },
depth(d),
ply(pl) {
assert(d > 0);
stage = (pos.checkers() ? EVASION_TT : MAIN_TT) +
!(ttm && pos.pseudo_legal(ttm));
const bool evasion = pos.checkers();
const bool tt = ttm && pos.pseudo_legal(ttm);
stage = get_start_stage(evasion, tt);
}
MovePicker_Main::Stages MovePicker_Main::get_start_stage(bool evasion, bool tt) {
static constexpr Stages startStages[2][2] = {
{ CAPTURE_INIT, MAIN_TT },
{ EVASION_INIT, EVASION_TT }
};
return startStages[evasion][tt];
}
/// MovePicker constructor for quiescence search
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
const CapturePieceToHistory* cph, const PieceToHistory** ch, Square rs)
: pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d) {
MovePicker_Quiescence::MovePicker_Quiescence(const Position& p,
Move ttm,
Depth d,
const ButterflyHistory* mh,
const CapturePieceToHistory* cph,
const PieceToHistory** ch,
Square rs) :
MovePicker(p, ttm),
mainHistory(mh),
captureHistory(cph),
continuationHistory(ch),
recaptureSquare(rs),
depth(d) {
assert(d <= 0);
stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) +
!( ttm
&& (pos.checkers() || depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare)
&& pos.pseudo_legal(ttm));
const bool evasion = pos.checkers();
const bool tt = ttm
&& ( pos.checkers()
|| depth > DEPTH_QS_RECAPTURES
|| to_sq(ttm) == recaptureSquare)
&& pos.pseudo_legal(ttm);
stage = get_start_stage(evasion, tt);
}
MovePicker_Quiescence::Stages MovePicker_Quiescence::get_start_stage(bool evasion, bool tt) {
static constexpr Stages startStages[2][2] = {
{ QCAPTURE_INIT, QSEARCH_TT },
{ EVASION_INIT, EVASION_TT }
};
return startStages[evasion][tt];
}
/// MovePicker constructor for ProbCut: we generate captures with SEE greater
/// than or equal to the given threshold.
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph)
: pos(p), captureHistory(cph), ttMove(ttm), threshold(th) {
MovePicker_ProbCut::MovePicker_ProbCut(const Position& p,
Move ttm,
Value th,
const CapturePieceToHistory* cph) :
MovePicker(p, ttm),
captureHistory(cph),
threshold(th) {
assert(!pos.checkers());
stage = PROBCUT_TT + !(ttm && pos.capture(ttm)
&& pos.pseudo_legal(ttm)
&& pos.see_ge(ttm, threshold));
const bool tt = ttm
&& pos.capture(ttm)
&& pos.pseudo_legal(ttm)
&& pos.see_ge(ttm, threshold);
stage = get_start_stage(tt);
}
/// MovePicker::score() assigns a numerical value to each move in a list, used
/// for sorting. Captures are ordered by Most Valuable Victim (MVV), preferring
/// captures with a good history. Quiets moves are ordered using the histories.
template<GenType Type>
void MovePicker::score() {
MovePicker_ProbCut::Stages MovePicker_ProbCut::get_start_stage(bool tt) {
static constexpr Stages startStages[2] = {
PROBCUT_INIT, PROBCUT_TT
};
static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type");
for (auto& m : *this)
if constexpr (Type == CAPTURES)
m.value = int(PieceValue[MG][pos.piece_on(to_sq(m))]) * 6
+ (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))];
else if constexpr (Type == QUIETS)
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
+ 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)]
+ (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)]
+ (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)]
+ (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)]
+ (ply < MAX_LPH ? std::min(4, depth / 3) * (*lowPlyHistory)[ply][from_to(m)] : 0);
else // Type == EVASIONS
{
if (pos.capture(m))
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m)));
else
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
+ 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)]
- (1 << 28);
}
return startStages[tt];
}
/// MovePicker::select() returns the next move satisfying a predicate function.
@ -143,30 +172,25 @@ Move MovePicker::select(Pred filter) {
return MOVE_NONE;
}
/// MovePicker::next_move() is the most important method of the MovePicker class. It
/// MovePicker_*::next_move() is the most important method of the MovePicker_* classes. It
/// returns a new pseudo-legal move every time it is called until there are no more
/// moves left, picking the move with the highest score from a list of generated moves.
Move MovePicker::next_move(bool skipQuiets) {
top:
Move MovePicker_Main::next_move(bool skipQuiets) {
switch (stage) {
case MAIN_TT:
case EVASION_TT:
case QSEARCH_TT:
case PROBCUT_TT:
++stage;
return ttMove;
case CAPTURE_INIT:
case PROBCUT_INIT:
case QCAPTURE_INIT:
cur = endBadCaptures = moves;
endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>();
score_captures();
++stage;
goto top;
[[fallthrough]];
case GOOD_CAPTURE:
if (select<Best>([&](){
@ -201,7 +225,7 @@ top:
cur = endBadCaptures;
endMoves = generate<QUIETS>(pos, cur);
score<QUIETS>();
score_quiets();
partial_insertion_sort(cur, endMoves, -3000 * depth);
}
@ -225,19 +249,43 @@ top:
case BAD_CAPTURE:
return select<Next>([](){ return true; });
case EVASION_TT:
++stage;
return ttMove;
case EVASION_INIT:
cur = moves;
endMoves = generate<EVASIONS>(pos, cur);
score<EVASIONS>();
score_evasions();
++stage;
[[fallthrough]];
case EVASION:
return select<Best>([](){ return true; });
}
case PROBCUT:
return select<Best>([&](){ return pos.see_ge(*cur, threshold); });
assert(false);
return MOVE_NONE; // Silence warning
}
Move MovePicker_Quiescence::next_move() {
switch (stage) {
case QSEARCH_TT:
++stage;
return ttMove;
case QCAPTURE_INIT:
cur = endBadCaptures = moves;
endMoves = generate<CAPTURES>(pos, cur);
score_captures();
++stage;
[[fallthrough]];
case QCAPTURE:
if (select<Best>([&](){ return depth > DEPTH_QS_RECAPTURES
@ -260,6 +308,47 @@ top:
case QCHECK:
return select<Next>([](){ return true; });
case EVASION_TT:
++stage;
return ttMove;
case EVASION_INIT:
cur = moves;
endMoves = generate<EVASIONS>(pos, cur);
score_evasions();
++stage;
[[fallthrough]];
case EVASION:
return select<Best>([](){ return true; });
}
assert(false);
return MOVE_NONE; // Silence warning
}
Move MovePicker_ProbCut::next_move() {
switch (stage) {
case PROBCUT_TT:
++stage;
return ttMove;
case PROBCUT_INIT:
cur = endBadCaptures = moves;
endMoves = generate<CAPTURES>(pos, cur);
score_captures();
++stage;
[[fallthrough]];
case PROBCUT:
return select<Best>([&](){ return pos.see_ge(*cur, threshold); });
}
assert(false);

View File

@ -23,139 +23,181 @@
#include <limits>
#include <type_traits>
#include "history.h"
#include "movegen.h"
#include "position.h"
#include "types.h"
namespace Stockfish {
/// StatsEntry stores the stat table value. It is usually a number but could
/// be a move or even a nested history. We use a class instead of naked value
/// to directly call history update operator<<() on the entry so to use stats
/// tables at caller sites as simple multi-dim arrays.
template<typename T, int D>
class StatsEntry {
/// MovePicker::score_*() assigns a numerical value to each move in a list, used
/// for sorting. Captures are ordered by Most Valuable Victim (MVV), preferring
/// captures with a good history. Quiets moves are ordered using the histories.
T entry;
template <typename T>
inline void score_captures_base(T& self) {
for (auto& m : self)
m.value = int(PieceValue[MG][self.pos.piece_on(to_sq(m))]) * 6
+ (*self.captureHistory)[self.pos.moved_piece(m)][to_sq(m)][type_of(self.pos.piece_on(to_sq(m)))];
}
public:
void operator=(const T& v) { entry = v; }
T* operator&() { return &entry; }
T* operator->() { return &entry; }
operator const T&() const { return entry; }
template <typename T>
inline void score_evasions_base(T& self) {
for (auto& m : self)
if (self.pos.capture(m))
m.value = PieceValue[MG][self.pos.piece_on(to_sq(m))]
- Value(type_of(self.pos.moved_piece(m)));
else
m.value = (*self.mainHistory)[self.pos.side_to_move()][from_to(m)]
+ 2 * (*self.continuationHistory[0])[self.pos.moved_piece(m)][to_sq(m)]
- (1 << 28);
}
void operator<<(int bonus) {
assert(abs(bonus) <= D); // Ensure range is [-D, D]
static_assert(D <= std::numeric_limits<T>::max(), "D overflows T");
entry += bonus - entry * abs(bonus) / D;
assert(abs(entry) <= D);
}
};
/// Stats is a generic N-dimensional array used to store various statistics.
/// The first template parameter T is the base type of the array, the second
/// template parameter D limits the range of updates in [-D, D] when we update
/// values with the << operator, while the last parameters (Size and Sizes)
/// encode the dimensions of the array.
template <typename T, int D, int Size, int... Sizes>
struct Stats : public std::array<Stats<T, D, Sizes...>, Size>
{
typedef Stats<T, D, Size, Sizes...> stats;
void fill(const T& v) {
// For standard-layout 'this' points to first struct member
assert(std::is_standard_layout<stats>::value);
typedef StatsEntry<T, D> entry;
entry* p = reinterpret_cast<entry*>(this);
std::fill(p, p + sizeof(*this) / sizeof(entry), v);
}
};
template <typename T, int D, int Size>
struct Stats<T, D, Size> : public std::array<StatsEntry<T, D>, Size> {};
/// In stats table, D=0 means that the template parameter is not used
enum StatsParams { NOT_USED = 0 };
enum StatsType { NoCaptures, Captures };
/// ButterflyHistory records how often quiet moves have been successful or
/// unsuccessful during the current search, and is used for reduction and move
/// ordering decisions. It uses 2 tables (one for each color) indexed by
/// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards
typedef Stats<int16_t, 13365, COLOR_NB, int(SQUARE_NB) * int(SQUARE_NB)> ButterflyHistory;
/// At higher depths LowPlyHistory records successful quiet moves near the root
/// and quiet moves which are/were in the PV (ttPv). It is cleared with each new
/// search and filled during iterative deepening.
constexpr int MAX_LPH = 4;
typedef Stats<int16_t, 10692, MAX_LPH, int(SQUARE_NB) * int(SQUARE_NB)> LowPlyHistory;
/// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous
/// move, see www.chessprogramming.org/Countermove_Heuristic
typedef Stats<Move, NOT_USED, PIECE_NB, SQUARE_NB> CounterMoveHistory;
/// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
typedef Stats<int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB> CapturePieceToHistory;
/// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
typedef Stats<int16_t, 29952, PIECE_NB, SQUARE_NB> PieceToHistory;
/// ContinuationHistory is the combined history of a given pair of moves, usually
/// the current one given a previous one. The nested history table is based on
/// PieceToHistory instead of ButterflyBoards.
typedef Stats<PieceToHistory, NOT_USED, PIECE_NB, SQUARE_NB> ContinuationHistory;
template <typename T>
inline void score_quiets_base(T& self) {
for (auto& m : self)
m.value = (*self.mainHistory)[self.pos.side_to_move()][from_to(m)]
+ 2 * (*self.continuationHistory[0])[self.pos.moved_piece(m)][to_sq(m)]
+ (*self.continuationHistory[1])[self.pos.moved_piece(m)][to_sq(m)]
+ (*self.continuationHistory[3])[self.pos.moved_piece(m)][to_sq(m)]
+ (*self.continuationHistory[5])[self.pos.moved_piece(m)][to_sq(m)]
+ (self.ply < MAX_LPH ? std::min(4, self.depth / 3) * (*self.lowPlyHistory)[self.ply][from_to(m)] : 0);
}
/// MovePicker class is used to pick one pseudo-legal move at a time from the
/// MovePicker* classes are used to pick one pseudo-legal move at a time from the
/// current position. The most important method is next_move(), which returns a
/// new pseudo-legal move each time it is called, until there are no moves left,
/// when MOVE_NONE is returned. In order to improve the efficiency of the
/// alpha-beta algorithm, MovePicker attempts to return the moves which are most
/// alpha-beta algorithm, Move pickers attempts to return the moves which are most
/// likely to get a cut-off first.
/// Different move pickers are needed in different places in search, sometimes
/// excluding certain moves, or rating them differently. Each MovePicker*
/// class represents one such use case.
class MovePicker {
protected:
enum PickType { Next, Best };
public:
MovePicker(const MovePicker&) = delete;
MovePicker(MovePicker&&) = delete;
MovePicker& operator=(const MovePicker&) = delete;
MovePicker(const Position&, Move, Value, const CapturePieceToHistory*);
MovePicker(const Position&, Move, Depth, const ButterflyHistory*,
const CapturePieceToHistory*,
const PieceToHistory**,
Square);
MovePicker(const Position&, Move, Depth, const ButterflyHistory*,
const LowPlyHistory*,
const CapturePieceToHistory*,
const PieceToHistory**,
Move,
const Move*,
int);
Move next_move(bool skipQuiets = false);
MovePicker& operator=(MovePicker&&) = delete;
MovePicker(const Position&, Move);
private:
template<PickType T, typename Pred> Move select(Pred);
template<GenType> void score();
ExtMove* begin() { return cur; }
ExtMove* end() { return endMoves; }
const Position& pos;
Move ttMove;
ExtMove moves[MAX_MOVES];
ExtMove* cur;
ExtMove* endMoves;
};
class MovePicker_Main : public MovePicker {
private:
enum Stages {
MAIN_TT, CAPTURE_INIT, GOOD_CAPTURE, REFUTATION, QUIET_INIT, QUIET, BAD_CAPTURE,
EVASION_TT, EVASION_INIT, EVASION
};
public:
MovePicker_Main(const Position&,
Move,
Depth,
const ButterflyHistory*,
const LowPlyHistory*,
const CapturePieceToHistory*,
const PieceToHistory**,
Move,
const Move*,
int);
Move next_move(bool skipQuiets = false);
private:
const ButterflyHistory* mainHistory;
const LowPlyHistory* lowPlyHistory;
const CapturePieceToHistory* captureHistory;
const PieceToHistory** continuationHistory;
Move ttMove;
ExtMove refutations[3], *cur, *endMoves, *endBadCaptures;
ExtMove refutations[3];
ExtMove* endBadCaptures;
int stage;
Square recaptureSquare;
Value threshold;
Depth depth;
int ply;
ExtMove moves[MAX_MOVES];
Stages get_start_stage(bool evastion, bool tt);
auto score_captures() { return score_captures_base(*this); }
auto score_evasions() { return score_evasions_base(*this); }
auto score_quiets() { return score_quiets_base(*this); }
template <typename T> friend void score_captures_base(T&);
template <typename T> friend void score_evasions_base(T&);
template <typename T> friend void score_quiets_base (T&);
};
class MovePicker_Quiescence : public MovePicker {
private:
enum Stages {
QSEARCH_TT, QCAPTURE_INIT, QCAPTURE, QCHECK_INIT, QCHECK,
EVASION_TT, EVASION_INIT, EVASION
};
public:
MovePicker_Quiescence(const Position&,
Move,
Depth,
const ButterflyHistory*,
const CapturePieceToHistory*,
const PieceToHistory**,
Square);
Move next_move();
private:
const ButterflyHistory* mainHistory;
const CapturePieceToHistory* captureHistory;
const PieceToHistory** continuationHistory;
ExtMove* endBadCaptures;
int stage;
Square recaptureSquare;
Depth depth;
Stages get_start_stage(bool evastion, bool tt);
auto score_captures() { return score_captures_base(*this); }
auto score_evasions() { return score_evasions_base(*this); }
template <typename T> friend void score_captures_base(T&);
template <typename T> friend void score_evasions_base(T&);
};
class MovePicker_ProbCut : public MovePicker {
private:
enum Stages {
PROBCUT_TT, PROBCUT_INIT, PROBCUT
};
public:
MovePicker_ProbCut(const Position&, Move, Value, const CapturePieceToHistory*);
Move next_move();
private:
const CapturePieceToHistory* captureHistory;
ExtMove* endBadCaptures;
int stage;
Value threshold;
Stages get_start_stage(bool tt);
auto score_captures() { return score_captures_base(*this); }
template <typename T> friend void score_captures_base(T&);
};
} // namespace Stockfish

View File

@ -854,7 +854,7 @@ namespace {
{
assert(probCutBeta < VALUE_INFINITE);
MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, &captureHistory);
MovePicker_ProbCut mp(pos, ttMove, probCutBeta - ss->staticEval, &captureHistory);
int probCutCount = 0;
bool ttPv = ss->ttPv;
ss->ttPv = false;
@ -932,13 +932,16 @@ moves_loop: // When in check, search starts from here
Move countermove = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq];
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory,
&thisThread->lowPlyHistory,
&captureHistory,
contHist,
countermove,
ss->killers,
ss->ply);
MovePicker_Main mp(pos,
ttMove,
depth,
&thisThread->mainHistory,
&thisThread->lowPlyHistory,
&captureHistory,
contHist,
countermove,
ss->killers,
ss->ply);
value = bestValue;
singularQuietLMR = moveCountPruning = false;
@ -1463,10 +1466,13 @@ moves_loop: // When in check, search starts from here
// to search the moves. Because the depth is <= 0 here, only captures,
// queen promotions, and other checks (only if depth >= DEPTH_QS_CHECKS)
// will be generated.
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory,
&thisThread->captureHistory,
contHist,
to_sq((ss-1)->currentMove));
MovePicker_Quiescence mp(pos,
ttMove,
depth,
&thisThread->mainHistory,
&thisThread->captureHistory,
contHist,
to_sq((ss-1)->currentMove));
// Loop through the moves until no moves remain or a beta cutoff occurs
while ((move = mp.next_move()) != MOVE_NONE)