1 
2 // move_do.c
3 
4 // includes
5 
6 #include <stdlib.h>
7 
8 #include "board.h"
9 #include "colour.h"
10 #include "hash.h"
11 #include "move.h"
12 #include "move_do.h"
13 #include "move_legal.h"
14 #include "piece.h"
15 #include "random.h"
16 #include "util.h"
17 
18 // prototypes
19 
20 static void square_clear (board_t * board, int square, int piece);
21 static void square_set   (board_t * board, int square, int piece, int pos);
22 static void square_move  (board_t * board, int from, int to, int piece);
23 
24 // functions
25 
26 // move_do()
27 
move_do(board_t * board,int move)28 void move_do(board_t * board, int move) {
29 
30    int me, opp;
31    int from, to;
32    int piece, pos, capture;
33    int old_flags, new_flags;
34    int sq, ep_square;
35    int pawn;
36 
37    ASSERT(board_is_ok(board));
38    ASSERT(move_is_ok(move));
39 
40    ASSERT(move_is_pseudo(move,board));
41 
42    // init
43 
44    me = board->turn;
45    opp = colour_opp(me);
46 
47    from = move_from(move);
48    to = move_to(move);
49 
50    piece = board->square[from];
51    ASSERT(colour_equal(piece,me));
52 
53    pos = board->pos[from];
54    ASSERT(pos>=0);
55 
56    // update turn
57 
58    board->turn = opp;
59    board->key ^= random_64(RandomTurn);
60 
61    // update castling rights
62 
63    old_flags = board_flags(board);
64 
65    if (piece_is_king(piece)) {
66       board->castle[me][SideH] = SquareNone;
67       board->castle[me][SideA] = SquareNone;
68    }
69 
70    if (board->castle[me][SideH] == from) board->castle[me][SideH] = SquareNone;
71    if (board->castle[me][SideA] == from) board->castle[me][SideA] = SquareNone;
72 
73    if (board->castle[opp][SideH] == to) board->castle[opp][SideH] = SquareNone;
74    if (board->castle[opp][SideA] == to) board->castle[opp][SideA] = SquareNone;
75 
76    new_flags = board_flags(board);
77 
78    board->key ^= hash_castle_key(new_flags^old_flags); // HACK
79 
80    // update en-passant square
81 
82    ep_square = sq = board->ep_square;
83    if (sq != SquareNone) {
84       board->key ^= random_64(RandomEnPassant+square_file(sq));
85       board->ep_square = SquareNone;
86    }
87 
88    if (piece_is_pawn(piece) && abs(to-from) == 32) {
89       pawn = piece_make_pawn(opp);
90       if (board->square[to-1] == pawn || board->square[to+1] == pawn) {
91          board->ep_square = sq = (from + to) / 2;
92          board->key ^= random_64(RandomEnPassant+square_file(sq));
93       }
94    }
95 
96    // update ply number (captures are handled later)
97 
98    board->ply_nb++;
99    if (piece_is_pawn(piece)) board->ply_nb = 0; // conversion
100 
101    // update move number
102 
103    if (me == Black) board->move_nb++;
104 
105    // castle
106 
107    if (colour_equal(board->square[to],me)) {
108 
109       int rank;
110       int king_from, king_to;
111       int rook_from, rook_to;
112       int rook;
113 
114       rank = colour_is_white(me) ? Rank1 : Rank8;
115 
116       king_from = from;
117       rook_from = to;
118 
119       if (to > from) { // h side
120          king_to = square_make(FileG,rank);
121          rook_to = square_make(FileF,rank);
122       } else { // a side
123          king_to = square_make(FileC,rank);
124          rook_to = square_make(FileD,rank);
125       }
126 
127       // remove the rook
128 
129       pos = board->pos[rook_from];
130       ASSERT(pos>=0);
131 
132       rook = Rook64 | me; // HACK
133 
134       square_clear(board,rook_from,rook);
135 
136       // move the king
137 
138       square_move(board,king_from,king_to,piece);
139 
140       // put the rook back
141 
142       square_set(board,rook_to,rook,pos);
143 
144       ASSERT(board->key==hash_key(board));
145 
146       return;
147    }
148 
149    // remove the captured piece
150 
151    if (piece_is_pawn(piece) && to == ep_square) {
152 
153       // en-passant capture
154 
155       sq = square_ep_dual(to);
156       capture = board->square[sq];
157       ASSERT(capture==piece_make_pawn(opp));
158 
159       square_clear(board,sq,capture);
160 
161       board->ply_nb = 0; // conversion
162 
163    } else {
164 
165       capture = board->square[to];
166 
167       if (capture != Empty) {
168 
169          // normal capture
170 
171          ASSERT(colour_equal(capture,opp));
172          ASSERT(!piece_is_king(capture));
173 
174          square_clear(board,to,capture);
175 
176          board->ply_nb = 0; // conversion
177       }
178    }
179 
180    // move the piece
181 
182    if (move_is_promote(move)) {
183 
184       // promote
185 
186       square_clear(board,from,piece);
187       piece = move_promote_hack(move) | me; // HACK
188       square_set(board,to,piece,pos);
189 
190    } else {
191 
192       // normal move
193 
194       square_move(board,from,to,piece);
195    }
196 
197    ASSERT(board->key==hash_key(board));
198 }
199 
200 // square_clear()
201 
square_clear(board_t * board,int square,int piece)202 static void square_clear(board_t * board, int square, int piece) {
203 
204    int pos, piece_12, colour;
205    int sq, size;
206 
207    ASSERT(board!=NULL);
208    ASSERT(square_is_ok(square));
209    ASSERT(piece_is_ok(piece));
210 
211    // init
212 
213    pos = board->pos[square];
214    ASSERT(pos>=0);
215 
216    colour = piece_colour(piece);
217    piece_12 = piece_to_12(piece);
218 
219    // square
220 
221    ASSERT(board->square[square]==piece);
222    board->square[square] = Empty;
223 
224    ASSERT(board->pos[square]==pos);
225    board->pos[square] = -1; // not needed
226 
227    // piece list
228 
229    ASSERT(board->list_size[colour]>=2);
230    size = --board->list_size[colour];
231    ASSERT(pos<=size);
232 
233    if (pos != size) {
234 
235       sq = board->list[colour][size];
236       ASSERT(square_is_ok(sq));
237       ASSERT(sq!=square);
238 
239       ASSERT(board->pos[sq]==size);
240       board->pos[sq] = pos;
241 
242       ASSERT(board->list[colour][pos]==square);
243       board->list[colour][pos] = sq;
244    }
245 
246    board->list[colour][size] = SquareNone;
247 
248    // material
249 
250    ASSERT(board->number[piece_12]>=1);
251    board->number[piece_12]--;
252 
253    // hash key
254 
255    board->key ^= random_64(RandomPiece+piece_12*64+square_to_64(square));
256 }
257 
258 // square_set()
259 
square_set(board_t * board,int square,int piece,int pos)260 static void square_set(board_t * board, int square, int piece, int pos) {
261 
262    int piece_12, colour;
263    int sq, size;
264 
265    ASSERT(board!=NULL);
266    ASSERT(square_is_ok(square));
267    ASSERT(piece_is_ok(piece));
268    ASSERT(pos>=0);
269 
270    // init
271 
272    colour = piece_colour(piece);
273    piece_12 = piece_to_12(piece);
274 
275    // square
276 
277    ASSERT(board->square[square]==Empty);
278    board->square[square] = piece;
279 
280    ASSERT(board->pos[square]==-1);
281    board->pos[square] = pos;
282 
283    // piece list
284 
285    size = board->list_size[colour]++;
286    ASSERT(board->list[colour][size]==SquareNone);
287    ASSERT(pos<=size);
288 
289    if (pos != size) {
290 
291       sq = board->list[colour][pos];
292       ASSERT(square_is_ok(sq));
293       ASSERT(sq!=square);
294 
295       ASSERT(board->pos[sq]==pos);
296       board->pos[sq] = size;
297 
298       ASSERT(board->list[colour][size]==SquareNone);
299       board->list[colour][size] = sq;
300    }
301 
302    board->list[colour][pos] = square;
303 
304    // material
305 
306    ASSERT(board->number[piece_12]<=8);
307    board->number[piece_12]++;
308 
309    // hash key
310 
311    board->key ^= random_64(RandomPiece+piece_12*64+square_to_64(square));
312 }
313 
314 // square_move()
315 
square_move(board_t * board,int from,int to,int piece)316 static void square_move(board_t * board, int from, int to, int piece) {
317 
318    int colour, pos;
319    int piece_index;
320 
321    ASSERT(board!=NULL);
322    ASSERT(square_is_ok(from));
323    ASSERT(square_is_ok(to));
324    ASSERT(piece_is_ok(piece));
325 
326    // init
327 
328    colour = piece_colour(piece);
329 
330    pos = board->pos[from];
331    ASSERT(pos>=0);
332 
333    // from
334 
335    ASSERT(board->square[from]==piece);
336    board->square[from] = Empty;
337 
338    ASSERT(board->pos[from]==pos);
339    board->pos[from] = -1; // not needed
340 
341    // to
342 
343    ASSERT(board->square[to]==Empty);
344    board->square[to] = piece;
345 
346    ASSERT(board->pos[to]==-1);
347    board->pos[to] = pos;
348 
349    // piece list
350 
351    ASSERT(board->list[colour][pos]==from);
352    board->list[colour][pos] = to;
353 
354    // hash key
355 
356    piece_index = RandomPiece + piece_to_12(piece) * 64;
357 
358    board->key ^= random_64(piece_index+square_to_64(from))
359                ^ random_64(piece_index+square_to_64(to));
360 }
361 
362 // end of move_do.cpp
363 
364