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