1º U64 hash2 = hash; // I create a variable to differentiate the value of the current hash key. I also use a couple of variables to store the current empassant and castling.
2º We have to make an xor each time a piece appears or disappears from a square
If there is a castling we have to consider that besides the king we also have to move the rook.
Ej:
/* move rook on castle */
hash2 ^= hash_piece[color[from]][ROOK][from];
color[to] = color[from];
piece[to] = piece[from];
color[from] = EMPTY;
piece[from] = EMPTY;
hash2 ^= hash_piece[color[to]][ROOK][to];
/* remove the piece from the original square */
hash2 ^= hash_piece[side][piece[(int)m.from]][(int)m.from];
/* if there is a capture we have to remove the captured piece/
hash2 ^= hash_piece[side-1][hist_dat[hply].capture][(int)m.to];
/* erase the pawn if this is an en passant move */
if (side == LIGHT) hash2 ^= hash_piece[DARK][PAWN][m.to + 8];
if (side == DARK) hash2 ^= hash_piece[LIGHT][PAWN][m.to - 8];
In the case of promotion, there is no need to do anything since a piece simply disappears from one square and another one appears on another square.
/* put piece "from original" square on "to square" */
hash2 ^= hash_piece[side][piece[(int)m.to]][(int)m.to];
3º we change side and update the hash key
/* switch side */
hash2 ^= hash_side[side];
side ^= 1;
/* put new side */
hash2 ^= hash_side[side];
4º we update empassant and castling if they have been modified
if (old_ep != -1)
hash2 ^= hash_ep[old_ep];
if (ep != -1)
hash2 ^= hash_ep[ep];
if (old_castle != castle) {
hash2 ^= hash_castle[old_castle];
hash2 ^= hash_castle[castle];
}
5º You can now optionally calculate the hash key from zero and compare with this hash2
Here you have if you want a sample in the TSCP makemove function, in this case the hash key, number of pieces and position of the kings are modified incrementally.
Code: Select all
/* makemove() makes a move. If the move is illegal, it
undoes whatever it did and returns FALSE. Otherwise, it
returns TRUE. */
int makemove(move_bytes m)
{
int from = 0, to = 0, old_castle, old_ep;
U64 hash2 = hash;
/* test to see if a castle move is legal and move rook
(the king is moved with the usual move code later) */
if (m.bits & 2) {
if (in_check(side))
return FALSE;
switch (m.to) {
case 62:
if (color[F1] != EMPTY || color[G1] != EMPTY ||
attack(F1, xside) || attack(G1, xside))
return FALSE;
from = H1;
to = F1;
break;
case 58:
if (color[B1] != EMPTY || color[C1] != EMPTY || color[D1] != EMPTY ||
attack(C1, xside) || attack(D1, xside))
return FALSE;
from = A1;
to = D1;
break;
case 6:
if (color[F8] != EMPTY || color[G8] != EMPTY ||
attack(F8, xside) || attack(G8, xside))
return FALSE;
from = H8;
to = F8;
break;
case 2:
if (color[B8] != EMPTY || color[C8] != EMPTY || color[D8] != EMPTY ||
attack(C8, xside) || attack(D8, xside))
return FALSE;
from = A8;
to = D8;
break;
default: /* shouldn't get here */
from = -1;
to = -1;
break;
}
/* move rook on castle */
hash2 ^= hash_piece[color[from]][ROOK][from];
color[to] = color[from];
piece[to] = piece[from];
color[from] = EMPTY;
piece[from] = EMPTY;
hash2 ^= hash_piece[color[to]][ROOK][to];
}
/* back up information so we can take the move back later. */
hist_dat[hply].m.b = m;
hist_dat[hply].capture = piece[(int)m.to];
hist_dat[hply].castle = old_castle = castle;
hist_dat[hply].ep = old_ep = ep;
hist_dat[hply].fifty = fifty;
hist_dat[hply].hash = hash;
/* remove the piece */
hash2 ^= hash_piece[side][piece[(int)m.from]][(int)m.from];
piece[(int)m.to] = piece[(int)m.from];
piece[(int)m.from] = EMPTY;
color[(int)m.to] = color[(int)m.from];
color[(int)m.from] = EMPTY;
/* update the castle, en passant, and fifty-move-draw variables */
castle &= castle_mask[(int)m.from] & castle_mask[(int)m.to];
if (m.bits & 8) {
if (side == LIGHT)
ep = m.to + 8;
else
ep = m.to - 8;
}
else
ep = -1;
if (m.bits & 17)
fifty = 0;
else
++fifty;
/* update positions of the kings, hash and number of pieces in captures */
if (side == DARK) {
if (piece[(int)m.to] == KING)
bk = (int)m.to;
if (hist_dat[hply].capture != EMPTY) {
hash2 ^= hash_piece[LIGHT][hist_dat[hply].capture][(int)m.to];
switch(hist_dat[hply].capture) {
case PAWN:
wp--;
break;
case KNIGHT:
wn--;
break;
case BISHOP:
wb--;
break;
case ROOK:
wr--;
break;
case QUEEN:
wq--;
break;
}
}
}
else if (side == LIGHT) {
if (piece[(int)m.to] == KING)
wk = (int)m.to;
if (hist_dat[hply].capture != EMPTY) {
hash2 ^= hash_piece[DARK][hist_dat[hply].capture][(int)m.to];
switch(hist_dat[hply].capture) {
case PAWN:
bp--;
break;
case KNIGHT:
bn--;
break;
case BISHOP:
bb--;
break;
case ROOK:
br--;
break;
case QUEEN:
bq--;
break;
}
}
}
/* erase the pawn if this is an en passant move */
if (m.bits & 4) {
if (side == LIGHT) {
color[m.to + 8] = EMPTY;
piece[m.to + 8] = EMPTY;
bp--;
hash2 ^= hash_piece[DARK][PAWN][m.to + 8];
}
else {
color[m.to - 8] = EMPTY;
piece[m.to - 8] = EMPTY;
wp--;
hash2 ^= hash_piece[LIGHT][PAWN][m.to - 8];
}
}
/* promote */
if (m.bits & 32) {
piece[(int)m.to] = m.promote;
switch (m.promote) {
case QUEEN:
if (side == LIGHT) {
wp--;
wq++;
}
else {
bp--;
bq++;
}
break;
case ROOK:
if (side == LIGHT) {
wp--;
wr++;
}
else {
bp--;
br++;
}
break;
case BISHOP:
if (side == LIGHT) {
wp--;
wb++;
}
else {
bp--;
bb++;
}
break;
case KNIGHT:
if (side == LIGHT) {
wp--;
wn++;
}
else {
bp--;
bn++;
}
break;
}
}
/* put piece */
hash2 ^= hash_piece[side][piece[(int)m.to]][(int)m.to];
/* switch sides and test for legality (if we can capture
the other guy's king, it's an illegal position and
we need to take the move back) */
hash2 ^= hash_side[side];
side ^= 1;
xside ^= 1;
++ply;
++hply;
if (in_check(xside)) {
takeback();
return FALSE;
}
hash2 ^= hash_side[side];
if (old_ep != -1)
hash2 ^= hash_ep[old_ep];
if (ep != -1)
hash2 ^= hash_ep[ep];
if (old_castle != castle) {
hash2 ^= hash_castle[old_castle];
hash2 ^= hash_castle[castle];
}
/* set_hash();
assert(hash == hash2); */
hash = hash2;
return TRUE;
}