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