Initial support for a qt gui to show search.
[rattatechess.git] / move.cpp
blob13a9ae554631b81123284835a6bb2152dc13275f
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()
158 old_hashes[num_old_hashes++] = hash;
159 hash ^= hash_key_toggle;
161 SWITCH(color_to_move, other_color);
162 num_moves += IS_WHITE(color_to_move);
164 flags_stack[flags_stack_ptr++] = castle_passing_mask;
165 flags_stack[flags_stack_ptr++] = fifty;
166 castle_passing_mask = 12 | (castle_passing_mask & 0xf0);
168 /* adjust the hash key for the new castle/en passant flags*/
169 if(flags_stack[flags_stack_ptr-2] != castle_passing_mask)
171 hash ^= hash_keys[ 12*64 + flags_stack[flags_stack_ptr-2] ]
172 ^ hash_keys[ 12*64 + castle_passing_mask ];
175 /* mark that now we do not know anything about pinnings */
176 under_check = 0xff;
179 void
180 Board::undo_null_move()
182 hash = old_hashes[--num_old_hashes];
184 num_moves -= IS_WHITE(color_to_move);
185 SWITCH(color_to_move, other_color);
187 fifty = flags_stack[--flags_stack_ptr];
188 castle_passing_mask = flags_stack[--flags_stack_ptr];
190 /* mark that now we do not know anything about pinnings */
191 under_check = 0xff;
195 #ifdef DEBUG
196 #define HEAVY_DEBUG
197 #endif
199 //do move m and adjust hashkey
200 void
201 Board::do_move(const Move& m)
203 A88 data = this->data;
205 #ifdef HEAVY_DEBUG
206 check_line_pawns();
207 check_mat_tracking();
208 #if TRACK_ATTACKS
209 check_attacks();
210 #endif //TRACK_ATTACKS
211 #endif //HEAVY_DEBUG
212 ASSERT(COLOR_OF(data[m.from]) == color_to_move);
213 ASSERT(data[king_pos[1]] == WK);
214 ASSERT(data[king_pos[0]] == BK);
215 ASSERT(DISTANCE(king_pos[0], king_pos[1]) >= 2);
217 /* save the hash key */
218 old_hashes[num_old_hashes++] = hash;
220 /* save all flags about the position */
221 flags_stack[flags_stack_ptr++] = castle_passing_mask;
222 flags_stack[flags_stack_ptr++] = fifty;
224 #if TRACK_ATTACKS
225 /* attacking info, 1/2 */
226 del_attacks(data[m.from], m.from);
227 #endif //TRACK_ATTACKS
229 data[m.to] = data[m.from];
230 data[m.from] = 0;
232 #if TRACK_ATTACKS
233 /* attacking info, 2/2 */
234 if(m.capture)
235 replace_attacks(m.capture,data[m.to], m.to);
236 else
237 add_attacks(data[m.to], m.to);
238 #endif //TRACK_ATTACKS;
240 /* update material tracking */
241 if(m.capture)
242 mat_remove(m.capture, m.to);
243 mat_move( data[m.to], m.from, m.to);
245 /* update pawn tracking */
246 if(PIECE_OF(data[m.to])==PAWN)
248 del_pawn(color_to_move, m.from);
249 if(m.flags <= 4) //readd pawn to tracking structure, unless promoting
250 add_pawn(color_to_move, m.to);
252 if(PIECE_OF(m.capture)==PAWN)
253 del_pawn(other_color, m.to);
255 /* adjust hash key */
256 hash ^= HASH_KEY( data[m.to], m.to )
257 ^ HASH_KEY( data[m.to], m.from )
258 ^ hash_key_toggle;
259 if(m.capture)
260 hash ^= HASH_KEY( m.capture, m.to );
262 /* reset fifty moves count */
263 if(m.capture || (PIECE_OF(data[m.to])==PAWN) )
264 fifty = 0;
265 else
266 fifty++;
268 /* reset castle/en passant flags*/
269 castle_passing_mask = 12 | (castle_passing_mask & castle_adj[m.from] & castle_adj[m.to]);
271 /* update king position */
272 if(PIECE_OF(data[m.to])==KING)
273 king_pos[IS_WHITE(data[m.to])] = m.to;
275 /* handle special moves */
276 switch(m.flags)
278 case PAWNOF2:
279 castle_passing_mask ^= 12^X(m.to);
280 break;
282 case ENPASSANT:
284 uint8_t place = ROW_OF(m.from)+COL_OF(m.to);
285 data[place] = 0;
286 mat_remove( PAWN|other_color, place);
287 del_pawn(other_color, place);
288 #if TRACK_ATTACKS
289 del_attacks(PAWN|other_color, place);
290 #endif //TRACK_ATTACKS
291 hash ^= HASH_KEY( PAWN|other_color, place );
292 break;
295 case CASTLEKINGSIDE:
297 uint8_t p1 = ROW_OF(m.from)+5;
298 uint8_t p2 = ROW_OF(m.from)+7;
299 data[p1] = data[p2];
300 data[p2] = 0;
301 mat_move( data[p1], p2, p1 );
302 #if TRACK_ATTACKS
303 del_attacks( data[p1], p2);
304 add_attacks( data[p1], p1);
305 #endif //TRACK_ATTACKS
306 hash ^= HASH_KEY( data[p1], p1 )
307 ^ HASH_KEY( data[p1], p2 );
308 break;
311 case CASTLEQUEENSIDE:
313 uint8_t p1 = ROW_OF(m.from)+3;
314 uint8_t p2 = ROW_OF(m.from);
315 data[p1] = data[p2];
316 data[p2] = 0;
317 mat_move( data[p1], p2, p1 );
318 #if TRACK_ATTACKS
319 del_attacks( data[p1], p2);
320 add_attacks( data[p1], p1);
321 #endif //TRACK_ATTACKS
322 hash ^= HASH_KEY( data[p1], p1 )
323 ^ HASH_KEY( data[p1], p2 );
324 break;
327 case PROMOTE_FIRST ... PROMOTE_LAST:
329 uint8_t p = (m.flags-PROMOTE0)|color_to_move;
330 hash ^= HASH_KEY( data[m.to], m.to )
331 ^ HASH_KEY( p, m.to );
332 mat_remove( data[m.to], m.to );
333 data[m.to] = p;
334 mat_add( data[m.to], m.to );
335 #if TRACK_ATTACKS
336 replace_attacks( 0, p, m.to );
337 #endif //TRACK_ATTACKS
341 /* adjust the hash key for the new castle/en passant flags*/
342 if(flags_stack[flags_stack_ptr-2] != castle_passing_mask)
344 hash ^= hash_keys[ 12*64 + flags_stack[flags_stack_ptr-2] ]
345 ^ hash_keys[ 12*64 + castle_passing_mask ];
348 /* switch side and increase move count */
349 SWITCH(color_to_move, other_color);
350 num_moves += IS_WHITE(color_to_move);
352 /* mark that now we do not know anything about pinnings */
353 under_check = 0xff;
355 ASSERT(data[king_pos[1]] == WK);
356 ASSERT(data[king_pos[0]] == BK);
357 ASSERT(DISTANCE(king_pos[0], king_pos[1]) >= 2);
358 #ifdef HEAVY_DEBUG
359 check_line_pawns();
360 check_mat_tracking();
361 #if TRACK_ATTACKS
362 check_attacks();
363 #endif //TRACK_ATTACKS
364 #endif //HEAVY_DEBUG
367 //-------------------------------------------------------------------------------------
368 //-------------------------------------------------------------------------------------
370 void
371 Board::undo_move(const Move& m)
373 A88 data = this->data;
375 #ifdef HEAVY_DEBUG
376 check_line_pawns();
377 check_mat_tracking();
378 #if TRACK_ATTACKS
379 check_attacks();
380 #endif //TRACK_ATTACKS
381 #endif //HEAVY_DEBUG
382 ASSERT(COLOR_OF(data[m.to]) == other_color);
383 ASSERT(data[king_pos[1]] == WK);
384 ASSERT(data[king_pos[0]] == BK);
385 ASSERT(DISTANCE(king_pos[0], king_pos[1]) >= 2);
387 #if TRACK_ATTACKS
388 /* attacking info, 1/2 */
389 if(m.capture)
390 replace_attacks(data[m.to], m.capture, m.to);
391 else
392 del_attacks(data[m.to], m.to);
393 #endif //TRACK_ATTACKS
395 data[m.from] = data[m.to];
396 if(m.capture)
397 data[m.to] = m.capture;
398 else
399 data[m.to] = 0;
401 #if TRACK_ATTACKS
402 /* attacking info, 2/2 */
403 add_attacks(data[m.from], m.from);
404 #endif //TRACK_ATTACKS
406 mat_move( data[m.from], m.to, m.from);
407 if(m.capture)
408 mat_add(m.capture, m.to);
410 /* update king position */
411 if(PIECE_OF(data[m.from])==KING)
412 king_pos[IS_WHITE(data[m.from])] = m.from;
414 /* handle special moves */
415 switch(m.flags)
417 case ENPASSANT:
419 uint8_t place = ROW_OF(m.from)+COL_OF(m.to);
420 data[place] = PAWN|color_to_move;
421 mat_add( PAWN|color_to_move, place);
422 add_pawn(color_to_move, place);
423 #if TRACK_ATTACKS
424 add_attacks( PAWN|color_to_move, place);
425 #endif //TRACK_ATTACKS
426 break;
429 case CASTLEQUEENSIDE:
431 uint8_t p1 = ROW_OF(m.from)+3;
432 uint8_t p2 = ROW_OF(m.from);
433 data[p2] = data[p1];
434 data[p1] = 0;
435 mat_move( data[p2], p1, p2 );
436 #if TRACK_ATTACKS
437 del_attacks( data[p2], p1);
438 add_attacks( data[p2], p2);
439 #endif //TRACK_ATTACKS
440 break;
443 case CASTLEKINGSIDE:
445 uint8_t p1 = ROW_OF(m.from)+5;
446 uint8_t p2 = ROW_OF(m.from)+7;
447 data[p2] = data[p1];
448 data[p1] = 0;
449 mat_move( data[p2], p1, p2 );
450 #if TRACK_ATTACKS
451 del_attacks( data[p2], p1);
452 add_attacks( data[p2], p2);
453 #endif //TRACK_ATTACKS
454 break;
457 case PROMOTE_FIRST ... PROMOTE_LAST:
459 uint8_t p = PAWN|other_color;
460 #if TRACK_ATTACKS
461 replace_attacks( data[m.from], 0, m.from );
462 #endif //TRACK_ATTACKS
463 mat_remove( data[m.from], m.from );
464 data[m.from] = p;
465 mat_add( data[m.from], m.from );
469 if(PIECE_OF(data[m.from])==PAWN)
471 if(m.flags <= 4)
472 del_pawn(other_color, m.to);
473 add_pawn(other_color, m.from);
475 if(PIECE_OF(m.capture)==PAWN)
476 add_pawn(color_to_move, m.to);
478 /* load saved flags */
479 fifty = flags_stack[--flags_stack_ptr];
480 castle_passing_mask = flags_stack[--flags_stack_ptr];
481 hash = old_hashes[--num_old_hashes];
483 /* switch side and increase move count */
484 num_moves -= IS_WHITE(color_to_move);
485 SWITCH(color_to_move, other_color);
487 /* mark that now we do not know anything about pinnings */
488 under_check = 0xff;
490 ASSERT(data[king_pos[1]] == WK);
491 ASSERT(data[king_pos[0]] == BK);
492 ASSERT(DISTANCE(king_pos[0], king_pos[1]) >= 2);
493 #ifdef HEAVY_DEBUG
494 check_line_pawns();
495 check_mat_tracking();
496 #if TRACK_ATTACKS
497 check_attacks();
498 #endif //TRACK_ATTACKS
499 #endif //HEAVY_DEBUG