Skip to content

Commit 6196555

Browse files
committed
Spell-chess: prune potion gates in quiet movegen
1 parent 595dd0f commit 6196555

File tree

2 files changed

+122
-6
lines changed

2 files changed

+122
-6
lines changed

perf_optimizations_log.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,9 @@ Idea v4: potion LMR tuning (lighter for potion checks/captures, heavier for weak
2727
- Bench new: 92861 NPS (-6.37%)
2828
- Perft startpos: depth1 1814, depth2 3007820, branching 1658.11 (unchanged)
2929
- Status: discarded (no Elo gain)
30+
31+
Idea v8: potion gate progressive pruning in QUIETS (topK gates by impact)
32+
- Bench baseline: 31353 NPS
33+
- Bench new: 67646 NPS (+115.8%)
34+
- Perft startpos: depth1 1814, depth2 3007820, branching 1658.11 (unchanged)
35+
- Status: pending (needs Elo test)

src/movegen.cpp

Lines changed: 116 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,64 @@ namespace {
4242
}
4343
};
4444

45+
struct GateScore {
46+
Square gate;
47+
int score;
48+
};
49+
50+
constexpr Direction RookDirections[] = {NORTH, SOUTH, EAST, WEST};
51+
constexpr Direction BishopDirections[] = {NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST};
52+
constexpr int PotionKingBonus = 10000;
53+
constexpr int MaxFreezePotionGates = 8;
54+
constexpr int MaxJumpPotionGates = 6;
55+
56+
void add_jump_gate_scores(const Position& pos, Color us, PieceType pt,
57+
const Direction* dirs, int dirCount, int scores[SQUARE_NB]) {
58+
Bitboard sliders = pos.pieces(us, pt);
59+
const Bitboard board = pos.board_bb();
60+
const Bitboard occ = pos.pieces();
61+
62+
while (sliders)
63+
{
64+
Square s = pop_lsb(sliders);
65+
for (int i = 0; i < dirCount; ++i)
66+
{
67+
Direction d = dirs[i];
68+
Square cur = s;
69+
while (true)
70+
{
71+
cur += d;
72+
if (!is_ok(cur) || !(board & square_bb(cur)))
73+
break;
74+
if (occ & square_bb(cur))
75+
{
76+
Square blocker = cur;
77+
cur += d;
78+
while (true)
79+
{
80+
if (!is_ok(cur) || !(board & square_bb(cur)))
81+
break;
82+
if (occ & square_bb(cur))
83+
{
84+
Piece target = pos.piece_on(cur);
85+
if (color_of(target) == ~us)
86+
{
87+
int bonus = int(CapturePieceValue[MG][target]);
88+
if (type_of(target) == pos.king_type())
89+
bonus += PotionKingBonus;
90+
scores[blocker] += bonus;
91+
}
92+
break;
93+
}
94+
cur += d;
95+
}
96+
break;
97+
}
98+
}
99+
}
100+
}
101+
}
102+
45103
template<MoveType T>
46104
ExtMove* make_move_and_gating(const Position& pos, ExtMove* moveList, Color us, Square from, Square to, PieceType pt = NO_PIECE_TYPE) {
47105

@@ -541,6 +599,9 @@ namespace {
541599
bool baseMovesSorted = false;
542600
Move baseMoves[MAX_MOVES];
543601
int baseCount = 0;
602+
constexpr bool LimitPotionGates = Type == QUIETS;
603+
int jumpGateScores[SQUARE_NB];
604+
bool jumpScoresReady = false;
544605

545606
for (int pt = 0; pt < Variant::POTION_TYPE_NB; ++pt)
546607
{
@@ -558,12 +619,10 @@ namespace {
558619
if (potion == Variant::POTION_JUMP)
559620
candidates &= allPieces;
560621

561-
while (candidates)
562-
{
563-
Square gate = pop_lsb(candidates);
622+
auto generate_for_gate = [&](Square gate) {
564623

565624
if (potion == Variant::POTION_JUMP && !(allPieces & gate))
566-
continue;
625+
return;
567626

568627
if (potion == Variant::POTION_FREEZE)
569628
{
@@ -595,7 +654,7 @@ namespace {
595654
}
596655

597656
cur = write;
598-
continue;
657+
return;
599658
}
600659

601660
Bitboard jumpRemoved = square_bb(gate);
@@ -625,7 +684,7 @@ namespace {
625684

626685
cur = write;
627686
if (!allowNonKing)
628-
continue;
687+
return;
629688

630689
if (!baseMovesSorted)
631690
{
@@ -691,6 +750,57 @@ namespace {
691750
}
692751

693752
cur = write;
753+
};
754+
755+
if constexpr (LimitPotionGates)
756+
{
757+
GateScore gateScores[SQUARE_NB];
758+
int gateCount = 0;
759+
760+
if (potion == Variant::POTION_JUMP && !jumpScoresReady)
761+
{
762+
std::fill_n(jumpGateScores, SQUARE_NB, 0);
763+
add_jump_gate_scores(pos, Us, ROOK, RookDirections, 4, jumpGateScores);
764+
add_jump_gate_scores(pos, Us, BISHOP, BishopDirections, 4, jumpGateScores);
765+
add_jump_gate_scores(pos, Us, QUEEN, RookDirections, 4, jumpGateScores);
766+
add_jump_gate_scores(pos, Us, QUEEN, BishopDirections, 4, jumpGateScores);
767+
jumpScoresReady = true;
768+
}
769+
770+
while (candidates)
771+
{
772+
Square gate = pop_lsb(candidates);
773+
int score = 0;
774+
if (potion == Variant::POTION_FREEZE)
775+
{
776+
Bitboard zone = pos.freeze_zone_from_square(gate);
777+
Bitboard enemies = zone & pos.pieces(~Us);
778+
while (enemies)
779+
score += int(CapturePieceValue[MG][pos.piece_on(pop_lsb(enemies))]);
780+
PieceType kingType = pos.king_type();
781+
if (kingType != NO_PIECE_TYPE && (zone & pos.pieces(~Us, kingType)))
782+
score += PotionKingBonus;
783+
}
784+
else
785+
score = jumpGateScores[gate];
786+
gateScores[gateCount++] = {gate, score};
787+
}
788+
789+
int gateLimit = potion == Variant::POTION_FREEZE ? MaxFreezePotionGates : MaxJumpPotionGates;
790+
if (gateCount > gateLimit)
791+
{
792+
std::partial_sort(gateScores, gateScores + gateLimit, gateScores + gateCount,
793+
[](const GateScore& a, const GateScore& b) { return a.score > b.score; });
794+
gateCount = gateLimit;
795+
}
796+
797+
for (int i = 0; i < gateCount; ++i)
798+
generate_for_gate(gateScores[i].gate);
799+
}
800+
else
801+
{
802+
while (candidates)
803+
generate_for_gate(pop_lsb(candidates));
694804
}
695805
}
696806

0 commit comments

Comments
 (0)