Skip to content

Commit

Permalink
Rewrite do_castle_move()
Browse files Browse the repository at this point in the history
And handle the castle directly in do/undo_move().
This allow to greatly simplify the code.

Here the beast is the nasty Chess960 that is
really tricky to get it right because could be
that 'from' and 'to' squares are the same or
that king's 'to' square is rook's 'from' square.

Anyhow should work: verified on all Chess960
starting positions.

No functional and no speed change also in Chess960.
  • Loading branch information
mcostalba committed Jan 28, 2013
1 parent 2218a58 commit 483c98a
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 114 deletions.
183 changes: 71 additions & 112 deletions src/position.cpp
Expand Up @@ -740,13 +740,6 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
st->rule50++;
st->pliesFromNull++;

if (type_of(m) == CASTLE)
{
st->key = k;
do_castle_move<true>(m);
return;
}

Color us = sideToMove;
Color them = ~us;
Square from = from_sq(m);
Expand All @@ -756,9 +749,25 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
PieceType capture = type_of(m) == ENPASSANT ? PAWN : type_of(piece_on(to));

assert(color_of(piece) == us);
assert(piece_on(to) == NO_PIECE || color_of(piece_on(to)) == them);
assert(piece_on(to) == NO_PIECE || color_of(piece_on(to)) == them || type_of(m) == CASTLE);
assert(capture != KING);

if (type_of(m) == CASTLE)
{
assert(piece == make_piece(us, KING));

bool kingSide = to > from;
Square rfrom = to; // Castle is encoded as "king captures friendly rook"
Square rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
capture = NO_PIECE_TYPE;

do_castle(from, to, rfrom, rto);

st->psqScore += psq_delta(make_piece(us, ROOK), rfrom, rto);
k ^= Zobrist::psq[us][ROOK][rfrom] ^ Zobrist::psq[us][ROOK][rto];
}

if (capture)
{
Square capsq = to;
Expand Down Expand Up @@ -835,19 +844,22 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
// Prefetch TT access as soon as we know the new hash key
prefetch((char*)TT.first_entry(k));

// Move the piece
Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to];
byTypeBB[ALL_PIECES] ^= from_to_bb;
byTypeBB[pt] ^= from_to_bb;
byColorBB[us] ^= from_to_bb;

board[to] = board[from];
board[from] = NO_PIECE;

// Update piece lists, index[from] is not updated and becomes stale. This
// works as long as index[] is accessed just by known occupied squares.
index[to] = index[from];
pieceList[us][pt][index[to]] = to;
// Move the piece. The tricky Chess960 castle is handled earlier
if (type_of(m) != CASTLE)
{
Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to];
byTypeBB[ALL_PIECES] ^= from_to_bb;
byTypeBB[pt] ^= from_to_bb;
byColorBB[us] ^= from_to_bb;

board[from] = NO_PIECE;
board[to] = piece;

// Update piece lists, index[from] is not updated and becomes stale. This
// works as long as index[] is accessed just by known occupied squares.
index[to] = index[from];
pieceList[us][pt][index[to]] = to;
}

// If the moving piece is a pawn do some special extra work
if (pt == PAWN)
Expand Down Expand Up @@ -952,19 +964,14 @@ void Position::undo_move(Move m) {

sideToMove = ~sideToMove;

if (type_of(m) == CASTLE)
return do_castle_move<false>(m);

Color us = sideToMove;
Color them = ~us;
Square from = from_sq(m);
Square to = to_sq(m);
Piece piece = piece_on(to);
PieceType pt = type_of(piece);
PieceType pt = type_of(piece_on(to));
PieceType capture = st->capturedType;

assert(is_empty(from));
assert(color_of(piece) == us);
assert(is_empty(from) || type_of(m) == CASTLE);
assert(capture != KING);

if (type_of(m) == PROMOTION)
Expand Down Expand Up @@ -992,19 +999,32 @@ void Position::undo_move(Move m) {
pt = PAWN;
}

// Put the piece back at the source square
Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to];
byTypeBB[ALL_PIECES] ^= from_to_bb;
byTypeBB[pt] ^= from_to_bb;
byColorBB[us] ^= from_to_bb;

board[from] = board[to];
board[to] = NO_PIECE;

// Update piece lists, index[to] is not updated and becomes stale. This
// works as long as index[] is accessed just by known occupied squares.
index[from] = index[to];
pieceList[us][pt][index[from]] = from;
if (type_of(m) == CASTLE)
{
bool kingSide = to > from;
Square rfrom = to; // Castle is encoded as "king captures friendly rook"
Square rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
capture = NO_PIECE_TYPE;
pt = KING;
do_castle(to, from, rto, rfrom);
}
else
{
// Put the piece back at the source square
Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to];
byTypeBB[ALL_PIECES] ^= from_to_bb;
byTypeBB[pt] ^= from_to_bb;
byColorBB[us] ^= from_to_bb;

