-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmake.c
275 lines (272 loc) · 10.8 KB
/
make.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
#include "chess.h"
#include "data.h"
/* last modified 01/06/16 */
/*
*******************************************************************************
* *
* 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 side, int move) {
uint64_t bit_move;
int piece, from, to, captured, promote, enemy = Flip(side), 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));
} 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:
case queen:
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);
}
}
break;
case king:
#if defined(DEBUG)
Print(2048, "captured a king (Make)\n");
for (i = 1; i <= ply; i++)
Print(2048,
"ply=%2d, phase=%d, piece=%2d,from=%2d,to=%2d,captured=%2d\n",
i, tree->phase[i], Piece(tree->curmv[i]), From(tree->curmv[i]),
To(tree->curmv[i]), Captured(tree->curmv[i]));
Print(2048, "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 01/06/16 */
/*
*******************************************************************************
* *
* 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 side, int move) {
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, side, move);
if (Reversible(1) == 0)
rep_index = -1;
tree->rep_list[++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];
}