1 #include "chess.h"
2 #include "data.h"
3 /* last modified 01/06/16 */
4 /*
5  *******************************************************************************
6  *                                                                             *
7  *   MakeMove() is responsible for updating the position database whenever a   *
8  *   piece is moved.  It performs the following operations:  (1) update the    *
9  *   board structure itself by moving the piece and removing any captured      *
10  *   piece.  (2) update the hash keys.  (3) update material counts.  (4) then  *
11  *   update castling status.  (5) and finally update number of moves since     *
12  *   last reversible move.                                                     *
13  *                                                                             *
14  *   There are some special-cases handled here, such as en passant captures    *
15  *   where the enemy pawn is not on the <target> square, castling which moves  *
16  *   both the king and rook, and then rook moves/captures which give up the    *
17  *   castling right to that side when the rook is moved.                       *
18  *                                                                             *
19  *   note:  side = 1 if white is to move, 0 otherwise.  enemy is the opposite  *
20  *   and is 1 if it is not white to move, 0 otherwise.                         *
21  *                                                                             *
22  *******************************************************************************
23  */
MakeMove(TREE * RESTRICT tree,int ply,int side,int move)24 void MakeMove(TREE * RESTRICT tree, int ply, int side, int move) {
25   uint64_t bit_move;
26   int piece, from, to, captured, promote, enemy = Flip(side), cpiece;
27 #if defined(DEBUG)
28   int i;
29 #endif
30 
31 /*
32  ************************************************************
33  *                                                          *
34  *  First, some basic information is updated for all moves  *
35  *  before we do the piece-specific stuff.  We need to save *
36  *  the current position and both hash signatures, and add  *
37  *  the current position to the repetition-list for the     *
38  *  side on move, before the move is actually made on the   *
39  *  board.  We also update the 50 move rule counter which   *
40  *  will be reset if a capture or pawn move is made here.   *
41  *                                                          *
42  *  If the en passant flag was set the previous ply, we     *
43  *  have already used it to generate moves at this ply and  *
44  *  we need to clear it before continuing.  If it is set,   *
45  *  we also need to update the hash signature since the EP  *
46  *  opportunity no longer exists after making any move at   *
47  *  this ply (one ply deeper than when a pawn was advanced  *
48  *  two squares).                                           *
49  *                                                          *
50  ************************************************************
51  */
52 #if defined(DEBUG)
53   ValidatePosition(tree, ply, move, "MakeMove(1)");
54 #endif
55   tree->status[ply + 1] = tree->status[ply];
56   tree->save_hash_key[ply] = HashKey;
57   tree->save_pawn_hash_key[ply] = PawnHashKey;
58   if (EnPassant(ply + 1)) {
59     HashEP(EnPassant(ply + 1));
60     EnPassant(ply + 1) = 0;
61   }
62   Reversible(ply + 1)++;
63 /*
64  ************************************************************
65  *                                                          *
66  *  Now do the things that are common to all pieces, such   *
67  *  as updating the bitboards and hash signature.           *
68  *                                                          *
69  ************************************************************
70  */
71   piece = Piece(move);
72   from = From(move);
73   to = To(move);
74   captured = Captured(move);
75   promote = Promote(move);
76   bit_move = SetMask(from) | SetMask(to);
77   cpiece = PcOnSq(to);
78   ClearSet(bit_move, Pieces(side, piece));
79   ClearSet(bit_move, Occupied(side));
80   Hash(side, piece, from);
81   Hash(side, piece, to);
82   PcOnSq(from) = 0;
83   PcOnSq(to) = pieces[side][piece];
84 /*
85  ************************************************************
86  *                                                          *
87  *  Now do the piece-specific things by jumping to the      *
88  *  appropriate routine.                                    *
89  *                                                          *
90  ************************************************************
91  */
92   switch (piece) {
93     case pawn:
94       HashP(side, from);
95       HashP(side, to);
96       Reversible(ply + 1) = 0;
97       if (captured == 1 && !cpiece) {
98         Clear(to + epsq[side], Pawns(enemy));
99         Clear(to + epsq[side], Occupied(enemy));
100         Hash(enemy, pawn, to + epsq[side]);
101         HashP(enemy, to + epsq[side]);
102         PcOnSq(to + epsq[side]) = 0;
103         Material -= PieceValues(enemy, pawn);
104         TotalPieces(enemy, pawn)--;
105         TotalAllPieces--;
106         captured = 0;
107       }
108       if (promote) {
109         TotalPieces(side, pawn)--;
110         Material -= PieceValues(side, pawn);
111         Clear(to, Pawns(side));
112         Hash(side, pawn, to);
113         HashP(side, to);
114         Hash(side, promote, to);
115         PcOnSq(to) = pieces[side][promote];
116         TotalPieces(side, occupied) += p_vals[promote];
117         TotalPieces(side, promote)++;
118         Material += PieceValues(side, promote);
119         Set(to, Pieces(side, promote));
120       } else if ((Abs(to - from) == 16) && (mask_eptest[to] & Pawns(enemy))) {
121         EnPassant(ply + 1) = to + epsq[side];
122         HashEP(to + epsq[side]);
123       }
124       break;
125     case knight:
126     case bishop:
127     case queen:
128       break;
129     case rook:
130       if (Castle(ply + 1, side) > 0) {
131         if ((from == rook_A[side]) && (Castle(ply + 1, side) & 2)) {
132           Castle(ply + 1, side) &= 1;
133           HashCastle(1, side);
134         } else if ((from == rook_H[side]) && (Castle(ply + 1, side) & 1)) {
135           Castle(ply + 1, side) &= 2;
136           HashCastle(0, side);
137         }
138       }
139       break;
140     case king:
141       KingSQ(side) = to;
142       if (Castle(ply + 1, side) > 0) {
143         if (Castle(ply + 1, side) & 2)
144           HashCastle(1, side);
145         if (Castle(ply + 1, side) & 1)
146           HashCastle(0, side);
147         if (Abs(to - from) == 2) {
148           Castle(ply + 1, side) = -1;
149           piece = rook;
150           if (to == rook_G[side]) {
151             from = rook_H[side];
152             to = rook_F[side];
153           } else {
154             from = rook_A[side];
155             to = rook_D[side];
156           }
157           bit_move = SetMask(from) | SetMask(to);
158           ClearSet(bit_move, Rooks(side));
159           ClearSet(bit_move, Occupied(side));
160           Hash(side, rook, from);
161           Hash(side, rook, to);
162           PcOnSq(from) = 0;
163           PcOnSq(to) = pieces[side][rook];
164         } else
165           Castle(ply + 1, side) = 0;
166       }
167       break;
168   }
169 /*
170  ************************************************************
171  *                                                          *
172  *  If this is a capture move, we also have to update the   *
173  *  information that must change when a piece is removed    *
174  *  from the board.                                         *
175  *                                                          *
176  ************************************************************
177  */
178   if (captured) {
179     Reversible(ply + 1) = 0;
180     TotalAllPieces--;
181     if (promote)
182       piece = promote;
183     Hash(enemy, captured, to);
184     Clear(to, Pieces(enemy, captured));
185     Clear(to, Occupied(enemy));
186     Material -= PieceValues(enemy, captured);
187     TotalPieces(enemy, captured)--;
188     if (captured != pawn)
189       TotalPieces(enemy, occupied) -= p_vals[captured];
190     switch (captured) {
191       case pawn:
192         HashP(enemy, to);
193         break;
194       case knight:
195       case bishop:
196       case queen:
197         break;
198       case rook:
199         if (Castle(ply + 1, enemy) > 0) {
200           if ((to == rook_A[enemy]) && (Castle(ply + 1, enemy) & 2)) {
201             Castle(ply + 1, enemy) &= 1;
202             HashCastle(1, enemy);
203           } else if ((to == rook_H[enemy]) && (Castle(ply + 1, enemy) & 1)) {
204             Castle(ply + 1, enemy) &= 2;
205             HashCastle(0, enemy);
206           }
207         }
208         break;
209       case king:
210 #if defined(DEBUG)
211         Print(2048, "captured a king (Make)\n");
212         for (i = 1; i <= ply; i++)
213           Print(2048,
214               "ply=%2d, phase=%d, piece=%2d,from=%2d,to=%2d,captured=%2d\n",
215               i, tree->phase[i], Piece(tree->curmv[i]), From(tree->curmv[i]),
216               To(tree->curmv[i]), Captured(tree->curmv[i]));
217         Print(2048, "ply=%2d, piece=%2d,from=%2d,to=%2d,captured=%2d\n", i,
218             piece, from, to, captured);
219         if (log_file)
220           DisplayChessBoard(log_file, tree->position);
221 #endif
222         break;
223     }
224   }
225 #if defined(DEBUG)
226   ValidatePosition(tree, ply + 1, move, "MakeMove(2)");
227 #endif
228   return;
229 }
230 
231 /* last modified 01/06/16 */
232 /*
233  *******************************************************************************
234  *                                                                             *
235  *   MakeMoveRoot() is used to make a move at the root of the game tree,       *
236  *   before any searching is done.  It uses MakeMove() to execute the move,    *
237  *   but then copies the resulting position back to position[0], the actual    *
238  *   board position.  It handles the special-case of the draw-by-repetition    *
239  *   rule by clearing the repetition list when a non-reversible move is made,  *
240  *   since no repetitions are possible once such a move is played.             *
241  *                                                                             *
242  *******************************************************************************
243  */
MakeMoveRoot(TREE * RESTRICT tree,int side,int move)244 void MakeMoveRoot(TREE * RESTRICT tree, int side, int move) {
245   int player;
246 
247 /*
248  ************************************************************
249  *                                                          *
250  *  First, make the move and then reset the repetition      *
251  *  index if the 50 move rule counter was reset to zero.    *
252  *                                                          *
253  ************************************************************
254  */
255   MakeMove(tree, 0, side, move);
256   if (Reversible(1) == 0)
257     rep_index = -1;
258   tree->rep_list[++rep_index] = HashKey;
259 /*
260  ************************************************************
261  *                                                          *
262  *  One odd action is to note if the castle status is       *
263  *  currently negative, which indicates that that side      *
264  *  castled during the previous search.  We simply set the  *
265  *  castle status for that side to zero and we are done.    *
266  *                                                          *
267  *  We then copy this back to ply=0 status (which is the    *
268  *  permanent game-board ply).                              *
269  *                                                          *
270  ************************************************************
271  */
272   for (player = black; player <= white; player++)
273     Castle(1, player) = Max(0, Castle(1, player));
274   tree->status[0] = tree->status[1];
275 }
276