Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
official-stockfish
GitHub Repository: official-stockfish/Stockfish
Path: blob/master/src/movegen.cpp
376 views
1
/*
2
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
3
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
4
5
Stockfish is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9
10
Stockfish is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
14
15
You should have received a copy of the GNU General Public License
16
along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include "movegen.h"
20
21
#include <cassert>
22
#include <initializer_list>
23
24
#include "bitboard.h"
25
#include "position.h"
26
27
#if defined(USE_AVX512ICL)
28
#include <array>
29
#include <algorithm>
30
#include <immintrin.h>
31
#endif
32
33
namespace Stockfish {
34
35
namespace {
36
37
#if defined(USE_AVX512ICL)
38
39
inline Move* write_moves(Move* moveList, uint32_t mask, __m512i vector) {
40
// Avoid _mm512_mask_compressstoreu_epi16() as it's 256 uOps on Zen4
41
_mm512_storeu_si512(reinterpret_cast<__m512i*>(moveList),
42
_mm512_maskz_compress_epi16(mask, vector));
43
return moveList + popcount(mask);
44
}
45
46
template<Direction offset>
47
inline Move* splat_pawn_moves(Move* moveList, Bitboard to_bb) {
48
alignas(64) static constexpr auto SPLAT_TABLE = [] {
49
std::array<Move, 64> table{};
50
for (int8_t i = 0; i < 64; i++)
51
{
52
Square from{std::clamp<int8_t>(i - offset, 0, 63)};
53
table[i] = {Move(from, Square{i})};
54
}
55
return table;
56
}();
57
58
auto table = reinterpret_cast<const __m512i*>(SPLAT_TABLE.data());
59
60
moveList =
61
write_moves(moveList, static_cast<uint32_t>(to_bb >> 0), _mm512_load_si512(table + 0));
62
moveList =
63
write_moves(moveList, static_cast<uint32_t>(to_bb >> 32), _mm512_load_si512(table + 1));
64
65
return moveList;
66
}
67
68
inline Move* splat_moves(Move* moveList, Square from, Bitboard to_bb) {
69
alignas(64) static constexpr auto SPLAT_TABLE = [] {
70
std::array<Move, 64> table{};
71
for (int8_t i = 0; i < 64; i++)
72
table[i] = {Move(SQUARE_ZERO, Square{i})};
73
return table;
74
}();
75
76
__m512i fromVec = _mm512_set1_epi16(Move(from, SQUARE_ZERO).raw());
77
78
auto table = reinterpret_cast<const __m512i*>(SPLAT_TABLE.data());
79
80
moveList = write_moves(moveList, static_cast<uint32_t>(to_bb >> 0),
81
_mm512_or_si512(_mm512_load_si512(table + 0), fromVec));
82
moveList = write_moves(moveList, static_cast<uint32_t>(to_bb >> 32),
83
_mm512_or_si512(_mm512_load_si512(table + 1), fromVec));
84
85
return moveList;
86
}
87
88
#else
89
90
template<Direction offset>
91
inline Move* splat_pawn_moves(Move* moveList, Bitboard to_bb) {
92
while (to_bb)
93
{
94
Square to = pop_lsb(to_bb);
95
*moveList++ = Move(to - offset, to);
96
}
97
return moveList;
98
}
99
100
inline Move* splat_moves(Move* moveList, Square from, Bitboard to_bb) {
101
while (to_bb)
102
*moveList++ = Move(from, pop_lsb(to_bb));
103
return moveList;
104
}
105
106
#endif
107
108
template<GenType Type, Direction D, bool Enemy>
109
Move* make_promotions(Move* moveList, [[maybe_unused]] Square to) {
110
111
constexpr bool all = Type == EVASIONS || Type == NON_EVASIONS;
112
113
if constexpr (Type == CAPTURES || all)
114
*moveList++ = Move::make<PROMOTION>(to - D, to, QUEEN);
115
116
if constexpr ((Type == CAPTURES && Enemy) || (Type == QUIETS && !Enemy) || all)
117
{
118
*moveList++ = Move::make<PROMOTION>(to - D, to, ROOK);
119
*moveList++ = Move::make<PROMOTION>(to - D, to, BISHOP);
120
*moveList++ = Move::make<PROMOTION>(to - D, to, KNIGHT);
121
}
122
123
return moveList;
124
}
125
126
127
template<Color Us, GenType Type>
128
Move* generate_pawn_moves(const Position& pos, Move* moveList, Bitboard target) {
129
130
constexpr Color Them = ~Us;
131
constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
132
constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
133
constexpr Direction Up = pawn_push(Us);
134
constexpr Direction UpRight = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
135
constexpr Direction UpLeft = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
136
137
const Bitboard emptySquares = ~pos.pieces();
138
const Bitboard enemies = Type == EVASIONS ? pos.checkers() : pos.pieces(Them);
139
140
Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB;
141
Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
142
143
// Single and double pawn pushes, no promotions
144
if constexpr (Type != CAPTURES)
145
{
146
Bitboard b1 = shift<Up>(pawnsNotOn7) & emptySquares;
147
Bitboard b2 = shift<Up>(b1 & TRank3BB) & emptySquares;
148
149
if constexpr (Type == EVASIONS) // Consider only blocking squares
150
{
151
b1 &= target;
152
b2 &= target;
153
}
154
155
moveList = splat_pawn_moves<Up>(moveList, b1);
156
moveList = splat_pawn_moves<Up + Up>(moveList, b2);
157
}
158
159
// Promotions and underpromotions
160
if (pawnsOn7)
161
{
162
Bitboard b1 = shift<UpRight>(pawnsOn7) & enemies;
163
Bitboard b2 = shift<UpLeft>(pawnsOn7) & enemies;
164
Bitboard b3 = shift<Up>(pawnsOn7) & emptySquares;
165
166
if constexpr (Type == EVASIONS)
167
b3 &= target;
168
169
while (b1)
170
moveList = make_promotions<Type, UpRight, true>(moveList, pop_lsb(b1));
171
172
while (b2)
173
moveList = make_promotions<Type, UpLeft, true>(moveList, pop_lsb(b2));
174
175
while (b3)
176
moveList = make_promotions<Type, Up, false>(moveList, pop_lsb(b3));
177
}
178
179
// Standard and en passant captures
180
if constexpr (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
181
{
182
Bitboard b1 = shift<UpRight>(pawnsNotOn7) & enemies;
183
Bitboard b2 = shift<UpLeft>(pawnsNotOn7) & enemies;
184
185
moveList = splat_pawn_moves<UpRight>(moveList, b1);
186
moveList = splat_pawn_moves<UpLeft>(moveList, b2);
187
188
if (pos.ep_square() != SQ_NONE)
189
{
190
assert(rank_of(pos.ep_square()) == relative_rank(Us, RANK_6));
191
192
// An en passant capture cannot resolve a discovered check
193
if (Type == EVASIONS && (target & (pos.ep_square() + Up)))
194
return moveList;
195
196
b1 = pawnsNotOn7 & attacks_bb<PAWN>(pos.ep_square(), Them);
197
198
assert(b1);
199
200
while (b1)
201
*moveList++ = Move::make<EN_PASSANT>(pop_lsb(b1), pos.ep_square());
202
}
203
}
204
205
return moveList;
206
}
207
208
209
template<Color Us, PieceType Pt>
210
Move* generate_moves(const Position& pos, Move* moveList, Bitboard target) {
211
212
static_assert(Pt != KING && Pt != PAWN, "Unsupported piece type in generate_moves()");
213
214
Bitboard bb = pos.pieces(Us, Pt);
215
216
while (bb)
217
{
218
Square from = pop_lsb(bb);
219
Bitboard b = attacks_bb<Pt>(from, pos.pieces()) & target;
220
221
moveList = splat_moves(moveList, from, b);
222
}
223
224
return moveList;
225
}
226
227
228
template<Color Us, GenType Type>
229
Move* generate_all(const Position& pos, Move* moveList) {
230
231
static_assert(Type != LEGAL, "Unsupported type in generate_all()");
232
233
const Square ksq = pos.square<KING>(Us);
234
Bitboard target;
235
236
// Skip generating non-king moves when in double check
237
if (Type != EVASIONS || !more_than_one(pos.checkers()))
238
{
239
target = Type == EVASIONS ? between_bb(ksq, lsb(pos.checkers()))
240
: Type == NON_EVASIONS ? ~pos.pieces(Us)
241
: Type == CAPTURES ? pos.pieces(~Us)
242
: ~pos.pieces(); // QUIETS
243
244
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
245
moveList = generate_moves<Us, KNIGHT>(pos, moveList, target);
246
moveList = generate_moves<Us, BISHOP>(pos, moveList, target);
247
moveList = generate_moves<Us, ROOK>(pos, moveList, target);
248
moveList = generate_moves<Us, QUEEN>(pos, moveList, target);
249
}
250
251
Bitboard b = attacks_bb<KING>(ksq) & (Type == EVASIONS ? ~pos.pieces(Us) : target);
252
253
moveList = splat_moves(moveList, ksq, b);
254
255
if ((Type == QUIETS || Type == NON_EVASIONS) && pos.can_castle(Us & ANY_CASTLING))
256
for (CastlingRights cr : {Us & KING_SIDE, Us & QUEEN_SIDE})
257
if (!pos.castling_impeded(cr) && pos.can_castle(cr))
258
*moveList++ = Move::make<CASTLING>(ksq, pos.castling_rook_square(cr));
259
260
return moveList;
261
}
262
263
} // namespace
264
265
266
// <CAPTURES> Generates all pseudo-legal captures plus queen promotions
267
// <QUIETS> Generates all pseudo-legal non-captures and underpromotions
268
// <EVASIONS> Generates all pseudo-legal check evasions
269
// <NON_EVASIONS> Generates all pseudo-legal captures and non-captures
270
//
271
// Returns a pointer to the end of the move list.
272
template<GenType Type>
273
Move* generate(const Position& pos, Move* moveList) {
274
275
static_assert(Type != LEGAL, "Unsupported type in generate()");
276
assert((Type == EVASIONS) == bool(pos.checkers()));
277
278
Color us = pos.side_to_move();
279
280
return us == WHITE ? generate_all<WHITE, Type>(pos, moveList)
281
: generate_all<BLACK, Type>(pos, moveList);
282
}
283
284
// Explicit template instantiations
285
template Move* generate<CAPTURES>(const Position&, Move*);
286
template Move* generate<QUIETS>(const Position&, Move*);
287
template Move* generate<EVASIONS>(const Position&, Move*);
288
template Move* generate<NON_EVASIONS>(const Position&, Move*);
289
290
// generate<LEGAL> generates all the legal moves in the given position
291
292
template<>
293
Move* generate<LEGAL>(const Position& pos, Move* moveList) {
294
295
Color us = pos.side_to_move();
296
Bitboard pinned = pos.blockers_for_king(us) & pos.pieces(us);
297
Square ksq = pos.square<KING>(us);
298
Move* cur = moveList;
299
300
moveList =
301
pos.checkers() ? generate<EVASIONS>(pos, moveList) : generate<NON_EVASIONS>(pos, moveList);
302
while (cur != moveList)
303
if (((pinned & cur->from_sq()) || cur->from_sq() == ksq || cur->type_of() == EN_PASSANT)
304
&& !pos.legal(*cur))
305
*cur = *(--moveList);
306
else
307
++cur;
308
309
return moveList;
310
}
311
312
} // namespace Stockfish
313
314