1 | /* |
2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 |
3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) |
4 | Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
5 | Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad |
6 | |
7 | Stockfish is free software: you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation, either version 3 of the License, or |
10 | (at your option) any later version. |
11 | |
12 | Stockfish is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | */ |
20 | |
21 | #include <cassert> |
22 | |
23 | #include "movegen.h" |
24 | #include "position.h" |
25 | |
26 | namespace { |
27 | |
28 | template<GenType Type, Direction D> |
29 | ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) { |
30 | |
31 | if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) |
32 | *moveList++ = make<PROMOTION>(to - D, to, QUEEN); |
33 | |
34 | if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS) |
35 | { |
36 | *moveList++ = make<PROMOTION>(to - D, to, ROOK); |
37 | *moveList++ = make<PROMOTION>(to - D, to, BISHOP); |
38 | *moveList++ = make<PROMOTION>(to - D, to, KNIGHT); |
39 | } |
40 | |
41 | // Knight promotion is the only promotion that can give a direct check |
42 | // that's not already included in the queen promotion. |
43 | if (Type == QUIET_CHECKS && (PseudoAttacks[KNIGHT][to] & ksq)) |
44 | *moveList++ = make<PROMOTION>(to - D, to, KNIGHT); |
45 | else |
46 | (void)ksq; // Silence a warning under MSVC |
47 | |
48 | return moveList; |
49 | } |
50 | |
51 | |
52 | template<Color Us, GenType Type> |
53 | ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) { |
54 | |
55 | // Compute some compile time parameters relative to the white side |
56 | constexpr Color Them = (Us == WHITE ? BLACK : WHITE); |
57 | constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); |
58 | constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); |
59 | constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); |
60 | constexpr Direction UpRight = (Us == WHITE ? NORTH_EAST : SOUTH_WEST); |
61 | constexpr Direction UpLeft = (Us == WHITE ? NORTH_WEST : SOUTH_EAST); |
62 | |
63 | Bitboard emptySquares; |
64 | |
65 | Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB; |
66 | Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB; |
67 | |
68 | Bitboard enemies = (Type == EVASIONS ? pos.pieces(Them) & target: |
69 | Type == CAPTURES ? target : pos.pieces(Them)); |
70 | |
71 | // Single and double pawn pushes, no promotions |
72 | if (Type != CAPTURES) |
73 | { |
74 | emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces()); |
75 | |
76 | Bitboard b1 = shift<Up>(pawnsNotOn7) & emptySquares; |
77 | Bitboard b2 = shift<Up>(b1 & TRank3BB) & emptySquares; |
78 | |
79 | if (Type == EVASIONS) // Consider only blocking squares |
80 | { |
81 | b1 &= target; |
82 | b2 &= target; |
83 | } |
84 | |
85 | if (Type == QUIET_CHECKS) |
86 | { |
87 | Square ksq = pos.square<KING>(Them); |
88 | |
89 | b1 &= pos.attacks_from<PAWN>(ksq, Them); |
90 | b2 &= pos.attacks_from<PAWN>(ksq, Them); |
91 | |
92 | // Add pawn pushes which give discovered check. This is possible only |
93 | // if the pawn is not on the same file as the enemy king, because we |
94 | // don't generate captures. Note that a possible discovery check |
95 | // promotion has been already generated amongst the captures. |
96 | Bitboard dcCandidateQuiets = pos.blockers_for_king(Them) & pawnsNotOn7; |
97 | if (dcCandidateQuiets) |
98 | { |
99 | Bitboard dc1 = shift<Up>(dcCandidateQuiets) & emptySquares & ~file_bb(ksq); |
100 | Bitboard dc2 = shift<Up>(dc1 & TRank3BB) & emptySquares; |
101 | |
102 | b1 |= dc1; |
103 | b2 |= dc2; |
104 | } |
105 | } |
106 | |
107 | while (b1) |
108 | { |
109 | Square to = pop_lsb(&b1); |
110 | *moveList++ = make_move(to - Up, to); |
111 | } |
112 | |
113 | while (b2) |
114 | { |
115 | Square to = pop_lsb(&b2); |
116 | *moveList++ = make_move(to - Up - Up, to); |
117 | } |
118 | } |
119 | |
120 | // Promotions and underpromotions |
121 | if (pawnsOn7) |
122 | { |
123 | if (Type == CAPTURES) |
124 | emptySquares = ~pos.pieces(); |
125 | |
126 | if (Type == EVASIONS) |
127 | emptySquares &= target; |
128 | |
129 | Bitboard b1 = shift<UpRight>(pawnsOn7) & enemies; |
130 | Bitboard b2 = shift<UpLeft >(pawnsOn7) & enemies; |
131 | Bitboard b3 = shift<Up >(pawnsOn7) & emptySquares; |
132 | |
133 | Square ksq = pos.square<KING>(Them); |
134 | |
135 | while (b1) |
136 | moveList = make_promotions<Type, UpRight>(moveList, pop_lsb(&b1), ksq); |
137 | |
138 | while (b2) |
139 | moveList = make_promotions<Type, UpLeft >(moveList, pop_lsb(&b2), ksq); |
140 | |
141 | while (b3) |
142 | moveList = make_promotions<Type, Up >(moveList, pop_lsb(&b3), ksq); |
143 | } |
144 | |
145 | // Standard and en-passant captures |
146 | if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) |
147 | { |
148 | Bitboard b1 = shift<UpRight>(pawnsNotOn7) & enemies; |
149 | Bitboard b2 = shift<UpLeft >(pawnsNotOn7) & enemies; |
150 | |
151 | while (b1) |
152 | { |
153 | Square to = pop_lsb(&b1); |
154 | *moveList++ = make_move(to - UpRight, to); |
155 | } |
156 | |
157 | while (b2) |
158 | { |
159 | Square to = pop_lsb(&b2); |
160 | *moveList++ = make_move(to - UpLeft, to); |
161 | } |
162 | |
163 | if (pos.ep_square() != SQ_NONE) |
164 | { |
165 | assert(rank_of(pos.ep_square()) == relative_rank(Us, RANK_6)); |
166 | |
167 | // An en passant capture can be an evasion only if the checking piece |
168 | // is the double pushed pawn and so is in the target. Otherwise this |
169 | // is a discovery check and we are forced to do otherwise. |
170 | if (Type == EVASIONS && !(target & (pos.ep_square() - Up))) |
171 | return moveList; |
172 | |
173 | b1 = pawnsNotOn7 & pos.attacks_from<PAWN>(pos.ep_square(), Them); |
174 | |
175 | assert(b1); |
176 | |
177 | while (b1) |
178 | *moveList++ = make<ENPASSANT>(pop_lsb(&b1), pos.ep_square()); |
179 | } |
180 | } |
181 | |
182 | return moveList; |
183 | } |
184 | |
185 | |
186 | template<PieceType Pt, bool Checks> |
187 | ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Color us, |
188 | Bitboard target) { |
189 | |
190 | assert(Pt != KING && Pt != PAWN); |
191 | |
192 | const Square* pl = pos.squares<Pt>(us); |
193 | |
194 | for (Square from = *pl; from != SQ_NONE; from = *++pl) |
195 | { |
196 | if (Checks) |
197 | { |
198 | if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN) |
199 | && !(PseudoAttacks[Pt][from] & target & pos.check_squares(Pt))) |
200 | continue; |
201 | |
202 | if (pos.blockers_for_king(~us) & from) |
203 | continue; |
204 | } |
205 | |
206 | Bitboard b = pos.attacks_from<Pt>(from) & target; |
207 | |
208 | if (Checks) |
209 | b &= pos.check_squares(Pt); |
210 | |
211 | while (b) |
212 | *moveList++ = make_move(from, pop_lsb(&b)); |
213 | } |
214 | |
215 | return moveList; |
216 | } |
217 | |
218 | |
219 | template<Color Us, GenType Type> |
220 | ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target) { |
221 | |
222 | constexpr CastlingRight OO = Us | KING_SIDE; |
223 | constexpr CastlingRight OOO = Us | QUEEN_SIDE; |
224 | constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations |
225 | |
226 | moveList = generate_pawn_moves<Us, Type>(pos, moveList, target); |
227 | moveList = generate_moves<KNIGHT, Checks>(pos, moveList, Us, target); |
228 | moveList = generate_moves<BISHOP, Checks>(pos, moveList, Us, target); |
229 | moveList = generate_moves< ROOK, Checks>(pos, moveList, Us, target); |
230 | moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target); |
231 | |
232 | if (Type != QUIET_CHECKS && Type != EVASIONS) |
233 | { |
234 | Square ksq = pos.square<KING>(Us); |
235 | Bitboard b = pos.attacks_from<KING>(ksq) & target; |
236 | while (b) |
237 | *moveList++ = make_move(ksq, pop_lsb(&b)); |
238 | |
239 | if (Type != CAPTURES && pos.can_castle(CastlingRight(OO | OOO))) |
240 | { |
241 | if (!pos.castling_impeded(OO) && pos.can_castle(OO)) |
242 | *moveList++ = make<CASTLING>(ksq, pos.castling_rook_square(OO)); |
243 | |
244 | if (!pos.castling_impeded(OOO) && pos.can_castle(OOO)) |
245 | *moveList++ = make<CASTLING>(ksq, pos.castling_rook_square(OOO)); |
246 | } |
247 | } |
248 | |
249 | return moveList; |
250 | } |
251 | |
252 | } // namespace |
253 | |
254 | |
255 | /// <CAPTURES> Generates all pseudo-legal captures and queen promotions |
256 | /// <QUIETS> Generates all pseudo-legal non-captures and underpromotions |
257 | /// <NON_EVASIONS> Generates all pseudo-legal captures and non-captures |
258 | /// |
259 | /// Returns a pointer to the end of the move list. |
260 | |
261 | template<GenType Type> |
262 | ExtMove* generate(const Position& pos, ExtMove* moveList) { |
263 | |
264 | assert(Type == CAPTURES || Type == QUIETS || Type == NON_EVASIONS); |
265 | assert(!pos.checkers()); |
266 | |
267 | Color us = pos.side_to_move(); |
268 | |
269 | Bitboard target = Type == CAPTURES ? pos.pieces(~us) |
270 | : Type == QUIETS ? ~pos.pieces() |
271 | : Type == NON_EVASIONS ? ~pos.pieces(us) : 0; |
272 | |
273 | return us == WHITE ? generate_all<WHITE, Type>(pos, moveList, target) |
274 | : generate_all<BLACK, Type>(pos, moveList, target); |
275 | } |
276 | |
277 | // Explicit template instantiations |
278 | template ExtMove* generate<CAPTURES>(const Position&, ExtMove*); |
279 | template ExtMove* generate<QUIETS>(const Position&, ExtMove*); |
280 | template ExtMove* generate<NON_EVASIONS>(const Position&, ExtMove*); |
281 | |
282 | |
283 | /// generate<QUIET_CHECKS> generates all pseudo-legal non-captures and knight |
284 | /// underpromotions that give check. Returns a pointer to the end of the move list. |
285 | template<> |
286 | ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* moveList) { |
287 | |
288 | assert(!pos.checkers()); |
289 | |
290 | Color us = pos.side_to_move(); |
291 | Bitboard dc = pos.blockers_for_king(~us) & pos.pieces(us); |
292 | |
293 | while (dc) |
294 | { |
295 | Square from = pop_lsb(&dc); |
296 | PieceType pt = type_of(pos.piece_on(from)); |
297 | |
298 | if (pt == PAWN) |
299 | continue; // Will be generated together with direct checks |
300 | |
301 | Bitboard b = pos.attacks_from(pt, from) & ~pos.pieces(); |
302 | |
303 | if (pt == KING) |
304 | b &= ~PseudoAttacks[QUEEN][pos.square<KING>(~us)]; |
305 | |
306 | while (b) |
307 | *moveList++ = make_move(from, pop_lsb(&b)); |
308 | } |
309 | |
310 | return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, moveList, ~pos.pieces()) |
311 | : generate_all<BLACK, QUIET_CHECKS>(pos, moveList, ~pos.pieces()); |
312 | } |
313 | |
314 | |
315 | /// generate<EVASIONS> generates all pseudo-legal check evasions when the side |
316 | /// to move is in check. Returns a pointer to the end of the move list. |
317 | template<> |
318 | ExtMove* generate<EVASIONS>(const Position& pos, ExtMove* moveList) { |
319 | |
320 | assert(pos.checkers()); |
321 | |
322 | Color us = pos.side_to_move(); |
323 | Square ksq = pos.square<KING>(us); |
324 | Bitboard sliderAttacks = 0; |
325 | Bitboard sliders = pos.checkers() & ~pos.pieces(KNIGHT, PAWN); |
326 | |
327 | // Find all the squares attacked by slider checkers. We will remove them from |
328 | // the king evasions in order to skip known illegal moves, which avoids any |
329 | // useless legality checks later on. |
330 | while (sliders) |
331 | { |
332 | Square checksq = pop_lsb(&sliders); |
333 | sliderAttacks |= LineBB[checksq][ksq] ^ checksq; |
334 | } |
335 | |
336 | // Generate evasions for king, capture and non capture moves |
337 | Bitboard b = pos.attacks_from<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks; |
338 | while (b) |
339 | *moveList++ = make_move(ksq, pop_lsb(&b)); |
340 | |
341 | if (more_than_one(pos.checkers())) |
342 | return moveList; // Double check, only a king move can save the day |
343 | |
344 | // Generate blocking evasions or captures of the checking piece |
345 | Square checksq = lsb(pos.checkers()); |
346 | Bitboard target = between_bb(checksq, ksq) | checksq; |
347 | |
348 | return us == WHITE ? generate_all<WHITE, EVASIONS>(pos, moveList, target) |
349 | : generate_all<BLACK, EVASIONS>(pos, moveList, target); |
350 | } |
351 | |
352 | |
353 | /// generate<LEGAL> generates all the legal moves in the given position |
354 | |
355 | template<> |
356 | ExtMove* generate<LEGAL>(const Position& pos, ExtMove* moveList) { |
357 | |
358 | Color us = pos.side_to_move(); |
359 | Bitboard pinned = pos.blockers_for_king(us) & pos.pieces(us); |
360 | Square ksq = pos.square<KING>(us); |
361 | ExtMove* cur = moveList; |
362 | |
363 | moveList = pos.checkers() ? generate<EVASIONS >(pos, moveList) |
364 | : generate<NON_EVASIONS>(pos, moveList); |
365 | while (cur != moveList) |
366 | if ( (pinned || from_sq(*cur) == ksq || type_of(*cur) == ENPASSANT) |
367 | && !pos.legal(*cur)) |
368 | *cur = (--moveList)->move; |
369 | else |
370 | ++cur; |
371 | |
372 | return moveList; |
373 | } |
374 | |