Skip to content

Commit d41ead9

Browse files
committed
Spell chess: lazy potion generation in MovePicker
1 parent 6196555 commit d41ead9

File tree

6 files changed

+110
-8
lines changed

6 files changed

+110
-8
lines changed

perf_optimizations_log.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,16 @@ Idea v8: potion gate progressive pruning in QUIETS (topK gates by impact)
3232
- Bench baseline: 31353 NPS
3333
- Bench new: 67646 NPS (+115.8%)
3434
- Perft startpos: depth1 1814, depth2 3007820, branching 1658.11 (unchanged)
35+
- Status: accepted (user: ~+80 Elo)
36+
37+
Idea v9: potion LMP pruning in search (non-PV, quiet potion moves)
38+
- Bench baseline: 137793 NPS
39+
- Bench new: 135998 NPS (-1.30%)
40+
- Perft startpos: unchanged (search-only change)
41+
- Status: discarded (no Elo gain)
42+
43+
Idea v10: lazy potion generation in MovePicker (generate potions only after quiets)
44+
- Bench baseline: 137402 NPS
45+
- Bench new: 172862 NPS (+25.8%)
46+
- Perft startpos: unchanged (generation-order change)
3547
- Status: pending (needs Elo test)

src/movegen.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,62 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) {
837837
: generate_all<BLACK, Type>(pos, moveList);
838838
}
839839

840+
ExtMove* generate_base(GenType Type, const Position& pos, ExtMove* moveList) {
841+
842+
assert(Type != LEGAL);
843+
Color us = pos.side_to_move();
844+
845+
switch (Type)
846+
{
847+
case CAPTURES:
848+
return us == WHITE ? generate_all_impl<WHITE, CAPTURES>(pos, moveList)
849+
: generate_all_impl<BLACK, CAPTURES>(pos, moveList);
850+
case QUIETS:
851+
return us == WHITE ? generate_all_impl<WHITE, QUIETS>(pos, moveList)
852+
: generate_all_impl<BLACK, QUIETS>(pos, moveList);
853+
case QUIET_CHECKS:
854+
return us == WHITE ? generate_all_impl<WHITE, QUIET_CHECKS>(pos, moveList)
855+
: generate_all_impl<BLACK, QUIET_CHECKS>(pos, moveList);
856+
case EVASIONS:
857+
return us == WHITE ? generate_all_impl<WHITE, EVASIONS>(pos, moveList)
858+
: generate_all_impl<BLACK, EVASIONS>(pos, moveList);
859+
case NON_EVASIONS:
860+
return us == WHITE ? generate_all_impl<WHITE, NON_EVASIONS>(pos, moveList)
861+
: generate_all_impl<BLACK, NON_EVASIONS>(pos, moveList);
862+
default:
863+
assert(false);
864+
return moveList;
865+
}
866+
}
867+
868+
ExtMove* generate_potions(GenType Type, const Position& pos, ExtMove* baseStart, ExtMove* baseEnd) {
869+
870+
assert(Type != LEGAL);
871+
Color us = pos.side_to_move();
872+
873+
switch (Type)
874+
{
875+
case CAPTURES:
876+
return us == WHITE ? generate_potion_moves<WHITE, CAPTURES>(pos, baseStart, baseEnd)
877+
: generate_potion_moves<BLACK, CAPTURES>(pos, baseStart, baseEnd);
878+
case QUIETS:
879+
return us == WHITE ? generate_potion_moves<WHITE, QUIETS>(pos, baseStart, baseEnd)
880+
: generate_potion_moves<BLACK, QUIETS>(pos, baseStart, baseEnd);
881+
case QUIET_CHECKS:
882+
return us == WHITE ? generate_potion_moves<WHITE, QUIET_CHECKS>(pos, baseStart, baseEnd)
883+
: generate_potion_moves<BLACK, QUIET_CHECKS>(pos, baseStart, baseEnd);
884+
case EVASIONS:
885+
return us == WHITE ? generate_potion_moves<WHITE, EVASIONS>(pos, baseStart, baseEnd)
886+
: generate_potion_moves<BLACK, EVASIONS>(pos, baseStart, baseEnd);
887+
case NON_EVASIONS:
888+
return us == WHITE ? generate_potion_moves<WHITE, NON_EVASIONS>(pos, baseStart, baseEnd)
889+
: generate_potion_moves<BLACK, NON_EVASIONS>(pos, baseStart, baseEnd);
890+
default:
891+
assert(false);
892+
return baseEnd;
893+
}
894+
}
895+
840896
// Explicit template instantiations
841897
template ExtMove* generate<CAPTURES>(const Position&, ExtMove*);
842898
template ExtMove* generate<QUIETS>(const Position&, ExtMove*);

