1 /***************************************************************************
2 movegen.cpp - description
4 begin : ven ott 25 2002
5 copyright : (C) 2002-2005 by Maurizio Monge
6 email : monge@linuz.sns.it
7 ***************************************************************************/
9 /***************************************************************************
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. *
16 ***************************************************************************/
21 /* macro to add a move in the move list */
22 #define ADDSIMPLEMOVE(f,tj) \
24 register Move* mtmp=mvg_curr++; \
32 #define ADDMOVE(f,tj,x) \
34 register Move* mtmp=mvg_curr++; \
37 mtmp->capture = data[((uint8_t)(tj))]; \
42 #define ADDPROMOTE(f,tj) \
44 register char kpt = data[(uint8_t)(tj)]; \
45 register Move* mtmp=mvg_curr; \
48 mtmp->capture = (kpt); \
49 mtmp->flags = PROMOTEQUEEN; \
54 mtmp->capture = (kpt); \
55 mtmp->flags = PROMOTEKNIGHT; \
60 mtmp->capture = (kpt); \
61 mtmp->flags = PROMOTEBISHOP; \
66 mtmp->capture = (kpt); \
67 mtmp->flags = PROMOTEROOK; \
73 Board::find_knight_moves( uint8_t where
)
75 if(pins
[where
] & NFREE
)
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
)
85 ADDMOVE(where
,currpos
,0);
89 //-------------------------------------------------------------------------------------
90 //-------------------------------------------------------------------------------------
93 Board::find_queen_moves( uint8_t where
)
95 find_bishop_moves(where
);
96 find_rook_moves(where
);
99 //------------------------------------------------------------------------------------
100 //------------------------------------------------------------------------------------
103 Board::find_king_moves( uint8_t where
)
105 uint8_t oldd
= data
[where
];
109 /* clear the place where the king is, so that the
110 king is not 'protecting' cases near him */
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
))
124 //minimize calls to the expensive "under_attack"
125 if(kingmoves
[i
]==RIGHT
)
127 else if(kingmoves
[i
]==LEFT
)
129 ADDMOVE(where
,currpos
,0);
132 /* test if castling is possible */
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
);
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
);
178 add_attacks(0, where
);
179 #endif //TRACK_ATTACKS
182 //-------------------------------------------------------------------------------------
183 //-------------------------------------------------------------------------------------
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
];
200 if(OUT_OF_BOARD(currpos
))
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
)
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) */
221 register uint8_t currpos
= where
;
226 if(OUT_OF_BOARD(currpos
))
228 if(data
[currpos
] & color_to_move
)
230 ADDMOVE(where
,currpos
,0);
232 while(!IS_OF_COLOR(data
[currpos
],other_color
));
239 //-------------------------------------------------------------------------------------
240 //-------------------------------------------------------------------------------------
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
];
257 if(OUT_OF_BOARD(currpos
))
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
)
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) */
278 register uint8_t currpos
= where
;
283 if(OUT_OF_BOARD(currpos
))
285 if(data
[currpos
] & color_to_move
)
287 ADDMOVE(where
,currpos
,0);
289 while(!IS_OF_COLOR(data
[currpos
],other_color
));
296 //-------------------------------------------------------------------------------------
297 //-------------------------------------------------------------------------------------
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 */
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;
364 tmp_pos
= where
+ LEFT
;
367 if(OUT_OF_BOARD(tmp_pos
))
371 left_piece
= data
[tmp_pos
];
376 tmp_pos
= where
+ 2*RIGHT
;
379 if(OUT_OF_BOARD(tmp_pos
))
383 right_piece
= data
[tmp_pos
];
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;
417 tmp_pos
= where
+ 2*LEFT
;
420 if(OUT_OF_BOARD(tmp_pos
))
424 left_piece
= data
[tmp_pos
];
429 tmp_pos
= where
+ RIGHT
;
432 if(OUT_OF_BOARD(tmp_pos
))
436 right_piece
= data
[tmp_pos
];
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
);
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();
492 /* setup some useful data */
495 /* if not double check... */
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 */
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
528 /* under double check only generate king moves */
529 find_king_moves( king_pos
[IS_WHITE(color_to_move
)]);