mirror of
https://github.com/sockspls/badfish
synced 2025-05-02 09:39:36 +00:00
Clean killers handling in movepicker
Original patch from Joona with added optimizations by me. Great cleanup of MovePicker with speed improvment of 1% No functional change. Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
parent
e217407450
commit
595a90dfd0
3 changed files with 71 additions and 117 deletions
|
@ -47,7 +47,6 @@ Application::Application() {
|
||||||
init_uci_options();
|
init_uci_options();
|
||||||
Position::init_zobrist();
|
Position::init_zobrist();
|
||||||
Position::init_piece_square_tables();
|
Position::init_piece_square_tables();
|
||||||
MovePicker::init_phase_table();
|
|
||||||
init_eval(1);
|
init_eval(1);
|
||||||
init_bitbases();
|
init_bitbases();
|
||||||
init_threads();
|
init_threads();
|
||||||
|
|
144
src/movepick.cpp
144
src/movepick.cpp
|
@ -43,11 +43,10 @@ namespace {
|
||||||
/// Variables
|
/// Variables
|
||||||
|
|
||||||
CACHE_LINE_ALIGNMENT
|
CACHE_LINE_ALIGNMENT
|
||||||
int MainSearchPhaseIndex;
|
const MovegenPhaseT MainSearchPhaseTable[] = { PH_STOP, PH_TT_MOVES, PH_GOOD_CAPTURES, PH_KILLERS, PH_NONCAPTURES, PH_BAD_CAPTURES, PH_STOP};
|
||||||
int EvasionsPhaseIndex;
|
const MovegenPhaseT EvasionsPhaseTable[] = { PH_STOP, PH_EVASIONS, PH_STOP};
|
||||||
int QsearchWithChecksPhaseIndex;
|
const MovegenPhaseT QsearchWithChecksPhaseTable[] = { PH_STOP, PH_TT_MOVES, PH_QCAPTURES, PH_QCHECKS, PH_STOP};
|
||||||
int QsearchWithoutChecksPhaseIndex;
|
const MovegenPhaseT QsearchWithoutChecksPhaseTable[] = { PH_STOP, PH_TT_MOVES, PH_QCAPTURES, PH_STOP};
|
||||||
uint8_t PhaseTable[32];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,33 +64,31 @@ namespace {
|
||||||
|
|
||||||
MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
|
MovePicker::MovePicker(const Position& p, Move ttm, Depth d,
|
||||||
const History& h, SearchStack* ss) : pos(p), H(h) {
|
const History& h, SearchStack* ss) : pos(p), H(h) {
|
||||||
ttMove = ttm;
|
ttMoves[0] = ttm;
|
||||||
if (ss)
|
if (ss)
|
||||||
{
|
{
|
||||||
mateKiller = (ss->mateKiller == ttm)? MOVE_NONE : ss->mateKiller;
|
ttMoves[1] = (ss->mateKiller == ttm)? MOVE_NONE : ss->mateKiller;
|
||||||
killer1 = ss->killers[0];
|
killers[0] = ss->killers[0];
|
||||||
killer2 = ss->killers[1];
|
killers[1] = ss->killers[1];
|
||||||
} else
|
} else
|
||||||
mateKiller = killer1 = killer2 = MOVE_NONE;
|
ttMoves[1] = killers[0] = killers[1] = MOVE_NONE;
|
||||||
|
|
||||||
movesPicked = numOfMoves = numOfBadCaptures = 0;
|
movesPicked = numOfMoves = numOfBadCaptures = 0;
|
||||||
checkKillers = checkLegal = finished = false;
|
finished = false;
|
||||||
|
|
||||||
if (p.is_check())
|
if (p.is_check())
|
||||||
phaseIndex = EvasionsPhaseIndex;
|
phasePtr = EvasionsPhaseTable;
|
||||||
else if (d > Depth(0))
|
else if (d > Depth(0))
|
||||||
phaseIndex = MainSearchPhaseIndex;
|
phasePtr = MainSearchPhaseTable;
|
||||||
else if (d == Depth(0))
|
else if (d == Depth(0))
|
||||||
phaseIndex = QsearchWithChecksPhaseIndex;
|
phasePtr = QsearchWithChecksPhaseTable;
|
||||||
else
|
else
|
||||||
phaseIndex = QsearchWithoutChecksPhaseIndex;
|
phasePtr = QsearchWithoutChecksPhaseTable;
|
||||||
|
|
||||||
Color us = pos.side_to_move();
|
Color us = pos.side_to_move();
|
||||||
|
|
||||||
dc = p.discovered_check_candidates(us);
|
dc = p.discovered_check_candidates(us);
|
||||||
pinned = p.pinned_pieces(us);
|
pinned = p.pinned_pieces(us);
|
||||||
|
|
||||||
finished = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,25 +112,11 @@ Move MovePicker::get_next_move() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next phase
|
// Next phase
|
||||||
phaseIndex++;
|
phasePtr++;
|
||||||
switch (PhaseTable[phaseIndex]) {
|
switch (*phasePtr) {
|
||||||
|
|
||||||
case PH_TT_MOVE:
|
case PH_TT_MOVES:
|
||||||
if (ttMove != MOVE_NONE)
|
movesPicked = 0; // This is used as index to ttMoves[]
|
||||||
{
|
|
||||||
assert(move_is_ok(ttMove));
|
|
||||||
if (move_is_legal(pos, ttMove, pinned))
|
|
||||||
return ttMove;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PH_MATE_KILLER:
|
|
||||||
if (mateKiller != MOVE_NONE)
|
|
||||||
{
|
|
||||||
assert(move_is_ok(mateKiller));
|
|
||||||
if (move_is_legal(pos, mateKiller, pinned))
|
|
||||||
return mateKiller;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PH_GOOD_CAPTURES:
|
case PH_GOOD_CAPTURES:
|
||||||
|
@ -144,16 +127,10 @@ Move MovePicker::get_next_move() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PH_KILLERS:
|
case PH_KILLERS:
|
||||||
movesPicked = numOfMoves = 0;
|
movesPicked = 0; // This is used as index to killers[]
|
||||||
if (killer1 != MOVE_NONE && move_is_legal(pos, killer1, pinned) && !pos.move_is_capture(killer1))
|
|
||||||
moves[numOfMoves++].move = killer1;
|
|
||||||
if (killer2 != MOVE_NONE && move_is_legal(pos, killer2, pinned) && !pos.move_is_capture(killer2))
|
|
||||||
moves[numOfMoves++].move = killer2;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PH_NONCAPTURES:
|
case PH_NONCAPTURES:
|
||||||
checkKillers = (numOfMoves != 0); // previous phase is PH_KILLERS
|
|
||||||
checkLegal = true;
|
|
||||||
numOfMoves = generate_noncaptures(pos, moves);
|
numOfMoves = generate_noncaptures(pos, moves);
|
||||||
score_noncaptures();
|
score_noncaptures();
|
||||||
std::sort(moves, moves + numOfMoves);
|
std::sort(moves, moves + numOfMoves);
|
||||||
|
@ -281,7 +258,7 @@ void MovePicker::score_evasions() {
|
||||||
for (int i = 0; i < numOfMoves; i++)
|
for (int i = 0; i < numOfMoves; i++)
|
||||||
{
|
{
|
||||||
Move m = moves[i].move;
|
Move m = moves[i].move;
|
||||||
if (m == ttMove)
|
if (m == ttMoves[0])
|
||||||
moves[i].score = 2*HistoryMax;
|
moves[i].score = 2*HistoryMax;
|
||||||
else if (!pos.square_is_empty(move_to(m)))
|
else if (!pos.square_is_empty(move_to(m)))
|
||||||
{
|
{
|
||||||
|
@ -301,17 +278,26 @@ void MovePicker::score_evasions() {
|
||||||
Move MovePicker::pick_move_from_list() {
|
Move MovePicker::pick_move_from_list() {
|
||||||
|
|
||||||
assert(movesPicked >= 0);
|
assert(movesPicked >= 0);
|
||||||
assert(!pos.is_check() || PhaseTable[phaseIndex] == PH_EVASIONS || PhaseTable[phaseIndex] == PH_STOP);
|
assert(!pos.is_check() || *phasePtr == PH_EVASIONS || *phasePtr == PH_STOP);
|
||||||
assert( pos.is_check() || PhaseTable[phaseIndex] != PH_EVASIONS);
|
assert( pos.is_check() || *phasePtr != PH_EVASIONS);
|
||||||
|
|
||||||
switch (PhaseTable[phaseIndex]) {
|
switch (*phasePtr) {
|
||||||
|
|
||||||
|
case PH_TT_MOVES:
|
||||||
|
while (movesPicked < 2) {
|
||||||
|
Move move = ttMoves[movesPicked++];
|
||||||
|
if ( move != MOVE_NONE
|
||||||
|
&& move_is_legal(pos, move, pinned))
|
||||||
|
return move;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case PH_GOOD_CAPTURES:
|
case PH_GOOD_CAPTURES:
|
||||||
while (movesPicked < numOfMoves)
|
while (movesPicked < numOfMoves)
|
||||||
{
|
{
|
||||||
Move move = moves[movesPicked++].move;
|
Move move = moves[movesPicked++].move;
|
||||||
if ( move != ttMove
|
if ( move != ttMoves[0]
|
||||||
&& move != mateKiller
|
&& move != ttMoves[1]
|
||||||
&& pos.pl_move_is_legal(move, pinned))
|
&& pos.pl_move_is_legal(move, pinned))
|
||||||
{
|
{
|
||||||
// Check for a non negative SEE now
|
// Check for a non negative SEE now
|
||||||
|
@ -327,15 +313,28 @@ Move MovePicker::pick_move_from_list() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PH_KILLERS:
|
case PH_KILLERS:
|
||||||
|
while (movesPicked < 2) {
|
||||||
|
Move move = killers[movesPicked++];
|
||||||
|
if ( move != MOVE_NONE
|
||||||
|
&& move != ttMoves[0]
|
||||||
|
&& move != ttMoves[1]
|
||||||
|
&& move_is_legal(pos, move, pinned)
|
||||||
|
&& !pos.move_is_capture(move))
|
||||||
|
return move;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case PH_NONCAPTURES:
|
case PH_NONCAPTURES:
|
||||||
while (movesPicked < numOfMoves)
|
while (movesPicked < numOfMoves)
|
||||||
{
|
{
|
||||||
Move move = moves[movesPicked++].move;
|
Move move = moves[movesPicked++].move;
|
||||||
if ( move != ttMove
|
if ( move != ttMoves[0]
|
||||||
&& move != mateKiller
|
&& move != ttMoves[1]
|
||||||
&& (!checkKillers || (move != killer1 && move != killer2))
|
&& move != killers[0]
|
||||||
&& (!checkLegal || pos.pl_move_is_legal(move, pinned)))
|
&& move != killers[1]
|
||||||
|
&& pos.pl_move_is_legal(move, pinned))
|
||||||
return move;
|
return move;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -356,7 +355,7 @@ Move MovePicker::pick_move_from_list() {
|
||||||
{
|
{
|
||||||
Move move = moves[movesPicked++].move;
|
Move move = moves[movesPicked++].move;
|
||||||
// Maybe postpone the legality check until after futility pruning?
|
// Maybe postpone the legality check until after futility pruning?
|
||||||
if ( move != ttMove
|
if ( move != ttMoves[0]
|
||||||
&& pos.pl_move_is_legal(move, pinned))
|
&& pos.pl_move_is_legal(move, pinned))
|
||||||
return move;
|
return move;
|
||||||
}
|
}
|
||||||
|
@ -367,42 +366,3 @@ Move MovePicker::pick_move_from_list() {
|
||||||
}
|
}
|
||||||
return MOVE_NONE;
|
return MOVE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// MovePicker::init_phase_table() initializes the PhaseTable[],
|
|
||||||
/// MainSearchPhaseIndex, EvasionPhaseIndex, QsearchWithChecksPhaseIndex
|
|
||||||
/// and QsearchWithoutChecksPhaseIndex. It is only called once during
|
|
||||||
/// program startup, and never again while the program is running.
|
|
||||||
|
|
||||||
void MovePicker::init_phase_table() {
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
// Main search
|
|
||||||
MainSearchPhaseIndex = i - 1;
|
|
||||||
PhaseTable[i++] = PH_TT_MOVE;
|
|
||||||
PhaseTable[i++] = PH_MATE_KILLER;
|
|
||||||
PhaseTable[i++] = PH_GOOD_CAPTURES;
|
|
||||||
PhaseTable[i++] = PH_KILLERS;
|
|
||||||
PhaseTable[i++] = PH_NONCAPTURES;
|
|
||||||
PhaseTable[i++] = PH_BAD_CAPTURES;
|
|
||||||
PhaseTable[i++] = PH_STOP;
|
|
||||||
|
|
||||||
// Check evasions
|
|
||||||
EvasionsPhaseIndex = i - 1;
|
|
||||||
PhaseTable[i++] = PH_EVASIONS;
|
|
||||||
PhaseTable[i++] = PH_STOP;
|
|
||||||
|
|
||||||
// Quiescence search with checks
|
|
||||||
QsearchWithChecksPhaseIndex = i - 1;
|
|
||||||
PhaseTable[i++] = PH_TT_MOVE;
|
|
||||||
PhaseTable[i++] = PH_QCAPTURES;
|
|
||||||
PhaseTable[i++] = PH_QCHECKS;
|
|
||||||
PhaseTable[i++] = PH_STOP;
|
|
||||||
|
|
||||||
// Quiescence search without checks
|
|
||||||
QsearchWithoutChecksPhaseIndex = i - 1;
|
|
||||||
PhaseTable[i++] = PH_TT_MOVE;
|
|
||||||
PhaseTable[i++] = PH_QCAPTURES;
|
|
||||||
PhaseTable[i++] = PH_STOP;
|
|
||||||
}
|
|
||||||
|
|
|
@ -35,9 +35,22 @@
|
||||||
//// Types
|
//// Types
|
||||||
////
|
////
|
||||||
|
|
||||||
struct EvalInfo;
|
|
||||||
struct SearchStack;
|
struct SearchStack;
|
||||||
|
|
||||||
|
enum MovegenPhase {
|
||||||
|
PH_TT_MOVES, // Transposition table move and mate killer
|
||||||
|
PH_GOOD_CAPTURES, // Queen promotions and captures with SEE values >= 0
|
||||||
|
PH_KILLERS, // Killer moves from the current ply
|
||||||
|
PH_NONCAPTURES, // Non-captures and underpromotions
|
||||||
|
PH_BAD_CAPTURES, // Queen promotions and captures with SEE values < 0
|
||||||
|
PH_EVASIONS, // Check evasions
|
||||||
|
PH_QCAPTURES, // Captures in quiescence search
|
||||||
|
PH_QCHECKS, // Non-capture checks in quiescence search
|
||||||
|
PH_STOP
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef uint8_t MovegenPhaseT;
|
||||||
|
|
||||||
/// MovePicker is a class which is used to pick one legal move at a time from
|
/// MovePicker is a class which is used to pick one legal move at a time from
|
||||||
/// the current position. It is initialized with a Position object and a few
|
/// the current position. It is initialized with a Position object and a few
|
||||||
/// moves we have reason to believe are good. The most important method is
|
/// moves we have reason to believe are good. The most important method is
|
||||||
|
@ -51,28 +64,12 @@ class MovePicker {
|
||||||
MovePicker& operator=(const MovePicker&); // silence a warning under MSVC
|
MovePicker& operator=(const MovePicker&); // silence a warning under MSVC
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum MovegenPhase {
|
|
||||||
PH_TT_MOVE, // Transposition table move
|
|
||||||
PH_MATE_KILLER, // Mate killer from the current ply
|
|
||||||
PH_GOOD_CAPTURES, // Queen promotions and captures with SEE values >= 0
|
|
||||||
PH_KILLERS, // Killer moves from the current ply
|
|
||||||
PH_NONCAPTURES, // Non-captures and underpromotions
|
|
||||||
PH_BAD_CAPTURES, // Queen promotions and captures with SEE values < 0
|
|
||||||
PH_EVASIONS, // Check evasions
|
|
||||||
PH_QCAPTURES, // Captures in quiescence search
|
|
||||||
PH_QCHECKS, // Non-capture checks in quiescence search
|
|
||||||
PH_STOP
|
|
||||||
};
|
|
||||||
|
|
||||||
MovePicker(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss = NULL);
|
MovePicker(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss = NULL);
|
||||||
Move get_next_move();
|
Move get_next_move();
|
||||||
Move get_next_move(Lock& lock);
|
Move get_next_move(Lock& lock);
|
||||||
int number_of_moves() const;
|
int number_of_moves() const;
|
||||||
Bitboard discovered_check_candidates() const;
|
Bitboard discovered_check_candidates() const;
|
||||||
|
|
||||||
static void init_phase_table();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void score_captures();
|
void score_captures();
|
||||||
void score_noncaptures();
|
void score_noncaptures();
|
||||||
|
@ -81,14 +78,12 @@ private:
|
||||||
|
|
||||||
const Position& pos;
|
const Position& pos;
|
||||||
const History& H;
|
const History& H;
|
||||||
Move ttMove, mateKiller, killer1, killer2;
|
Move ttMoves[2], killers[2];
|
||||||
Bitboard pinned, dc;
|
const MovegenPhaseT* phasePtr;
|
||||||
MoveStack moves[256], badCaptures[64];
|
int movesPicked, numOfMoves, numOfBadCaptures;
|
||||||
int phaseIndex;
|
|
||||||
int numOfMoves, numOfBadCaptures;
|
|
||||||
int movesPicked;
|
|
||||||
bool checkKillers, checkLegal;
|
|
||||||
bool finished;
|
bool finished;
|
||||||
|
Bitboard dc, pinned;
|
||||||
|
MoveStack moves[256], badCaptures[64];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue