1 /***************************************************************************
4 begin : lun ott 21 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 ***************************************************************************/
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;
39 Move
Board::uncompress_move(uint16_t m
) const
42 retv
.from
= SQUARE_FROM_64(m
);
43 retv
.to
= SQUARE_FROM_64(m
>>6);
44 retv
.capture
= data
[retv
.to
];
47 if(PIECE_OF(data
[retv
.from
]) == PAWN
)
49 if(ABS(Y(retv
.from
)-Y(retv
.to
))==2)
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
;
66 void Board::recalc_hash()
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
97 HashKey h
= hash
^ hash_key_toggle
98 ^ HASH_KEY( data
[m
.from
], m
.to
)
99 ^ HASH_KEY( data
[m
.from
], m
.from
);
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 */
111 newcpm
^= 12^X(m
.to
);
116 uint8_t place
= ROW_OF(m
.from
)+COL_OF(m
.to
);
117 h
^= HASH_KEY( PAWN
|other_color
, place
);
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
);
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
);
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
);
148 if(newcpm
!= castle_passing_mask
)
149 h
^= hash_keys
[ 12*64 + newcpm
]
150 ^ hash_keys
[ 12*64 + castle_passing_mask
];
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 */
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 */
199 //do move m and adjust hashkey
201 Board::do_move(const Move
& m
)
203 A88 data
= this->data
;
207 check_mat_tracking();
210 #endif //TRACK_ATTACKS
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
;
225 /* attacking info, 1/2 */
226 del_attacks(data
[m
.from
], m
.from
);
227 #endif //TRACK_ATTACKS
229 data
[m
.to
] = data
[m
.from
];
233 /* attacking info, 2/2 */
235 replace_attacks(m
.capture
,data
[m
.to
], m
.to
);
237 add_attacks(data
[m
.to
], m
.to
);
238 #endif //TRACK_ATTACKS;
240 /* update material tracking */
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
)
260 hash
^= HASH_KEY( m
.capture
, m
.to
);
262 /* reset fifty moves count */
263 if(m
.capture
|| (PIECE_OF(data
[m
.to
])==PAWN
) )
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 */
279 castle_passing_mask
^= 12^X(m
.to
);
284 uint8_t place
= ROW_OF(m
.from
)+COL_OF(m
.to
);
286 mat_remove( PAWN
|other_color
, place
);
287 del_pawn(other_color
, place
);
289 del_attacks(PAWN
|other_color
, place
);
290 #endif //TRACK_ATTACKS
291 hash
^= HASH_KEY( PAWN
|other_color
, place
);
297 uint8_t p1
= ROW_OF(m
.from
)+5;
298 uint8_t p2
= ROW_OF(m
.from
)+7;
301 mat_move( data
[p1
], p2
, p1
);
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
);
311 case CASTLEQUEENSIDE
:
313 uint8_t p1
= ROW_OF(m
.from
)+3;
314 uint8_t p2
= ROW_OF(m
.from
);
317 mat_move( data
[p1
], p2
, p1
);
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
);
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
);
334 mat_add( data
[m
.to
], m
.to
);
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 */
355 ASSERT(data
[king_pos
[1]] == WK
);
356 ASSERT(data
[king_pos
[0]] == BK
);
357 ASSERT(DISTANCE(king_pos
[0], king_pos
[1]) >= 2);
360 check_mat_tracking();
363 #endif //TRACK_ATTACKS
367 //-------------------------------------------------------------------------------------
368 //-------------------------------------------------------------------------------------
371 Board::undo_move(const Move
& m
)
373 A88 data
= this->data
;
377 check_mat_tracking();
380 #endif //TRACK_ATTACKS
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);
388 /* attacking info, 1/2 */
390 replace_attacks(data
[m
.to
], m
.capture
, m
.to
);
392 del_attacks(data
[m
.to
], m
.to
);
393 #endif //TRACK_ATTACKS
395 data
[m
.from
] = data
[m
.to
];
397 data
[m
.to
] = m
.capture
;
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
);
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 */
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
);
424 add_attacks( PAWN
|color_to_move
, place
);
425 #endif //TRACK_ATTACKS
429 case CASTLEQUEENSIDE
:
431 uint8_t p1
= ROW_OF(m
.from
)+3;
432 uint8_t p2
= ROW_OF(m
.from
);
435 mat_move( data
[p2
], p1
, p2
);
437 del_attacks( data
[p2
], p1
);
438 add_attacks( data
[p2
], p2
);
439 #endif //TRACK_ATTACKS
445 uint8_t p1
= ROW_OF(m
.from
)+5;
446 uint8_t p2
= ROW_OF(m
.from
)+7;
449 mat_move( data
[p2
], p1
, p2
);
451 del_attacks( data
[p2
], p1
);
452 add_attacks( data
[p2
], p2
);
453 #endif //TRACK_ATTACKS
457 case PROMOTE_FIRST
... PROMOTE_LAST
:
459 uint8_t p
= PAWN
|other_color
;
461 replace_attacks( data
[m
.from
], 0, m
.from
);
462 #endif //TRACK_ATTACKS
463 mat_remove( data
[m
.from
], m
.from
);
465 mat_add( data
[m
.from
], m
.from
);
469 if(PIECE_OF(data
[m
.from
])==PAWN
)
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 */
490 ASSERT(data
[king_pos
[1]] == WK
);
491 ASSERT(data
[king_pos
[0]] == BK
);
492 ASSERT(DISTANCE(king_pos
[0], king_pos
[1]) >= 2);
495 check_mat_tracking();
498 #endif //TRACK_ATTACKS