1 /* move_check.cpp
2
3 GNU Chess engine
4
5 Copyright (C) 2001-2011 Free Software Foundation, Inc.
6
7 This program 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 This program 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
22 // move_check.cpp
23
24 // includes
25
26 #include "attack.h"
27 #include "colour.h"
28 #include "fen.h"
29 #include "list.h"
30 #include "move.h"
31 #include "move_check.h"
32 #include "move_do.h"
33 #include "move_gen.h"
34 #include "piece.h"
35 #include "square.h"
36 #include "util.h"
37
38 namespace engine {
39
40 // prototypes
41
42 static void add_quiet_checks (list_t * list, const board_t * board);
43
44 static void add_castle_checks (list_t * list, board_t * board);
45
46 static void add_check (list_t * list, int move, board_t * board);
47
48 static void find_pins (int list[], const board_t * board);
49
50 // functions
51
52 // gen_quiet_checks()
53
gen_quiet_checks(list_t * list,board_t * board)54 void gen_quiet_checks(list_t * list, board_t * board) {
55
56 ASSERT(list!=NULL);
57 ASSERT(board!=NULL);
58
59 ASSERT(!board_is_check(board));
60
61 LIST_CLEAR(list);
62
63 add_quiet_checks(list,board);
64 add_castle_checks(list,board);
65
66 // debug
67
68 ASSERT(list_is_ok(list));
69 }
70
71 // add_quiet_checks()
72
add_quiet_checks(list_t * list,const board_t * board)73 static void add_quiet_checks(list_t * list, const board_t * board) {
74
75 int me, opp;
76 int king;
77 const sq_t * ptr, * ptr_2;
78 int from, to, sq;
79 int piece;
80 const inc_t * inc_ptr;
81 int inc;
82 int pawn;
83 int rank;
84 int pin[8+1];
85
86 ASSERT(list!=NULL);
87 ASSERT(board!=NULL);
88
89 // init
90
91 me = board->turn;
92 opp = COLOUR_OPP(me);
93
94 king = KING_POS(board,opp);
95
96 find_pins(pin,board);
97
98 // indirect checks
99
100 for (ptr = pin; (from=*ptr) != SquareNone; ptr++) {
101
102 piece = board->square[from];
103
104 ASSERT(is_pinned(board,from,opp));
105
106 if (PIECE_IS_PAWN(piece)) {
107
108 inc = PAWN_MOVE_INC(me);
109 rank = PAWN_RANK(from,me);
110
111 if (rank != Rank7) { // promotes are generated with captures
112 to = from + inc;
113 if (board->square[to] == Empty) {
114 if (DELTA_INC_LINE(to-king) != DELTA_INC_LINE(from-king)) {
115 ASSERT(!SQUARE_IS_PROMOTE(to));
116 LIST_ADD(list,MOVE_MAKE(from,to));
117 if (rank == Rank2) {
118 to = from + (2*inc);
119 if (board->square[to] == Empty) {
120 ASSERT(DELTA_INC_LINE(to-king)!=DELTA_INC_LINE(from-king));
121 ASSERT(!SQUARE_IS_PROMOTE(to));
122 LIST_ADD(list,MOVE_MAKE(from,to));
123 }
124 }
125 }
126 }
127 }
128
129 } else if (PIECE_IS_SLIDER(piece)) {
130
131 for (inc_ptr = PIECE_INC(piece); (inc=*inc_ptr) != IncNone; inc_ptr++) {
132 for (to = from+inc; board->square[to] == Empty; to += inc) {
133 ASSERT(DELTA_INC_LINE(to-king)!=DELTA_INC_LINE(from-king));
134 LIST_ADD(list,MOVE_MAKE(from,to));
135 }
136 }
137
138 } else {
139
140 for (inc_ptr = PIECE_INC(piece); (inc=*inc_ptr) != IncNone; inc_ptr++) {
141 to = from + inc;
142 if (board->square[to] == Empty) {
143 if (DELTA_INC_LINE(to-king) != DELTA_INC_LINE(from-king)) {
144 LIST_ADD(list,MOVE_MAKE(from,to));
145 }
146 }
147 }
148 }
149 }
150
151 // piece direct checks
152
153 for (ptr = &board->piece[me][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king
154
155 for (ptr_2 = pin; (sq=*ptr_2) != SquareNone; ptr_2++) {
156 if (sq == from) goto next_piece;
157 }
158
159 ASSERT(!is_pinned(board,from,opp));
160
161 piece = board->square[from];
162 inc_ptr = PIECE_INC(piece);
163
164 if (PIECE_IS_SLIDER(piece)) {
165
166 for (; (inc=*inc_ptr) != IncNone; inc_ptr++) {
167 for (to = from+inc; board->square[to] == Empty; to += inc) {
168 if (PIECE_ATTACK(board,piece,to,king)) {
169 LIST_ADD(list,MOVE_MAKE(from,to));
170 }
171 }
172 }
173
174 } else {
175
176 for (; (inc=*inc_ptr) != IncNone; inc_ptr++) {
177 to = from + inc;
178 if (board->square[to] == Empty) {
179 if (PSEUDO_ATTACK(piece,king-to)) {
180 LIST_ADD(list,MOVE_MAKE(from,to));
181 }
182 }
183 }
184 }
185
186 next_piece: ;
187 }
188
189 // pawn direct checks
190
191 inc = PAWN_MOVE_INC(me);
192 pawn = PAWN_MAKE(me);
193
194 to = king - (inc-1);
195 ASSERT(PSEUDO_ATTACK(pawn,king-to));
196
197 from = to - inc;
198 if (board->square[from] == pawn) {
199 if (board->square[to] == Empty) {
200 ASSERT(!SQUARE_IS_PROMOTE(to));
201 LIST_ADD(list,MOVE_MAKE(from,to));
202 }
203 } else {
204 from = to - (2*inc);
205 if (board->square[from] == pawn) {
206 if (PAWN_RANK(from,me) == Rank2
207 && board->square[to] == Empty
208 && board->square[from+inc] == Empty) {
209 ASSERT(!SQUARE_IS_PROMOTE(to));
210 LIST_ADD(list,MOVE_MAKE(from,to));
211 }
212 }
213 }
214
215 to = king - (inc+1);
216 ASSERT(PSEUDO_ATTACK(pawn,king-to));
217
218 from = to - inc;
219 if (board->square[from] == pawn) {
220 if (board->square[to] == Empty) {
221 ASSERT(!SQUARE_IS_PROMOTE(to));
222 LIST_ADD(list,MOVE_MAKE(from,to));
223 }
224 } else {
225 from = to - (2*inc);
226 if (board->square[from] == pawn) {
227 if (PAWN_RANK(from,me) == Rank2
228 && board->square[to] == Empty
229 && board->square[from+inc] == Empty) {
230 ASSERT(!SQUARE_IS_PROMOTE(to));
231 LIST_ADD(list,MOVE_MAKE(from,to));
232 }
233 }
234 }
235 }
236
237 // add_castle_checks()
238
add_castle_checks(list_t * list,board_t * board)239 static void add_castle_checks(list_t * list, board_t * board) {
240
241 ASSERT(list!=NULL);
242 ASSERT(board!=NULL);
243
244 ASSERT(!board_is_check(board));
245
246 if (COLOUR_IS_WHITE(board->turn)) {
247
248 if ((board->flags & FlagsWhiteKingCastle) != 0
249 && board->square[F1] == Empty
250 && board->square[G1] == Empty
251 && !is_attacked(board,F1,Black)) {
252 add_check(list,MOVE_MAKE_FLAGS(E1,G1,MoveCastle),board);
253 }
254
255 if ((board->flags & FlagsWhiteQueenCastle) != 0
256 && board->square[D1] == Empty
257 && board->square[C1] == Empty
258 && board->square[B1] == Empty
259 && !is_attacked(board,D1,Black)) {
260 add_check(list,MOVE_MAKE_FLAGS(E1,C1,MoveCastle),board);
261 }
262
263 } else { // black
264
265 if ((board->flags & FlagsBlackKingCastle) != 0
266 && board->square[F8] == Empty
267 && board->square[G8] == Empty
268 && !is_attacked(board,F8,White)) {
269 add_check(list,MOVE_MAKE_FLAGS(E8,G8,MoveCastle),board);
270 }
271
272 if ((board->flags & FlagsBlackQueenCastle) != 0
273 && board->square[D8] == Empty
274 && board->square[C8] == Empty
275 && board->square[B8] == Empty
276 && !is_attacked(board,D8,White)) {
277 add_check(list,MOVE_MAKE_FLAGS(E8,C8,MoveCastle),board);
278 }
279 }
280 }
281
282 // add_check()
283
add_check(list_t * list,int move,board_t * board)284 static void add_check(list_t * list, int move, board_t * board) {
285
286 undo_t undo[1];
287
288 ASSERT(list!=NULL);
289 ASSERT(move_is_ok(move));
290 ASSERT(board!=NULL);
291
292 move_do(board,move,undo);
293 if (IS_IN_CHECK(board,board->turn)) LIST_ADD(list,move);
294 move_undo(board,move,undo);
295 }
296
297 // move_is_check()
298
move_is_check(int move,board_t * board)299 bool move_is_check(int move, board_t * board) {
300
301 undo_t undo[1];
302 bool check;
303 int me, opp, king;
304 int from, to, piece;
305
306 ASSERT(move_is_ok(move));
307 ASSERT(board!=NULL);
308
309 // slow test for complex moves
310
311 if (MOVE_IS_SPECIAL(move)) {
312
313 move_do(board,move,undo);
314 check = IS_IN_CHECK(board,board->turn);
315 move_undo(board,move,undo);
316
317 return check;
318 }
319
320 // init
321
322 me = board->turn;
323 opp = COLOUR_OPP(me);
324 king = KING_POS(board,opp);
325
326 from = MOVE_FROM(move);
327 to = MOVE_TO(move);
328 piece = board->square[from];
329 ASSERT(COLOUR_IS(piece,me));
330
331 // direct check
332
333 if (PIECE_ATTACK(board,piece,to,king)) return true;
334
335 // indirect check
336
337 if (is_pinned(board,from,opp)
338 && DELTA_INC_LINE(king-to) != DELTA_INC_LINE(king-from)) {
339 return true;
340 }
341
342 return false;
343 }
344
345 // find_pins()
346
find_pins(int list[],const board_t * board)347 static void find_pins(int list[], const board_t * board) {
348
349 int me, opp;
350 int king;
351 const sq_t * ptr;
352 int from;
353 int piece;
354 int delta;
355 int inc;
356 int sq;
357 int capture;
358 int pin;
359
360 ASSERT(list!=NULL);
361 ASSERT(board!=NULL);
362
363 // init
364
365 me = board->turn;
366 opp = COLOUR_OPP(me);
367
368 king = KING_POS(board,opp);
369
370 for (ptr = &board->piece[me][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king
371
372 piece = board->square[from];
373
374 delta = king - from;
375 ASSERT(delta_is_ok(delta));
376
377 if (PSEUDO_ATTACK(piece,delta)) {
378
379 ASSERT(PIECE_IS_SLIDER(piece));
380
381 inc = DELTA_INC_LINE(delta);
382 ASSERT(inc!=IncNone);
383
384 ASSERT(SLIDER_ATTACK(piece,inc));
385
386 sq = from;
387 do sq += inc; while ((capture=board->square[sq]) == Empty);
388
389 ASSERT(sq!=king);
390
391 if (COLOUR_IS(capture,me)) {
392 pin = sq;
393 do sq += inc; while (board->square[sq] == Empty);
394 if (sq == king) *list++ = pin;
395 }
396 }
397 }
398
399 *list = SquareNone;
400 }
401
402 } // namespace engine
403
404 // end of move_check.cpp
405
406