1
0
Fork 0
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:
Marco Costalba 2009-08-26 14:33:17 +01:00
parent e217407450
commit 595a90dfd0
3 changed files with 71 additions and 117 deletions

View file

@ -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();

View file

@ -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;
}

View file

@ -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];
}; };