src/movegen.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ inline bool operator<(const ExtMove& f, const ExtMove& s) {
5555
template<GenType>
5656
ExtMove* generate(const Position& pos, ExtMove* moveList);
5757

58+
ExtMove* generate_base(GenType Type, const Position& pos, ExtMove* moveList);
59+
ExtMove* generate_potions(GenType Type, const Position& pos, ExtMove* baseStart, ExtMove* baseEnd);
60+
5861
constexpr size_t moveListSize = sizeof(ExtMove) * MAX_MOVES;
5962

6063
/// The MoveList struct is a simple wrapper around generate(). It sometimes comes

src/movepick.cpp

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ int history_slot(Piece pc) {
3232
namespace {
3333

3434
enum Stages {
35-
MAIN_TT, CAPTURE_INIT, GOOD_CAPTURE, REFUTATION, QUIET_INIT, QUIET, BAD_CAPTURE,
35+
MAIN_TT, CAPTURE_INIT, GOOD_CAPTURE, REFUTATION, QUIET_INIT, QUIET, POTION_INIT, POTION, BAD_CAPTURE,
3636
EVASION_TT, EVASION_INIT, EVASION,
3737
PROBCUT_TT, PROBCUT_INIT, PROBCUT,
3838
QSEARCH_TT, QCAPTURE_INIT, QCAPTURE, QCHECK_INIT, QCHECK
@@ -117,7 +117,7 @@ bool MovePicker::is_potion_move(Move m) const {
117117
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const GateHistory* dh, const LowPlyHistory* lp,
118118
const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, const Move* killers, int pl)
119119
: pos(p), mainHistory(mh), gateHistory(dh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch),
120-
ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) {
120+
ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, quietStart(moves), quietEnd(moves), depth(d), ply(pl) {
121121

122122
assert(d > 0);
123123

@@ -128,7 +128,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist
128128
/// MovePicker constructor for quiescence search
129129
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const GateHistory* dh,
130130
const CapturePieceToHistory* cph, const PieceToHistory** ch, Square rs)
131-
: pos(p), mainHistory(mh), gateHistory(dh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d) {
131+
: pos(p), mainHistory(mh), gateHistory(dh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), quietStart(moves), quietEnd(moves), recaptureSquare(rs), depth(d) {
132132

133133
assert(d <= 0);
134134

@@ -141,7 +141,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist
141141
/// MovePicker constructor for ProbCut: we generate captures with SEE greater
142142
/// than or equal to the given threshold.
143143
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const GateHistory* dh, const CapturePieceToHistory* cph)
144-
: pos(p), gateHistory(dh), captureHistory(cph), ttMove(ttm), threshold(th) {
144+
: pos(p), gateHistory(dh), captureHistory(cph), ttMove(ttm), quietStart(moves), quietEnd(moves), threshold(th) {
145145

146146
assert(!pos.checkers());
147147

@@ -272,12 +272,16 @@ Move MovePicker::next_move(bool skipQuiets) {
272272
case QUIET_INIT:
273273
if (!skipQuiets && !(pos.must_capture() && pos.has_capture()))
274274
{
275-
cur = endBadCaptures;
276-
endMoves = generate<QUIETS>(pos, cur);
275+
quietStart = endBadCaptures;
276+
quietEnd = generate_base(QUIETS, pos, quietStart);
277+
cur = quietStart;
278+
endMoves = quietEnd;
277279

278280
score<QUIETS>();
279281
partial_insertion_sort(cur, endMoves, -3000 * depth);
280282
}
283+
else
284+
quietStart = quietEnd = endBadCaptures;
281285

282286
++stage;
283287
[[fallthrough]];
@@ -289,6 +293,34 @@ Move MovePicker::next_move(bool skipQuiets) {
289293
&& *cur != refutations[2].move;}))
290294
return *(cur - 1);
291295

296+
++stage;
297+
[[fallthrough]];
298+
299+
case POTION_INIT:
300+
if ( skipQuiets
301+
|| (pos.must_capture() && pos.has_capture())
302+
|| !pos.potions_enabled()
303+
|| quietStart == quietEnd)
304+
{
305+
cur = moves;
306+
endMoves = endBadCaptures;
307+
stage = BAD_CAPTURE;
308+
goto top;
309+
}
310+
311+
cur = quietEnd;
312+
endMoves = generate_potions(QUIETS, pos, quietStart, quietEnd);
313+
314+
score<QUIETS>();
315+
partial_insertion_sort(cur, endMoves, -3000 * depth);
316+
317+
++stage;
318+
[[fallthrough]];
319+
320+
case POTION:
321+
if (select<Next>([&](){return true;}))
322+
return *(cur - 1);
323+
292324
// Prepare the pointers to loop over the bad captures
293325
cur = moves;
294326
endMoves = endBadCaptures;

src/movepick.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ class MovePicker {
157157
const CapturePieceToHistory* captureHistory;
158158
const PieceToHistory** continuationHistory;
159159
Move ttMove;
160-
ExtMove refutations[3], *cur, *endMoves, *endBadCaptures;
160+
ExtMove refutations[3], *cur, *endMoves, *endBadCaptures, *quietStart, *quietEnd;
161161
int stage;
162162
Square recaptureSquare;
163163
Value threshold;

src/search.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,6 @@ namespace {
11641164
if (pos.must_capture() && pos.attackers_to(to_sq(move), ~us))
11651165
{}
11661166
else
1167-
11681167
if ( captureOrPromotion
11691168
|| givesCheck)
11701169
{

0 commit comments

Comments
 (0)