Rev 33 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
33 | pmbaty | 1 | #include "chess.h" |
2 | #include "data.h" |
||
108 | pmbaty | 3 | /* last modified 01/06/16 */ |
33 | pmbaty | 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 | */ |
||
108 | pmbaty | 24 | void MakeMove(TREE * RESTRICT tree, int ply, int side, int move) { |
33 | pmbaty | 25 | uint64_t bit_move; |
108 | pmbaty | 26 | int piece, from, to, captured, promote, enemy = Flip(side), cpiece; |
33 | pmbaty | 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: |
||
108 | pmbaty | 196 | case queen: |
33 | pmbaty | 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) |
||
108 | pmbaty | 211 | Print(2048, "captured a king (Make)\n"); |
33 | pmbaty | 212 | for (i = 1; i <= ply; i++) |
108 | pmbaty | 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, |
||
33 | pmbaty | 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 | |||
108 | pmbaty | 231 | /* last modified 01/06/16 */ |
33 | pmbaty | 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 | */ |
||
108 | pmbaty | 244 | void MakeMoveRoot(TREE * RESTRICT tree, int side, int move) { |
33 | pmbaty | 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 | */ |
||
108 | pmbaty | 255 | MakeMove(tree, 0, side, move); |
33 | pmbaty | 256 | if (Reversible(1) == 0) |
108 | pmbaty | 257 | rep_index = -1; |
258 | tree->rep_list[++rep_index] = HashKey; |
||
33 | pmbaty | 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 | } |