#include "chess.h"
#include "data.h"
/* last modified 02/22/14 */
/*
*******************************************************************************
* *
* MakeMove() is responsible for updating the position database whenever a *
* piece is moved. It performs the following operations: (1) update the *
* board structure itself by moving the piece and removing any captured *
* piece. (2) update the hash keys. (3) update material counts. (4) then *
* update castling status. (5) and finally update number of moves since *
* last reversible move. *
* *
* There are some special-cases handled here, such as en passant captures *
* where the enemy pawn is not on the <target> square, castling which moves *
* both the king and rook, and then rook moves/captures which give up the *
* castling right to that side when the rook is moved. *
* *
* note: side = 1 if white is to move, 0 otherwise. enemy is the opposite *
* and is 1 if it is not white to move, 0 otherwise. *
* *
*******************************************************************************
*/
void MakeMove(TREE * RESTRICT tree, int ply, int move, int side) {
uint64_t bit_move;
int piece, from, to, captured, promote, enemy = Flip(side);
int cpiece;
#if defined(DEBUG)
int i;
#endif
/*
************************************************************
* *
* First, some basic information is updated for all moves *
* before we do the piece-specific stuff. We need to save *
* the current position and both hash signatures, and add *
* the current position to the repetition-list for the *
* side on move, before the move is actually made on the *
* board. We also update the 50 move rule counter which *
* will be reset if a capture or pawn move is made here. *
* *
* If the en passant flag was set the previous ply, we *
* have already used it to generate moves at this ply and *
* we need to clear it before continuing. If it is set, *
* we also need to update the hash signature since the EP *
* opportunity no longer exists after making any move at *
* this ply (one ply deeper than when a pawn was advanced *
* two squares). *
* *
************************************************************
*/
#if defined(DEBUG)
ValidatePosition(tree, ply, move, "MakeMove(1)");
#endif
tree->status[ply + 1] = tree->status[ply];
tree->save_hash_key[ply] = HashKey;
tree->save_pawn_hash_key[ply] = PawnHashKey;
if (EnPassant(ply + 1)) {
HashEP(EnPassant(ply + 1));
EnPassant(ply + 1) = 0;
}
Reversible(ply + 1)++;
/*
************************************************************
* *
* Now do the things that are common to all pieces, such *
* as updating the bitboards and hash signature. *
* *
************************************************************
*/
piece = Piece(move);
from = From(move);
to = To(move);
captured = Captured(move);
promote = Promote(move);
bit_move = SetMask(from) | SetMask(to);
cpiece = PcOnSq(to);
ClearSet(bit_move, Pieces(side, piece));
ClearSet(bit_move, Occupied(side));
Hash(side, piece, from);
Hash(side, piece, to);
PcOnSq(from) = 0;
PcOnSq(to) = pieces[side][piece];
/*
************************************************************
* *
* Now do the piece-specific things by jumping to the *
* appropriate routine. *
* *
************************************************************
*/
switch (piece) {
case pawn:
HashP(side, from);
HashP(side, to);
Reversible(ply + 1) = 0;
if (captured == 1 && !cpiece) {
Clear(to + epsq[side], Pawns(enemy));
Clear(to + epsq[side], Occupied(enemy));
Hash(enemy, pawn, to + epsq[side]);
HashP(enemy, to + epsq[side]);
PcOnSq(to + epsq[side]) = 0;
Material -= PieceValues(enemy, pawn);
TotalPieces(enemy, pawn)--;
TotalAllPieces--;
captured = 0;
}
if (promote) {
TotalPieces(side, pawn)--;
Material -= PieceValues(side, pawn);
Clear(to, Pawns(side));
Hash(side, pawn, to);
HashP(side, to);
Hash(side, promote, to);
PcOnSq(to) = pieces[side][promote];
TotalPieces(side, occupied) += p_vals[promote];
TotalPieces(side, promote)++;
Material += PieceValues(side, promote);
Set(to, Pieces(side, promote));
switch (promote) {
case knight:
case bishop:
TotalMinors(side)++;
break;
case rook:
TotalMajors(side)++;
break;
case queen:
TotalMajors(side) += 2;
break;
}
} else if ((Abs(to - from) == 16) && (mask_eptest[to] & Pawns(enemy))) {
EnPassant(ply + 1) = to + epsq[side];
HashEP(to + epsq[side]);
}
break;
case knight:
case bishop:
case queen:
break;
case rook:
if (Castle(ply + 1, side) > 0) {
if ((from == rook_A[side]) && (Castle(ply + 1, side) & 2)) {
Castle(ply + 1, side) &= 1;
HashCastle(1, side);
} else if ((from == rook_H[side]) && (Castle(ply + 1, side) & 1)) {
Castle(ply + 1, side) &= 2;
HashCastle(0, side);
}
}
break;
case king:
KingSQ(side) = to;
if (Castle(ply + 1, side) > 0) {
if (Castle(ply + 1, side) & 2)
HashCastle(1, side);
if (Castle(ply + 1, side) & 1)
HashCastle(0, side);
if (Abs(to - from) == 2) {
Castle(ply + 1, side) = -1;
piece = rook;
if (to == rook_G[side]) {
from = rook_H[side];
to = rook_F[side];
} else {
from = rook_A[side];
to = rook_D[side];
}
bit_move = SetMask(from) | SetMask(to);
ClearSet(bit_move, Rooks(side));
ClearSet(bit_move, Occupied(side));
Hash(side, rook, from);
Hash(side, rook, to);
PcOnSq(from) = 0;
PcOnSq(to) = pieces[side][rook];
} else
Castle(ply + 1, side) = 0;
}
break;
}
/*
************************************************************
* *
* If this is a capture move, we also have to update the *
* information that must change when a piece is removed *
* from the board. *
* *
************************************************************
*/
if (captured) {
Reversible(ply + 1) = 0;
TotalAllPieces--;
if (promote)
piece = promote;
Hash(enemy, captured, to);
Clear(to, Pieces(enemy, captured));
Clear(to, Occupied(enemy));
Material -= PieceValues(enemy, captured);
TotalPieces(enemy, captured)--;
if (captured != pawn)
TotalPieces(enemy, occupied) -= p_vals[captured];
switch (captured) {
case pawn:
HashP(enemy, to);
break;
case knight:
case bishop:
TotalMinors(enemy)--;
break;
case rook:
if (Castle(ply + 1, enemy) > 0) {
if ((to == rook_A[enemy]) && (Castle(ply + 1, enemy) & 2)) {
Castle(ply + 1, enemy) &= 1;
HashCastle(1, enemy);
} else if ((to == rook_H[enemy]) && (Castle(ply + 1, enemy) & 1)) {
Castle(ply + 1, enemy) &= 2;
HashCastle(0, enemy);
}
}
TotalMajors(enemy)--;
break;
case queen:
TotalMajors(enemy) -= 2;
break;
case king:
#if defined(DEBUG)
Print(128, "captured a king (Make)\n");
for (i = 1; i <= ply; i++)
Print(128, "ply=%2d, piece=%2d,from=%2d,to=%2d,captured=%2d\n", i,
Piece(tree->curmv[i]), From(tree->curmv[i]), To(tree->curmv[i]),
Captured(tree->curmv[i]));
Print(128, "ply=%2d, piece=%2d,from=%2d,to=%2d,captured=%2d\n", i,
piece, from, to, captured);
if (log_file)
DisplayChessBoard(log_file, tree->position);
#endif
break;
}
}
#if defined(DEBUG)
ValidatePosition(tree, ply + 1, move, "MakeMove(2)");
#endif
return;
}
/* last modified 05/08/14 */
/*
*******************************************************************************
* *
* MakeMoveRoot() is used to make a move at the root of the game tree, *
* before any searching is done. It uses MakeMove() to execute the move, *
* but then copies the resulting position back to position[0], the actual *
* board position. It handles the special-case of the draw-by-repetition *
* rule by clearing the repetition list when a non-reversible move is made, *
* since no repetitions are possible once such a move is played. *
* *
*******************************************************************************
*/
void MakeMoveRoot(TREE * RESTRICT tree, int move, int side) {
int player;
/*
************************************************************
* *
* First, make the move and then reset the repetition *
* index if the 50 move rule counter was reset to zero. *
* *
************************************************************
*/
MakeMove(tree, 0, move, side);
if (Reversible(1) == 0)
tree->rep_index = -1;
tree->rep_list[++(tree->rep_index)] = HashKey;
/*
************************************************************
* *
* One odd action is to note if the castle status is *
* currently negative, which indicates that that side *
* castled during the previous search. We simply set the *
* castle status for that side to zero and we are done. *
* *
* We then copy this back to ply=0 status (which is the *
* permanent game-board ply). *
* *
************************************************************
*/
for (player = black; player <= white; player++)
Castle(1, player) = Max(0, Castle(1, player));
tree->status[0] = tree->status[1];
}