Fixed sideeffects of enabling the gui to visualize the search tree.
[rattatechess.git] / genmoves.cpp
blobeb6caf430f8c4421de79a4b855c8d2b807071845
1 /***************************************************************************
2 movegen.cpp - description
3 -------------------
4 begin : ven ott 25 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"
19 #include "engine.h"
21 /* macro to add a move in the move list */
22 #define ADDSIMPLEMOVE(f,tj) \
23 { \
24 register Move* mtmp=mvg_curr++; \
25 mtmp->from = (f); \
26 mtmp->to = (tj); \
27 mtmp->capture = 0; \
28 mtmp->flags = 0; \
29 mtmp->val = 0; \
32 #define ADDMOVE(f,tj,x) \
33 { \
34 register Move* mtmp=mvg_curr++; \
35 mtmp->from = (f); \
36 mtmp->to = (tj); \
37 mtmp->capture = data[((uint8_t)(tj))]; \
38 mtmp->flags = (x); \
39 mtmp->val = 0; \
42 #define ADDPROMOTE(f,tj) \
43 { \
44 register char kpt = data[(uint8_t)(tj)]; \
45 register Move* mtmp=mvg_curr; \
46 mtmp->from = (f); \
47 mtmp->to = (tj); \
48 mtmp->capture = (kpt); \
49 mtmp->flags = PROMOTEQUEEN; \
50 mtmp->val = 0; \
51 mtmp++; \
52 mtmp->from = (f); \
53 mtmp->to = (tj); \
54 mtmp->capture = (kpt); \
55 mtmp->flags = PROMOTEKNIGHT; \
56 mtmp->val = 0; \
57 mtmp++; \
58 mtmp->from = (f); \
59 mtmp->to = (tj); \
60 mtmp->capture = (kpt); \
61 mtmp->flags = PROMOTEBISHOP; \
62 mtmp->val = 0; \
63 mtmp++; \
64 mtmp->from = (f); \
65 mtmp->to = (tj); \
66 mtmp->capture = (kpt); \
67 mtmp->flags = PROMOTEROOK; \
68 mtmp->val = 0; \
69 mvg_curr+=4; \
72 void
73 Board::find_knight_moves( uint8_t where)
75 if(pins[where] & NFREE)
76 return;
78 KnightMove* hm= &Board::knightmoves[where];
79 for(int i=hm->numm;i>=0;i--)
81 register uint8_t currpos = hm->jump[i];
82 if(data[currpos] & color_to_move)
83 continue;
85 ADDMOVE(where,currpos,0);
89 //-------------------------------------------------------------------------------------
90 //-------------------------------------------------------------------------------------
92 void
93 Board::find_queen_moves( uint8_t where)
95 find_bishop_moves(where);
96 find_rook_moves(where);
99 //------------------------------------------------------------------------------------
100 //------------------------------------------------------------------------------------
102 void
103 Board::find_king_moves( uint8_t where)
105 uint8_t oldd = data[where];
106 bool freerg = false;
107 bool freelf = false;
109 /* clear the place where the king is, so that the
110 king is not 'protecting' cases near him */
111 data[where] = 0;
112 #if TRACK_ATTACKS
113 del_attacks(0, where);
114 #endif //TRACK_ATTACKS
116 for(int i=7;i>=0;i--)
118 uint8_t currpos = where + kingmoves[i];
119 if( OUT_OF_BOARD(currpos)
120 || (data[currpos] & color_to_move)
121 || (pins[currpos]&NFREE && data[currpos]==0)
122 || under_attack(currpos,other_color))
123 continue;
124 //minimize calls to the expensive "under_attack"
125 if(kingmoves[i]==RIGHT)
126 freerg = true;
127 else if(kingmoves[i]==LEFT)
128 freelf = true;
129 ADDMOVE(where,currpos,0);
132 /* test if castling is possible */
133 if(!under_check)
135 if(color_to_move==WHITE)
137 if((castle_passing_mask & WCANCASTLEKS)
138 && freerg // ie: !under_attack(POS_XY(5,0),BLACK)
139 && data[ first_rank[1]+5 ]==0
140 && data[ first_rank[1]+6 ]==0
141 && !under_attack( first_rank[1]+6 ,BLACK))
143 ADDMOVE(where, first_rank[1]+6 ,CASTLEKINGSIDE);
145 if((castle_passing_mask & WCANCASTLEQS)
146 && freelf // ie: !under_attack(POS_XY(3,0),BLACK)
147 && data[ first_rank[1]+3 ]==0
148 && data[ first_rank[1]+2 ]==0
149 && data[ first_rank[1]+1 ]==0
150 && !under_attack( first_rank[1]+2 ,BLACK))
152 ADDMOVE(where, first_rank[1]+2 ,CASTLEQUEENSIDE);
155 else
157 if((castle_passing_mask & BCANCASTLEKS)
158 && freerg // ie: !under_attack(POS_XY(5,7),WHITE)
159 && data[ first_rank[0]+5 ]==0
160 && data[ first_rank[0]+6 ]==0
161 && !under_attack( first_rank[0]+6, WHITE))
163 ADDMOVE(where, first_rank[0]+6 ,CASTLEKINGSIDE);
165 if((castle_passing_mask & BCANCASTLEQS)
166 && freelf // ie: !under_attack(POS_XY(3,7),WHITE)
167 && data[ first_rank[0]+3 ]==0
168 && data[ first_rank[0]+2 ]==0
169 && data[ first_rank[0]+1 ]==0
170 && !under_attack( first_rank[0]+2, WHITE))
172 ADDMOVE(where, first_rank[0]+2 ,CASTLEQUEENSIDE);
176 data[where] = oldd;
177 #if TRACK_ATTACKS
178 add_attacks(0, where);
179 #endif //TRACK_ATTACKS
182 //-------------------------------------------------------------------------------------
183 //-------------------------------------------------------------------------------------
185 void
186 Board::find_bishop_moves( uint8_t where)
188 /* fast path if the bishop is not pinned */
189 if( !(pins[where] & NFREE) )
191 for(int i=3;i>=0;i--)
193 register uint8_t currpos = where;
194 register uint8_t currinc = bishmoves[i];
198 currpos += currinc;
200 if(OUT_OF_BOARD(currpos))
201 break;
203 /* break if out of board or we found a where of the same color (or a stone) */
204 if(data[currpos] & color_to_move)
205 break;
207 ADDMOVE(where,currpos,0);
209 /* exit loop if the square is not empty (don't 'jump') */
210 while(!IS_OF_COLOR(data[currpos],other_color));
213 /* if we are pinned but we can move along the line */
214 else if(pins[where] & DIAG)
216 register uint8_t currinc = bishmoves[pins[where]&0x0f];
218 /* do for the 2 allowed directions (back and forward) */
219 for(int i=2;i>0;i--)
221 register uint8_t currpos = where;
225 currpos += currinc;
226 if(OUT_OF_BOARD(currpos))
227 break;
228 if(data[currpos] & color_to_move)
229 break;
230 ADDMOVE(where,currpos,0);
232 while(!IS_OF_COLOR(data[currpos],other_color));
234 currinc = -currinc;
239 //-------------------------------------------------------------------------------------
240 //-------------------------------------------------------------------------------------
242 void
243 Board::find_rook_moves( uint8_t where)
245 /* fast path if the rook is not pinned */
246 if(!(pins[where] & NFREE))
248 for(int i=3;i>=0;i--)
250 register uint8_t currpos = where;
251 register uint8_t currinc = rookmoves[i];
255 currpos += currinc;
257 if(OUT_OF_BOARD(currpos))
258 break;
260 /* break if out of board or we found a where of the same color (or a stone) */
261 if(data[currpos] & color_to_move)
262 break;
264 ADDMOVE(where,currpos,0);
266 /* exit loop if the square is not empty (don't 'jump') */
267 while(!IS_OF_COLOR(data[currpos],other_color));
270 /* if we are pinned but we can move along the line */
271 else if(pins[where] & COLM)
273 register uint8_t currinc = rookmoves[pins[where]&0x0f];
275 /* do for the 2 allowed directions (back and forward) */
276 for(int i=2;i>0;i--)
278 register uint8_t currpos = where;
282 currpos += currinc;
283 if(OUT_OF_BOARD(currpos))
284 break;
285 if(data[currpos] & color_to_move)
286 break;
287 ADDMOVE(where,currpos,0);
289 while(!IS_OF_COLOR(data[currpos],other_color));
291 currinc = -currinc;
296 //-------------------------------------------------------------------------------------
297 //-------------------------------------------------------------------------------------
299 void
300 Board::find_pawn_moves(uint8_t where)
302 /*static const uint8_t second_rank[] = { 0x60, 0x10 };
303 static const uint8_t seventh_rank[] = { 0x10, 0x60 };
304 static const uint8_t passant_rank[] = { 0x30, 0x40 };*/
306 uint8_t is_white = IS_WHITE(color_to_move);
307 uint8_t updir = up_dir[is_white];
308 uint8_t row_p = ROW_OF(where);
310 register uint8_t up = where + updir;
312 uint8_t cginfo=pins[where];
313 bool free = !(cginfo & NFREE);
314 bool cangoforw = true;
315 bool cantakerg = X(where) != 7;
316 bool cantakelf = X(where) != 0;
318 /* if the pawn is pinned set a few marks */
319 if(!free)
321 /* nm is the direction of the pinning
322 FIXME: theese checks depend on the layout of the bishop/rook moves array */
323 uint8_t nm = cginfo & 0x0f;
324 cangoforw = ((cginfo & COLM) && (nm>=2));
325 cantakerg &= ((cginfo & DIAG)
326 && ((nm&1) == 1-is_white));
327 cantakelf &= ((cginfo & DIAG)
328 && ((nm&1) == is_white));
331 /* if the pawn is not going to promote... */
332 if(row_p != seventh_rank[is_white])
334 /* if can the pawn move forward... */
335 if(IS_VOID(data[up]) && cangoforw)
337 uint8_t up2 = up + updir;
338 ADDSIMPLEMOVE(where,up);
340 /* if the pawn can move of two */
341 if(row_p == second_rank[is_white] && IS_VOID(data[up2]))
342 ADDMOVE(where,up2,PAWNOF2);
345 /* can the pawn capture on the right or take en passant? */
346 if(cantakerg) //not in the last col
348 uint8_t upright = up + RIGHT;
350 if(COLOR_OF(data[upright])==other_color)
352 ADDMOVE(where,upright,0);
354 else if( (row_p == passant_rank[is_white]) &&
355 ((castle_passing_mask&0x0f) == COL_OF(upright)))
357 /* uff, looks like this odd check is really needed, as the en passant
358 cannot be done if there is the king on one side and an enemy
359 ROOK (or queen) on the other */
360 uint8_t right_piece = 0;
361 uint8_t left_piece = 0;
362 uint8_t tmp_pos;
364 tmp_pos = where + LEFT;
365 while(1)
367 if(OUT_OF_BOARD(tmp_pos))
368 break;
369 if(data[tmp_pos])
371 left_piece = data[tmp_pos];
372 break;
374 tmp_pos += LEFT;
376 tmp_pos = where + 2*RIGHT;
377 while(1)
379 if(OUT_OF_BOARD(tmp_pos))
380 break;
381 if(data[tmp_pos])
383 right_piece = data[tmp_pos];
384 break;
386 tmp_pos += RIGHT;
388 if(!(left_piece == (KING|color_to_move)
389 && (right_piece&~BISHOP)==(ROOK|other_color))
390 && !(right_piece == (KING|color_to_move)
391 && (left_piece&~BISHOP)==(ROOK|other_color)))
393 ADDMOVE(where,upright,ENPASSANT);
398 /* can the pawn capture on the left or take en passant? */
399 if(cantakelf) //not in the first col
401 uint8_t upleft = up + LEFT;
403 if(COLOR_OF(data[upleft])==other_color)
405 ADDMOVE(where,upleft,0);
407 else if( (row_p == passant_rank[is_white]) &&
408 ((castle_passing_mask & 0x0f) == COL_OF(upleft)))
410 /* uff, looks like this odd check is really needed, as the en passant
411 cannot be done if there is the king on one side and an enemy
412 ROOK (or queen) on the other */
413 uint8_t right_piece = 0;
414 uint8_t left_piece = 0;
415 uint8_t tmp_pos;
417 tmp_pos = where + 2*LEFT;
418 while(1)
420 if(OUT_OF_BOARD(tmp_pos))
421 break;
422 if(data[tmp_pos])
424 left_piece = data[tmp_pos];
425 break;
427 tmp_pos += LEFT;
429 tmp_pos = where + RIGHT;
430 while(1)
432 if(OUT_OF_BOARD(tmp_pos))
433 break;
434 if(data[tmp_pos])
436 right_piece = data[tmp_pos];
437 break;
439 tmp_pos += RIGHT;
441 if(!(left_piece == (KING|color_to_move)
442 && (right_piece&~BISHOP)==(ROOK|other_color))
443 && !(right_piece == (KING|color_to_move)
444 && (left_piece&~BISHOP)==(ROOK|other_color)))
446 ADDMOVE(where,upleft,ENPASSANT);
451 else
453 /* can we go forw? */
454 if(IS_VOID(data[up]) && cangoforw)
456 ADDPROMOTE(where,up);
459 if(cantakerg) //not in the last col
461 uint8_t upright = up + RIGHT;
463 if(COLOR_OF(data[upright])==other_color)
465 ADDPROMOTE(where,upright);
469 if(cantakelf) //not in the first col
471 uint8_t upleft = up + LEFT;
473 if(COLOR_OF(data[upleft])==other_color)
475 ADDPROMOTE(where,upleft);
481 //-------------------------------------------------------------------------------------
482 //-------------------------------------------------------------------------------------
484 /* fill the mvs array (that we suppose to be big enough, etc) with all
485 the legal moves for the player on move */
486 int Board::find_moves(Move* mvs)
488 if(under_check == 0xff)
489 find_check_and_pins();
490 find_other_pins();
492 /* setup some useful data */
493 mvg_curr = mvs;
495 /* if not double check... */
496 if(under_check<2)
498 int mt = (color_to_move == BLACK ? -1 : +5);
499 for(int i=mat_tracking[ROOK+mt].count-1;i>=0;i--)
500 find_rook_moves( mat_tracking[ROOK+mt].pos[i]);
501 for(int i=mat_tracking[BISHOP+mt].count-1;i>=0;i--)
502 find_bishop_moves( mat_tracking[BISHOP+mt].pos[i]);
503 for(int i=mat_tracking[QUEEN+mt].count-1;i>=0;i--)
504 find_queen_moves( mat_tracking[QUEEN+mt].pos[i]);
505 for(int i=mat_tracking[KNIGHT+mt].count-1;i>=0;i--)
506 find_knight_moves( mat_tracking[KNIGHT+mt].pos[i]);
507 for(int i=mat_tracking[PAWN+mt].count-1;i>=0;i--)
508 find_pawn_moves( mat_tracking[PAWN+mt].pos[i]);
509 for(int i=mat_tracking[KING+mt].count-1;i>=0;i--) /* ! */
510 find_king_moves( mat_tracking[KING+mt].pos[i]);
512 /* if under check select only the moves that protect the king */
513 if(under_check==1)
515 int n=mvg_curr-mvs;
516 mvg_curr=mvs;
517 for(int i=0;i<n;i++)
518 if(pins[mvs[i].to]&NFREE //ok, interposition/capture
519 || ((mvs[i].flags == ENPASSANT) && //ok, taking a checking pawn en-passant
520 pins[ROW_OF(mvs[i].from) | COL_OF(mvs[i].to)]&NFREE)
521 || PIECE_OF(data[mvs[i].from])==KING) //ok, moving king
522 *mvg_curr++=mvs[i];
525 return mvg_curr-mvs;
528 /* under double check only generate king moves */
529 find_king_moves( king_pos[IS_WHITE(color_to_move)]);
530 return mvg_curr-mvs;