board[to] = NO_PIECE;
board[from] = make_piece(us, pt);

// Update piece lists, index[to] is not updated and becomes stale. This
// works as long as index[] is accessed just by known occupied squares.
index[from] = index[to];
pieceList[us][pt][index[from]] = from;
}

if (capture)
{
Expand Down Expand Up @@ -1039,91 +1059,30 @@ void Position::undo_move(Move m) {
}


/// Position::do_castle_move() is a private method used to do/undo a castling
/// move. Note that castling moves are encoded as "king captures friendly rook"
/// moves, for instance white short castling in a non-Chess960 game is encoded
/// as e1h1.
template<bool Do>
void Position::do_castle_move(Move m) {
/// Position::do_castle() is a helper used to do/undo a castling move. This
/// is a bit tricky, especially in Chess960.

assert(is_ok(m));
assert(type_of(m) == CASTLE);
void Position::do_castle(Square kfrom, Square kto, Square rfrom, Square rto) {

Color us = sideToMove;
Square kfrom, kto, rfrom, rto;

bool kingSide = to_sq(m) > from_sq(m);
kfrom = kto = from_sq(m);
rfrom = rto = to_sq(m);

if (Do)
{
kto = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
}
else
{
kfrom = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
rfrom = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
}

assert(piece_on(kfrom) == make_piece(us, KING));
assert(piece_on(rfrom) == make_piece(us, ROOK));

// Move the pieces, with some care; in chess960 could be kto == rfrom
Bitboard k_from_to_bb = SquareBB[kfrom] ^ SquareBB[kto];
Bitboard r_from_to_bb = SquareBB[rfrom] ^ SquareBB[rto];
byTypeBB[KING] ^= k_from_to_bb;
byTypeBB[ROOK] ^= r_from_to_bb;
byTypeBB[ALL_PIECES] ^= k_from_to_bb ^ r_from_to_bb;
byColorBB[us] ^= k_from_to_bb ^ r_from_to_bb;

// Update board
// Could be from == to, so first set NO_PIECE then KING and ROOK
board[kfrom] = board[rfrom] = NO_PIECE;
board[kto] = make_piece(us, KING);
board[rto] = make_piece(us, ROOK);

// Update piece lists
pieceList[us][KING][index[kfrom]] = kto;
pieceList[us][ROOK][index[rfrom]] = rto;
int tmp = index[rfrom]; // In Chess960 could be kto == rfrom
index[kto] = index[kfrom];
index[rto] = tmp;

if (Do)
{
// Reset capture field
st->capturedType = NO_PIECE_TYPE;

// Update incremental scores
st->psqScore += psq_delta(make_piece(us, KING), kfrom, kto);
st->psqScore += psq_delta(make_piece(us, ROOK), rfrom, rto);

// Update hash key
st->key ^= Zobrist::psq[us][KING][kfrom] ^ Zobrist::psq[us][KING][kto];
st->key ^= Zobrist::psq[us][ROOK][rfrom] ^ Zobrist::psq[us][ROOK][rto];

// Clear en passant square
if (st->epSquare != SQ_NONE)
{
st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
st->epSquare = SQ_NONE;
}

// Update castling rights
st->key ^= Zobrist::castle[st->castleRights & castleRightsMask[kfrom]];
st->castleRights &= ~castleRightsMask[kfrom];

// Update checkers BB
st->checkersBB = attackers_to(king_square(~us)) & pieces(us);

sideToMove = ~sideToMove;
}
else
// Undo: point our state pointer back to the previous state
st = st->previous;

assert(pos_is_ok());
// Could be kfrom == rto, so use a 'tmp' variable
int tmp = index[kfrom];
index[rto] = index[rfrom];
index[kto] = tmp;
pieceList[us][KING][index[kto]] = kto;
pieceList[us][ROOK][index[rto]] = rto;
}


Expand Down
4 changes: 2 additions & 2 deletions src/position.h
Expand Up @@ -191,8 +191,8 @@ class Position {
void put_piece(Piece p, Square s);
void set_castle_right(Color c, Square rfrom);

// Helper template functions
template<bool Do> void do_castle_move(Move m);
// Helper functions
void do_castle(Square kfrom, Square kto, Square rfrom, Square rto);
template<bool FindPinned> Bitboard hidden_checkers() const;

// Computing hash keys from scratch (for initialization and debugging)
Expand Down

0 comments on commit 483c98a

Please sign in to comment.