This time pretty improved the rough-see heuristic.
[rattatechess.git] / check.cpp
blobdb27c97c5477f313a24fb08296ba10fbf11b10ad
1 /***************************************************************************
2 check.cpp - description
3 -------------------
4 begin : Wed Mar 13 2002
5 copyright : (C) 2002-2005 by Maurizio Monge
6 email : monge@linuz.sns.it
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 #include "board.h"
20 /*******************************************************************************
21 Find the pins for color to move and set a flag to mark whick is the
22 pinning direction. The under_check var is also set to a value that is
23 0/1/2 if the color to move is under no check, check or double check.
24 *******************************************************************************/
25 void
26 Board::find_check_and_pins()
28 ASSERT(data[king_pos[1]] == WK);
29 ASSERT(data[king_pos[0]] == BK);
30 ASSERT(DISTANCE(king_pos[0], king_pos[1]) >= 2);
32 A88 d = data;
33 A88 cg = pins;
34 uint8_t inc;
35 uint8_t check;
36 uint8_t maybe_ink;
38 uint8_t pos = king_pos[IS_WHITE(color_to_move)];
39 uint8_t attacker = other_color;
40 uint8_t defender = color_to_move;
41 uint8_t killer = BISHOP|attacker;
43 //clear pinning mask
44 zero_a88(pins);
46 under_check = 0;
48 /* check bishop (or queen) attacks */
49 for(int i=3;i>=0;i--)
51 inc = bishmoves[i];
52 check = pos;
53 maybe_ink = 0xff;
56 diag_cont_lab:;
57 check += inc;
59 if(OUT_OF_BOARD(check))
60 break;
62 if(COLOR_OF(d[check]) == defender)
64 if(maybe_ink==0xff) //first piece on the line?
66 maybe_ink = check;
67 goto diag_cont_lab;
69 else
70 break; //two non-offending pieces in the line
73 if( (d[check] & ((uint8_t)~ROOK)) == killer)
75 if(maybe_ink==0xff)
76 { //under a true check, sign all
77 register uint8_t p = pos;
78 under_check++;
81 p+=inc;
82 cg[p] = NFREE;
84 while(p!=check);
86 else
88 cg[maybe_ink] = NFREE|i|DIAG;
90 break;
93 while(!d[check]);
96 /* check rook (or queen) attacks */
97 killer = ROOK|attacker;
99 for(int i=3;i>=0;i--)
101 inc = rookmoves[i];
102 check = pos;
103 maybe_ink = 0xff;
106 col_cont_lab:;
107 check += inc;
109 if(OUT_OF_BOARD(check))
110 break;
112 if(COLOR_OF(d[check]) == defender)
114 if(maybe_ink==0xff) //first piece on the line?
116 maybe_ink = check;
117 goto col_cont_lab;
119 else
120 break; //two non-offending pieces in the line
123 if( (d[check] & ((uint8_t)~BISHOP)) == killer)
125 if(maybe_ink==0xff)
126 { //under a true check, sign all
127 register uint8_t p = pos;
128 under_check++;
131 p+=inc;
132 cg[p] = NFREE;
134 while(p!=check);
136 else
138 cg[maybe_ink] = NFREE|i|COLM;
140 break;
143 while(!d[check]);
146 /* check knight attacks */
147 killer = KNIGHT|attacker;
149 KnightMove* hm= &knightmoves[pos];
150 for(int i=hm->numm;i>=0;i--)
152 check = hm->jump[i];
153 if(d[check] == killer)
155 under_check++;
156 cg[check] = NFREE;
161 /* check pawn attacks */
163 killer = PAWN|attacker;
164 check = pos - up_dir[IS_WHITE(attacker)] + RIGHT;
165 if(!OUT_OF_BOARD(check) && (d[check] == killer))
167 under_check++;
168 cg[check] = NFREE;
171 check += 2*LEFT;
172 if(!OUT_OF_BOARD(check) && (d[check] == killer))
174 under_check++;
175 cg[check] = NFREE;
181 /*******************************************************************************
182 Find the pins for the other color.
183 *******************************************************************************/
184 void
185 Board::find_other_pins()
187 ASSERT(data[king_pos[1]] == WK);
188 ASSERT(data[king_pos[0]] == BK);
189 ASSERT(DISTANCE(king_pos[0], king_pos[1]) >= 2);
191 A88 d = data;
192 A88 cg = oth_pins;
193 uint8_t inc;
194 uint8_t check;
195 uint8_t maybe_ink;
197 uint8_t pos = king_pos[IS_WHITE(other_color)];
198 uint8_t attacker = color_to_move;
199 uint8_t killer = BISHOP|attacker;
201 //clear pinning mask
202 zero_a88(oth_pins);
204 /* check bishop (or queen) attacks */
205 for(int i=3;i>=0;i--)
207 inc = bishmoves[i];
208 check = pos;
209 maybe_ink = 0xff;
211 while(1)
213 check += inc;
215 if(OUT_OF_BOARD(check))
216 break;
218 if( (d[check] & ((uint8_t)~ROOK)) == killer)
220 ASSERT(maybe_ink!=0xff); //else, under a true check!
221 cg[maybe_ink] = NFREE|i|DIAG;
222 break;
224 else if(d[check])
226 if(maybe_ink!=0xff)
227 break;
228 maybe_ink = check;
233 /* check rook (or queen) attacks */
234 killer = ROOK|attacker;
236 for(int i=3;i>=0;i--)
238 inc = rookmoves[i];
239 check = pos;
240 maybe_ink = 0xff;
242 while(1)
244 check += inc;
246 if(OUT_OF_BOARD(check))
247 break;
249 if( (d[check] & ((uint8_t)~BISHOP)) == killer)
251 ASSERT(maybe_ink!=0xff); //else, under a true check!
252 cg[maybe_ink] = NFREE|i|COLM;
254 break;
256 else if(d[check])
258 if(maybe_ink!=0xff)
259 break;
260 maybe_ink = check;
266 /*******************************************************************************
267 Almost exact, does not handle en-passant and castle
268 *******************************************************************************/
269 bool
270 Board::move_is_check(const Move& m)
272 /* discover check? */
273 /* if a pawn is marked on an attack line and moves, it is almost
274 always a check (unless very rare en-passant on the attack line) */
275 if(oth_pins[m.from])
276 return true;
278 uint8_t enking = king_pos[IS_WHITE(other_color)];
279 uint8_t delta = enking - m.to;
280 uint8_t piece = PIECE_OF(data[m.from]);
282 /* not 100% exact, promotion to queen/rook may give check backward
283 and it would not be detected because of the pawn itself "interposed" */
284 if(m.flags >= PROMOTE_FIRST)
285 piece = m.flags-PROMOTE0;
287 switch(piece)
289 case PAWN:
291 if(delta == RIGHT_OF(up_dir[IS_WHITE(color_to_move)]) ||
292 delta == LEFT_OF(up_dir[IS_WHITE(color_to_move)]))
293 return true;
294 /* TODO:handle promote */
295 break;
298 case KNIGHT:
300 int deltax = X(enking) - X(m.to);
301 int deltay = Y(enking) - Y(m.to);
303 /* to see if it is reachable test if the distance is sqrt(5) */
304 if(deltax*deltax + deltay*deltay == 5)
305 return true;
306 break;
309 case QUEEN:
310 case BISHOP:
312 int deltax = X(enking) - X(m.to);
313 int deltay = Y(enking) - Y(m.to);
314 if(ABS(deltax) == ABS(deltay))
316 uint8_t inc = (deltax>0?RIGHT:LEFT) + (deltay>0?UP:DOWN);
317 for(uint8_t currpos = m.to+inc; currpos != enking; currpos+=inc)
318 if(data[currpos])
319 return false;
320 return true;
322 if(piece != QUEEN) /* for the queen fall through to the rook */
323 break;
326 case ROOK:
328 int deltax = X(enking) - X(m.to);
329 int deltay = Y(enking) - Y(m.to);
330 if(ABS(deltax)==0 || ABS(deltay)==0)
332 uint8_t inc = deltax>0 ? RIGHT : (deltax<0 ? LEFT : (deltay>0?UP:DOWN));
333 for(uint8_t currpos = m.to+inc; currpos != enking; currpos+=inc)
334 if(data[currpos])
335 return false;
336 return true;
338 break;
342 return false;