per test
[rattatechess.git] / move.cpp
blobff6042bd0aa0205b0ab561547db08f135fc6bf96
1 /***************************************************************************
2 move.cpp - description
3 -------------------
4 begin : lun ott 21 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 ***************************************************************************/
19 #include "engine.h"
20 #include "board.h"
21 #include <stdio.h>
23 #define HASH_KEY(piece, square) hash_keys[ PIECE_TO_12(piece)*64 + SQUARE_TO_64(square) ]
25 //-------------------------------------------------------------------------------------
27 /* return a 14 bits integer with the move */
28 uint16_t Board::compress_move(const Move& m) const
30 uint16_t retv = SQUARE_TO_64(m.from) | (SQUARE_TO_64(m.to)<<6);
32 if(m.flags >= PROMOTE_FIRST && m.flags <= PROMOTE_LAST)
34 retv |= (m.flags-PROMOTE0)<<12;
36 return retv;
39 Move Board::uncompress_move(uint16_t m) const
41 Move retv;
42 retv.from = SQUARE_FROM_64(m);
43 retv.to = SQUARE_FROM_64(m>>6);
44 retv.capture = data[retv.to];
45 retv.flags = 0;
47 if(PIECE_OF(data[retv.from]) == PAWN)
49 if(ABS(Y(retv.from)-Y(retv.to))==2)
50 retv.flags = PAWNOF2;
51 else if(X(retv.from) != X(retv.to) && !retv.capture)
52 retv.flags = ENPASSANT;
53 else if(Y(retv.to) == (color_to_move==WHITE?7:0))
54 retv.flags = (m>>12) + PROMOTE0;
56 else if(PIECE_OF(data[retv.from]) == KING)
58 if(X(retv.from)==4 && X(retv.to)==6)
59 retv.flags = CASTLEKINGSIDE;
60 else if(X(retv.from)==4 && X(retv.to)==2)
61 retv.flags = CASTLEQUEENSIDE;
63 return retv;
66 void Board::recalc_hash()
68 hash = HashKey(0,0);
70 int piece_pos = 128;
71 for(int i=7;i>=0;i--)
73 piece_pos -= 8;
74 for(int j=7;j>=0;j--)
76 piece_pos--;
78 if(data[piece_pos])
79 hash ^= HASH_KEY( data[piece_pos], piece_pos );
83 /* adjust castle and en-passant */
84 hash ^= hash_keys[ 12*64 + castle_passing_mask ];
86 /* adjust player to move */
87 if(color_to_move == BLACK)
88 hash ^= hash_key_toggle;
91 /* return the hash key that the board would have after playing the move */
92 HashKey Board::move_hash(const Move& m) const
94 uint8_t newcpm;
96 /* adjust hash key */
97 HashKey h = hash ^ hash_key_toggle
98 ^ HASH_KEY( data[m.from], m.to )
99 ^ HASH_KEY( data[m.from], m.from );
100 if(m.capture)
101 h ^= HASH_KEY( m.capture, m.to );
104 /* reset castle/en passant flags*/
105 newcpm = 12 | (castle_passing_mask & castle_adj[m.from] & castle_adj[m.to]);
107 /* handle special moves */
108 switch(m.flags)
110 case PAWNOF2:
111 newcpm ^= 12^X(m.to);
112 break;
114 case ENPASSANT:
116 uint8_t place = ROW_OF(m.from)+COL_OF(m.to);
117 h ^= HASH_KEY( PAWN|other_color, place );
118 break;
121 case CASTLEKINGSIDE:
123 uint8_t p1 = ROW_OF(m.from)+5;
124 uint8_t p2 = ROW_OF(m.from)+7;
125 h ^= HASH_KEY( color_to_move|ROOK, p1 )
126 ^ HASH_KEY( color_to_move|ROOK, p2 );
127 break;
130 case CASTLEQUEENSIDE:
132 uint8_t p1 = ROW_OF(m.from)+3;
133 uint8_t p2 = ROW_OF(m.from);
134 h ^= HASH_KEY( color_to_move|ROOK, p1 )
135 ^ HASH_KEY( color_to_move|ROOK, p2 );
136 break;
139 case PROMOTEROOK ... PROMOTEKNIGHT:
141 uint8_t p = (m.flags-4)|color_to_move;
142 h ^= HASH_KEY( color_to_move|PAWN, m.to )
143 ^ HASH_KEY( p, m.to );
144 break;
148 if(newcpm != castle_passing_mask)
149 h ^= hash_keys[ 12*64 + newcpm ]
150 ^ hash_keys[ 12*64 + castle_passing_mask ];
152 return h;
155 void
156 Board::do_null_move(SaveBuf& s)
158 s.hash_key = hash;
160 hash ^= hash_key_toggle;
162 SWITCH(color_to_move, other_color);
163 num_moves += IS_WHITE(color_to_move);
165 s.castle_passing_mask = castle_passing_mask;
166 s.fifty = fifty;
168 castle_passing_mask = 12 | (castle_passing_mask & 0xf0);
170 /* adjust the hash key for the new castle/en passant flags*/
171 if(s.castle_passing_mask != castle_passing_mask)
173 hash ^= hash_keys[ 12*64 + s.castle_passing_mask ]
174 ^ hash_keys[ 12*64 + castle_passing_mask ];
177 /* mark that now we do not know anything about pinnings */
178 under_check = 0xff;
181 void
182 Board::undo_null_move(const SaveBuf& s)
184 hash = s.hash_key;
186 num_moves -= IS_WHITE(color_to_move);
187 SWITCH(color_to_move, other_color);
189 fifty = s.fifty;
190 castle_passing_mask = s.castle_passing_mask;
192 /* mark that now we do not know anything about pinnings */
193 under_check = 0xff;
197 #ifdef DEBUG
198 #define HEAVY_DEBUG
199 #endif
201 //do move m and adjust hashkey
202 void
203 Board::do_move(const Move& m, SaveBuf& s)
205 A88 data = this->data;
207 #ifdef HEAVY_DEBUG
208 check_line_pawns();
209 check_mat_tracking();
210 #if TRACK_ATTACKS
211 check_attacks();
212 #endif //TRACK_ATTACKS
213 #endif //HEAVY_DEBUG
214 ASSERT(COLOR_OF(data[m.from]) == color_to_move);
215 ASSERT(data[king_pos[1]] == WK);
216 ASSERT(data[king_pos[0]] == BK);
217 ASSERT(DISTANCE(king_pos[0], king_pos[1]) >= 2);
219 /* save the hash key */
220 s.hash_key = hash;
222 /* save all flags about the position */
223 s.castle_passing_mask = castle_passing_mask;
224 s.fifty = fifty;
226 #if TRACK_ATTACKS
227 /* attacking info, 1/2 */
228 del_attacks(data[m.from], m.from);
229 #endif //TRACK_ATTACKS
231 data[m.to] = data[m.from];
232 data[m.from] = 0;
234 #if TRACK_ATTACKS
235 /* attacking info, 2/2 */
236 if(m.capture)
237 replace_attacks(m.capture,data[m.to], m.to);
238 else
239 add_attacks(data[m.to], m.to);
240 #endif //TRACK_ATTACKS;
242 /* update material tracking */
243 if(m.capture)
244 mat_remove(m.capture, m.to);
245 mat_move( data[m.to], m.from, m.to);
247 /* update pawn tracking */
248 if(PIECE_OF(data[m.to])==PAWN)
250 del_pawn(color_to_move, m.from);
251 if(m.flags <= 4) //readd pawn to tracking structure, unless promoting
252 add_pawn(color_to_move, m.to);
254 if(PIECE_OF(m.capture)==PAWN)
255 del_pawn(other_color, m.to);
257 /* adjust hash key */
258 hash ^= HASH_KEY( data[m.to], m.to )
259 ^ HASH_KEY( data[m.to], m.from )
260 ^ hash_key_toggle;
261 if(m.capture)
262 hash ^= HASH_KEY( m.capture, m.to );
264 /* reset fifty moves count */
265 if(m.capture || (PIECE_OF(data[m.to])==PAWN) )
266 fifty = 0;
267 else
268 fifty++;
270 /* reset castle/en passant flags*/
271 castle_passing_mask = 12 | (castle_passing_mask & castle_adj[m.from] & castle_adj[m.to]);
273 /* update king position */
274 if(PIECE_OF(data[m.to])==KING)
275 king_pos[IS_WHITE(data[m.to])] = m.to;
277 /* handle special moves */
278 switch(m.flags)
280 case PAWNOF2:
281 castle_passing_mask ^= 12^X(m.to);
282 break;
284 case ENPASSANT:
286 uint8_t place = ROW_OF(m.from)+COL_OF(m.to);
287 data[place] = 0;
288 mat_remove( PAWN|other_color, place);
289 del_pawn(other_color, place);
290 #if TRACK_ATTACKS
291 del_attacks(PAWN|other_color, place);
292 #endif //TRACK_ATTACKS
293 hash ^= HASH_KEY( PAWN|other_color, place );
294 break;
297 case CASTLEKINGSIDE:
299 uint8_t p1 = ROW_OF(m.from)+5;
300 uint8_t p2 = ROW_OF(m.from)+7;
301 data[p1] = data[p2];
302 data[p2] = 0;
303 mat_move( data[p1], p2, p1 );
304 #if TRACK_ATTACKS
305 del_attacks( data[p1], p2);
306 add_attacks( data[p1], p1);
307 #endif //TRACK_ATTACKS
308 hash ^= HASH_KEY( data[p1], p1 )
309 ^ HASH_KEY( data[p1], p2 );
310 break;
313 case CASTLEQUEENSIDE:
315 uint8_t p1 = ROW_OF(m.from)+3;
316 uint8_t p2 = ROW_OF(m.from);
317 data[p1] = data[p2];
318 data[p2] = 0;
319 mat_move( data[p1], p2, p1 );
320 #if TRACK_ATTACKS
321 del_attacks( data[p1], p2);
322 add_attacks( data[p1], p1);
323 #endif //TRACK_ATTACKS
324 hash ^= HASH_KEY( data[p1], p1 )
325 ^ HASH_KEY( data[p1], p2 );
326 break;
329 case PROMOTE_FIRST ... PROMOTE_LAST:
331 uint8_t p = (m.flags-PROMOTE0)|color_to_move;
332 hash ^= HASH_KEY( data[m.to], m.to )
333 ^ HASH_KEY( p, m.to );
334 mat_remove( data[m.to], m.to );
335 data[m.to] = p;
336 mat_add( data[m.to], m.to );
337 #if TRACK_ATTACKS
338 replace_attacks( 0, p, m.to );
339 #endif //TRACK_ATTACKS
343 /* adjust the hash key for the new castle/en passant flags*/
344 if(s.castle_passing_mask != castle_passing_mask)
346 hash ^= hash_keys[ 12*64 + s.castle_passing_mask ]
347 ^ hash_keys[ 12*64 + castle_passing_mask ];
350 /* switch side and increase move count */
351 SWITCH(color_to_move, other_color);
352 num_moves += IS_WHITE(color_to_move);
354 /* mark that now we do not know anything about pinnings */
355 under_check = 0xff;
357 ASSERT(data[king_pos[1]] == WK);
358 ASSERT(data[king_pos[0]] == BK);
359 ASSERT(DISTANCE(king_pos[0], king_pos[1]) >= 2);
360 #ifdef HEAVY_DEBUG
361 check_line_pawns();
362 check_mat_tracking();
363 #if TRACK_ATTACKS
364 check_attacks();
365 #endif //TRACK_ATTACKS
366 #endif //HEAVY_DEBUG
369 //-------------------------------------------------------------------------------------
370 //-------------------------------------------------------------------------------------
372 void
373 Board::undo_move(const Move& m, const SaveBuf& s)
375 A88 data = this->data;
377 #ifdef HEAVY_DEBUG
378 check_line_pawns();
379 check_mat_tracking();
380 #if TRACK_ATTACKS
381 check_attacks();
382 #endif //TRACK_ATTACKS
383 #endif //HEAVY_DEBUG
384 ASSERT(COLOR_OF(data[m.to]) == other_color);
385 ASSERT(data[king_pos[1]] == WK);
386 ASSERT(data[king_pos[0]] == BK);
387 ASSERT(DISTANCE(king_pos[0], king_pos[1]) >= 2);
389 #if TRACK_ATTACKS
390 /* attacking info, 1/2 */
391 if(m.capture)
392 replace_attacks(data[m.to], m.capture, m.to);
393 else
394 del_attacks(data[m.to], m.to);
395 #endif //TRACK_ATTACKS
397 data[m.from] = data[m.to];
398 if(m.capture)
399 data[m.to] = m.capture;
400 else
401 data[m.to] = 0;
403 #if TRACK_ATTACKS
404 /* attacking info, 2/2 */
405 add_attacks(data[m.from], m.from);
406 #endif //TRACK_ATTACKS
408 mat_move( data[m.from], m.to, m.from);
409 if(m.capture)
410 mat_add(m.capture, m.to);
412 /* update king position */
413 if(PIECE_OF(data[m.from])==KING)
414 king_pos[IS_WHITE(data[m.from])] = m.from;
416 /* handle special moves */
417 switch(m.flags)
419 case ENPASSANT:
421 uint8_t place = ROW_OF(m.from)+COL_OF(m.to);
422 data[place] = PAWN|color_to_move;
423 mat_add( PAWN|color_to_move, place);
424 add_pawn(color_to_move, place);
425 #if TRACK_ATTACKS
426 add_attacks( PAWN|color_to_move, place);
427 #endif //TRACK_ATTACKS
428 break;
431 case CASTLEQUEENSIDE:
433 uint8_t p1 = ROW_OF(m.from)+3;
434 uint8_t p2 = ROW_OF(m.from);
435 data[p2] = data[p1];
436 data[p1] = 0;
437 mat_move( data[p2], p1, p2 );
438 #if TRACK_ATTACKS
439 del_attacks( data[p2], p1);
440 add_attacks( data[p2], p2);
441 #endif //TRACK_ATTACKS
442 break;
445 case CASTLEKINGSIDE:
447 uint8_t p1 = ROW_OF(m.from)+5;
448 uint8_t p2 = ROW_OF(m.from)+7;
449 data[p2] = data[p1];
450 data[p1] = 0;
451 mat_move( data[p2], p1, p2 );
452 #if TRACK_ATTACKS
453 del_attacks( data[p2], p1);
454 add_attacks( data[p2], p2);
455 #endif //TRACK_ATTACKS
456 break;
459 case PROMOTE_FIRST ... PROMOTE_LAST:
461 uint8_t p = PAWN|other_color;
462 #if TRACK_ATTACKS
463 replace_attacks( data[m.from], 0, m.from );
464 #endif //TRACK_ATTACKS
465 mat_remove( data[m.from], m.from );
466 data[m.from] = p;
467 mat_add( data[m.from], m.from );
471 if(PIECE_OF(data[m.from])==PAWN)
473 if(m.flags <= 4)
474 del_pawn(other_color, m.to);
475 add_pawn(other_color, m.from);
477 if(PIECE_OF(m.capture)==PAWN)
478 add_pawn(color_to_move, m.to);
480 /* load saved flags */
481 fifty = s.fifty;
482 castle_passing_mask = s.castle_passing_mask;
483 hash = s.hash_key;
485 /* switch side and increase move count */
486 num_moves -= IS_WHITE(color_to_move);
487 SWITCH(color_to_move, other_color);
489 /* mark that now we do not know anything about pinnings */
490 under_check = 0xff;
492 ASSERT(data[king_pos[1]] == WK);
493 ASSERT(data[king_pos[0]] == BK);
494 ASSERT(DISTANCE(king_pos[0], king_pos[1]) >= 2);
495 #ifdef HEAVY_DEBUG
496 check_line_pawns();
497 check_mat_tracking();
498 #if TRACK_ATTACKS
499 check_attacks();
500 #endif //TRACK_ATTACKS
501 #endif //HEAVY_DEBUG