namespace {
enum Sequencer {
- MAIN_SEARCH, TT_MOVE_S1, CAPTURES_S1, KILLERS_S1, QUIETS_1_S1,
- QUIETS_2_S1, BAD_CAPTURES_S1, STOP_S1,
- EVASIONS, TT_MOVE_S2, EVASIONS_S2, STOP_S2,
- CAPTURES_AND_CHECKS, TT_MOVE_S3, CAPTURES_S3, QUIET_CHECKS_S3, STOP_S3,
- CAPTURES, TT_MOVE_S4, CAPTURES_S4, STOP_S4,
- PROBCUT, TT_MOVE_S5, CAPTURES_S5, STOP_S5,
- RECAPTURES, CAPTURES_S6, STOP_S6
+ MAIN_SEARCH, CAPTURES_S1, KILLERS_S1, QUIETS_1_S1, QUIETS_2_S1, BAD_CAPTURES_S1,
+ EVASION, EVASIONS_S2,
+ QSEARCH_0, CAPTURES_S3, QUIET_CHECKS_S3,
+ QSEARCH_1, CAPTURES_S4,
+ PROBCUT, CAPTURES_S5,
+ RECAPTURE, CAPTURES_S6,
+ STOP
};
// Unary predicate used by std::partition to split positive scores from remaining
assert(d > DEPTH_ZERO);
captureThreshold = 0;
- curMove = lastMove = 0;
- badCaptures = moves + MAX_MOVES;
+ curMove = lastMove = moves;
+ lastBadCapture = moves + MAX_MOVES - 1;
if (p.in_check())
- phase = EVASIONS;
+ phase = EVASION;
else
{
+ phase = MAIN_SEARCH;
+
killers[0].move = ss->killers[0];
killers[1].move = ss->killers[1];
// Consider negative captures as good if still enough to reach beta
else if (ss && ss->eval > beta)
captureThreshold = beta - ss->eval;
-
- phase = MAIN_SEARCH;
}
ttMove = (ttm && pos.is_pseudo_legal(ttm) ? ttm : MOVE_NONE);
- phase += (ttMove == MOVE_NONE);
+ lastMove += (ttMove != MOVE_NONE);
}
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const History& h,
- Square sq) : pos(p), H(h), curMove(0), lastMove(0) {
+ Square sq) : pos(p), H(h), curMove(moves), lastMove(moves) {
assert(d <= DEPTH_ZERO);
if (p.in_check())
- phase = EVASIONS;
+ phase = EVASION;
else if (d > DEPTH_QS_NO_CHECKS)
- phase = CAPTURES_AND_CHECKS;
+ phase = QSEARCH_0;
else if (d > DEPTH_QS_RECAPTURES)
{
- phase = CAPTURES;
+ phase = QSEARCH_1;
// Skip TT move if is not a capture or a promotion, this avoids qsearch
// tree explosion due to a possible perpetual check or similar rare cases
}
else
{
- phase = RECAPTURES - 1;
+ phase = RECAPTURE;
recaptureSquare = sq;
ttm = MOVE_NONE;
}
ttMove = (ttm && pos.is_pseudo_legal(ttm) ? ttm : MOVE_NONE);
- phase += (ttMove == MOVE_NONE);
+ lastMove += (ttMove != MOVE_NONE);
}
-MovePicker::MovePicker(const Position& p, Move ttm, const History& h,
- PieceType pt) : pos(p), H(h), curMove(0), lastMove(0) {
+MovePicker::MovePicker(const Position& p, Move ttm, const History& h, PieceType pt)
+ : pos(p), H(h), curMove(moves), lastMove(moves) {
assert(!pos.in_check());
// In ProbCut we generate only captures better than parent's captured piece
captureThreshold = PieceValueMidgame[pt];
+ ttMove = (ttm && pos.is_pseudo_legal(ttm) ? ttm : MOVE_NONE);
- if (ttm && (!pos.is_capture(ttm) || pos.see(ttm) <= captureThreshold))
- ttm = MOVE_NONE;
+ if (ttMove && (!pos.is_capture(ttMove) || pos.see(ttMove) <= captureThreshold))
+ ttMove = MOVE_NONE;
- ttMove = (ttm && pos.is_pseudo_legal(ttm) ? ttm : MOVE_NONE);
- phase += (ttMove == MOVE_NONE);
+ lastMove += (ttMove != MOVE_NONE);
}
- type_of(pos.piece_moved(m));
if (is_promotion(m))
- cur->score += PieceValueMidgame[promotion_piece_type(m)];
+ cur->score += PieceValueMidgame[promotion_type(m)];
}
}
void MovePicker::score_noncaptures() {
Move m;
- Square from;
for (MoveStack* cur = moves; cur != lastMove; cur++)
{
m = cur->move;
- from = from_sq(m);
- cur->score = H.value(pos.piece_on(from), to_sq(m));
+ cur->score = H.value(pos.piece_moved(m), to_sq(m));
}
}
}
-/// MovePicker::next_phase() generates, scores and sorts the next bunch of moves,
+/// MovePicker::generate_next() generates, scores and sorts the next bunch of moves,
/// when there are no more moves to try for the current phase.
-void MovePicker::next_phase() {
+void MovePicker::generate_next() {
curMove = moves;
switch (++phase) {
- case TT_MOVE_S1: case TT_MOVE_S2: case TT_MOVE_S3: case TT_MOVE_S4: case TT_MOVE_S5:
- lastMove = curMove + 1;
- return;
-
case CAPTURES_S1: case CAPTURES_S3: case CAPTURES_S4: case CAPTURES_S5: case CAPTURES_S6:
lastMove = generate<MV_CAPTURE>(pos, moves);
score_captures();
return;
case BAD_CAPTURES_S1:
- // Bad captures SEE value is already calculated so just pick them in order
- // to get SEE move ordering.
- curMove = badCaptures;
- lastMove = moves + MAX_MOVES;
+ // Just pick them in reverse order to get MVV/LVA ordering
+ curMove = moves + MAX_MOVES - 1;
+ lastMove = lastBadCapture;
return;
case EVASIONS_S2:
lastMove = generate<MV_QUIET_CHECK>(pos, moves);
return;
- case STOP_S1: case STOP_S2: case STOP_S3: case STOP_S4: case STOP_S5: case STOP_S6:
+ case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT: case RECAPTURE:
+ phase = STOP;
+ case STOP:
lastMove = curMove + 1; // Avoid another next_phase() call
return;
while (true)
{
while (curMove == lastMove)
- next_phase();
+ generate_next();
switch (phase) {
- case TT_MOVE_S1: case TT_MOVE_S2: case TT_MOVE_S3: case TT_MOVE_S4: case TT_MOVE_S5:
+ case MAIN_SEARCH: case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT:
curMove++;
return ttMove;
{
assert(captureThreshold <= 0); // Otherwise we cannot use see_sign()
- int seeScore = pos.see_sign(move);
- if (seeScore >= captureThreshold)
+ if (pos.see_sign(move) >= captureThreshold)
return move;
// Losing capture, move it to the tail of the array
- (--badCaptures)->move = move;
- badCaptures->score = seeScore;
+ (lastBadCapture--)->move = move;
}
break;
case KILLERS_S1:
move = (curMove++)->move;
- if ( move != MOVE_NONE
- && pos.is_pseudo_legal(move)
- && move != ttMove
+ if ( move != MOVE_NONE
+ && pos.is_pseudo_legal(move)
+ && move != ttMove
&& !pos.is_capture(move))
return move;
break;
- case QUIETS_1_S1:
- case QUIETS_2_S1:
+ case QUIETS_1_S1: case QUIETS_2_S1:
move = (curMove++)->move;
if ( move != ttMove
&& move != killers[0].move
break;
case BAD_CAPTURES_S1:
- move = pick_best(curMove++, lastMove)->move;
- return move;
+ return (curMove--)->move;
- case EVASIONS_S2:
- case CAPTURES_S3:
- case CAPTURES_S4:
+ case EVASIONS_S2: case CAPTURES_S3: case CAPTURES_S4:
move = pick_best(curMove++, lastMove)->move;
if (move != ttMove)
return move;
return move;
break;
- case STOP_S1: case STOP_S2: case STOP_S3: case STOP_S4: case STOP_S5: case STOP_S6:
+ case STOP:
return MOVE_NONE;
default: