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(SaveBuf
& s
)
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
;
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 */
182 Board::undo_null_move(const SaveBuf
& s
)
186 num_moves
-= IS_WHITE(color_to_move
);
187 SWITCH(color_to_move
, other_color
);
190 castle_passing_mask
= s
.castle_passing_mask
;
192 /* mark that now we do not know anything about pinnings */
201 //do move m and adjust hashkey
203 Board::do_move(const Move
& m
, SaveBuf
& s
)
205 A88 data
= this->data
;
209 check_mat_tracking();
212 #endif //TRACK_ATTACKS
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 */
222 /* save all flags about the position */
223 s
.castle_passing_mask
= castle_passing_mask
;
227 /* attacking info, 1/2 */
228 del_attacks(data
[m
.from
], m
.from
);
229 #endif //TRACK_ATTACKS
231 data
[m
.to
] = data
[m
.from
];
235 /* attacking info, 2/2 */
237 replace_attacks(m
.capture
,data
[m
.to
], m
.to
);
239 add_attacks(data
[m
.to
], m
.to
);
240 #endif //TRACK_ATTACKS;
242 /* update material tracking */
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
)
262 hash
^= HASH_KEY( m
.capture
, m
.to
);
264 /* reset fifty moves count */
265 if(m
.capture
|| (PIECE_OF(data
[m
.to
])==PAWN
) )
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 */
281 castle_passing_mask
^= 12^X(m
.to
);
286 uint8_t place
= ROW_OF(m
.from
)+COL_OF(m
.to
);
288 mat_remove( PAWN
|other_color
, place
);
289 del_pawn(other_color
, place
);
291 del_attacks(PAWN
|other_color
, place
);
292 #endif //TRACK_ATTACKS
293 hash
^= HASH_KEY( PAWN
|other_color
, place
);
299 uint8_t p1
= ROW_OF(m
.from
)+5;
300 uint8_t p2
= ROW_OF(m
.from
)+7;
303 mat_move( data
[p1
], p2
, p1
);
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
);
313 case CASTLEQUEENSIDE
:
315 uint8_t p1
= ROW_OF(m
.from
)+3;
316 uint8_t p2
= ROW_OF(m
.from
);
319 mat_move( data
[p1
], p2
, p1
);
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
);
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
);
336 mat_add( data
[m
.to
], m
.to
);
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 */
357 ASSERT(data
[king_pos
[1]] == WK
);
358 ASSERT(data
[king_pos
[0]] == BK
);
359 ASSERT(DISTANCE(king_pos
[0], king_pos
[1]) >= 2);
362 check_mat_tracking();
365 #endif //TRACK_ATTACKS
369 //-------------------------------------------------------------------------------------
370 //-------------------------------------------------------------------------------------
373 Board::undo_move(const Move
& m
, const SaveBuf
& s
)
375 A88 data
= this->data
;
379 check_mat_tracking();
382 #endif //TRACK_ATTACKS
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);
390 /* attacking info, 1/2 */
392 replace_attacks(data
[m
.to
], m
.capture
, m
.to
);
394 del_attacks(data
[m
.to
], m
.to
);
395 #endif //TRACK_ATTACKS
397 data
[m
.from
] = data
[m
.to
];
399 data
[m
.to
] = m
.capture
;
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
);
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 */
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
);
426 add_attacks( PAWN
|color_to_move
, place
);
427 #endif //TRACK_ATTACKS
431 case CASTLEQUEENSIDE
:
433 uint8_t p1
= ROW_OF(m
.from
)+3;
434 uint8_t p2
= ROW_OF(m
.from
);
437 mat_move( data
[p2
], p1
, p2
);
439 del_attacks( data
[p2
], p1
);
440 add_attacks( data
[p2
], p2
);
441 #endif //TRACK_ATTACKS
447 uint8_t p1
= ROW_OF(m
.from
)+5;
448 uint8_t p2
= ROW_OF(m
.from
)+7;
451 mat_move( data
[p2
], p1
, p2
);
453 del_attacks( data
[p2
], p1
);
454 add_attacks( data
[p2
], p2
);
455 #endif //TRACK_ATTACKS
459 case PROMOTE_FIRST
... PROMOTE_LAST
:
461 uint8_t p
= PAWN
|other_color
;
463 replace_attacks( data
[m
.from
], 0, m
.from
);
464 #endif //TRACK_ATTACKS
465 mat_remove( data
[m
.from
], m
.from
);
467 mat_add( data
[m
.from
], m
.from
);
471 if(PIECE_OF(data
[m
.from
])==PAWN
)
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 */
482 castle_passing_mask
= s
.castle_passing_mask
;
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 */
492 ASSERT(data
[king_pos
[1]] == WK
);
493 ASSERT(data
[king_pos
[0]] == BK
);
494 ASSERT(DISTANCE(king_pos
[0], king_pos
[1]) >= 2);
497 check_mat_tracking();
500 #endif //TRACK_ATTACKS