Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
- Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
+ Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
namespace {
enum Stages {
- MAIN_SEARCH, GOOD_CAPTURES_INIT, GOOD_CAPTURES, KILLERS, KILLERS_2,
- QUIET_INIT, QUIET, BAD_CAPTURES,
- EVASION, ALL_EVASIONS,
- QSEARCH_WITH_CHECKS, QCAPTURES_CHECKS_INIT, QCAPTURES_CHECKS, CHECKS,
- QSEARCH_WITHOUT_CHECKS, QCAPTURES_NO_CHECKS, REMAINING,
- RECAPTURE, RECAPTURES,
- PROBCUT, PROBCUT_INIT, PROBCUT_CAPTURES
+ MAIN_SEARCH, CAPTURES_INIT, GOOD_CAPTURES, KILLERS, COUNTERMOVE, QUIET_INIT, QUIET, BAD_CAPTURES,
+ EVASION, EVASIONS_INIT, ALL_EVASIONS,
+ PROBCUT, PROBCUT_INIT, PROBCUT_CAPTURES,
+ QSEARCH_WITH_CHECKS, QCAPTURES_1_INIT, QCAPTURES_1, QCHECKS,
+ QSEARCH_NO_CHECKS, QCAPTURES_2_INIT, QCAPTURES_2,
+ QSEARCH_RECAPTURES, QRECAPTURES
};
// Our insertion sort, which is guaranteed to be stable, as it should be
stage = QSEARCH_WITH_CHECKS;
else if (d > DEPTH_QS_RECAPTURES)
- stage = QSEARCH_WITHOUT_CHECKS;
+ stage = QSEARCH_NO_CHECKS;
else
{
- stage = RECAPTURE;
+ stage = QSEARCH_RECAPTURES;
recaptureSquare = s;
return;
}
stage = PROBCUT;
- // In ProbCut we generate captures with SEE higher than the given threshold
+ // In ProbCut we generate captures with SEE higher than or equal to the given threshold
ttMove = ttm
&& pos.pseudo_legal(ttm)
&& pos.capture(ttm)
- && pos.see(ttm) > threshold ? ttm : MOVE_NONE;
+ && pos.see_ge(ttm, threshold)? ttm : MOVE_NONE;
stage += (ttMove == MOVE_NONE);
}
void MovePicker::score<QUIETS>() {
const HistoryStats& history = pos.this_thread()->history;
- const FromToStats& fromTo = pos.this_thread()->fromTo;
- const CounterMoveStats* cm = (ss-1)->counterMoves;
- const CounterMoveStats* fm = (ss-2)->counterMoves;
- const CounterMoveStats* f2 = (ss-4)->counterMoves;
+ const CounterMoveStats& cmh = *(ss-1)->counterMoves;
+ const CounterMoveStats& fmh = *(ss-2)->counterMoves;
+ const CounterMoveStats& fm2 = *(ss-4)->counterMoves;
Color c = pos.side_to_move();
for (auto& m : *this)
- m.value = history[pos.moved_piece(m)][to_sq(m)]
- + (cm ? (*cm)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO)
- + (fm ? (*fm)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO)
- + (f2 ? (*f2)[pos.moved_piece(m)][to_sq(m)] : VALUE_ZERO)
- + fromTo.get(c, m);
+ m.value = cmh[pos.moved_piece(m)][to_sq(m)]
+ + fmh[pos.moved_piece(m)][to_sq(m)]
+ + fm2[pos.moved_piece(m)][to_sq(m)]
+ + history.get(c, m);
}
template<>
void MovePicker::score<EVASIONS>() {
- // Try winning and equal captures ordered by MVV/LVA, then non-captures ordered
- // by history value, then bad captures and quiet moves with a negative SEE ordered
- // by SEE value.
+ // Try captures ordered by MVV/LVA, then non-captures ordered by stats heuristics
const HistoryStats& history = pos.this_thread()->history;
- const FromToStats& fromTo = pos.this_thread()->fromTo;
Color c = pos.side_to_move();
- Value see;
for (auto& m : *this)
- if ((see = pos.see_sign(m)) < VALUE_ZERO)
- m.value = see - HistoryStats::Max; // At the bottom
-
- else if (pos.capture(m))
+ if (pos.capture(m))
m.value = PieceValue[MG][pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m))) + HistoryStats::Max;
else
- m.value = history[pos.moved_piece(m)][to_sq(m)] + fromTo.get(c, m);
+ m.value = history.get(c, m);
}
switch (stage) {
case MAIN_SEARCH: case EVASION: case QSEARCH_WITH_CHECKS:
- case QSEARCH_WITHOUT_CHECKS: case PROBCUT:
+ case QSEARCH_NO_CHECKS: case PROBCUT:
++stage;
return ttMove;
- case GOOD_CAPTURES_INIT:
+ case CAPTURES_INIT:
endBadCaptures = cur = moves;
endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>();
move = pick_best(cur++, endMoves);
if (move != ttMove)
{
- if (pos.see_sign(move) >= VALUE_ZERO)
+ if (pos.see_ge(move, VALUE_ZERO))
return move;
// Losing capture, move it to the beginning of the array
*endBadCaptures++ = move;
}
}
- ++stage;
- // First killer move
- move = ss->killers[0];
+ ++stage;
+ move = ss->killers[0]; // First killer move
if ( move != MOVE_NONE
&& move != ttMove
&& pos.pseudo_legal(move)
&& !pos.capture(move))
return move;
- case KILLERS_2:
+ case COUNTERMOVE:
++stage;
move = countermove;
if ( move != MOVE_NONE
return *cur++;
break;
- case ALL_EVASIONS:
+ case EVASIONS_INIT:
cur = moves;
endMoves = generate<EVASIONS>(pos, cur);
- if (endMoves - cur > 1)
- score<EVASIONS>();
- stage = REMAINING;
- goto remaining;
-
- case QCAPTURES_CHECKS_INIT:
- case QCAPTURES_NO_CHECKS:
- cur = moves;
- endMoves = generate<CAPTURES>(pos, cur);
- score<CAPTURES>();
+ score<EVASIONS>();
++stage;
-remaining:
- case QCAPTURES_CHECKS:
- case REMAINING:
+ case ALL_EVASIONS:
while (cur < endMoves)
{
move = pick_best(cur++, endMoves);
if (move != ttMove)
return move;
}
- if (stage == REMAINING)
- break;
+ break;
+
+ case PROBCUT_INIT:
cur = moves;
- endMoves = generate<QUIET_CHECKS>(pos, cur);
+ endMoves = generate<CAPTURES>(pos, cur);
+ score<CAPTURES>();
++stage;
- case CHECKS:
+ case PROBCUT_CAPTURES:
while (cur < endMoves)
{
- move = cur++->move;
- if (move != ttMove)
+ move = pick_best(cur++, endMoves);
+ if ( move != ttMove
+ && pos.see_ge(move, threshold))
return move;
}
break;
- case RECAPTURE:
+ case QCAPTURES_1_INIT: case QCAPTURES_2_INIT:
cur = moves;
endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>();
++stage;
- case RECAPTURES:
+ case QCAPTURES_1: case QCAPTURES_2:
while (cur < endMoves)
{
move = pick_best(cur++, endMoves);
- if (to_sq(move) == recaptureSquare)
+ if (move != ttMove)
+ return move;
+ }
+ if (stage == QCAPTURES_2)
+ break;
+ cur = moves;
+ endMoves = generate<QUIET_CHECKS>(pos, cur);
+ ++stage;
+
+ case QCHECKS:
+ while (cur < endMoves)
+ {
+ move = cur++->move;
+ if (move != ttMove)
return move;
}
break;
- case PROBCUT_INIT:
+ case QSEARCH_RECAPTURES:
cur = moves;
endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>();
++stage;
- case PROBCUT_CAPTURES:
+ case QRECAPTURES:
while (cur < endMoves)
{
move = pick_best(cur++, endMoves);
- if ( move != ttMove
- && pos.see(move) > threshold)
+ if (to_sq(move) == recaptureSquare)
return move;
}
break;