1
2 // move.c
3
4 // includes
5
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "attack.h"
10 #include "colour.h"
11 #include "list.h"
12 #include "move.h"
13 #include "move_do.h"
14 #include "move_gen.h"
15 #include "move_legal.h"
16 #include "option.h"
17 #include "piece.h"
18 #include "square.h"
19 #include "util.h"
20
21 // "constants"
22
23 static const uint8 PromotePiece[5] = { PieceNone64, Knight64, Bishop64, Rook64, Queen64 };
24
25 // functions
26
27 // move_is_ok()
28
move_is_ok(int move)29 bool move_is_ok(int move) {
30
31 if (move < 0 || move >= 65536) return FALSE;
32
33 if (move == MoveNone) return FALSE;
34
35 return TRUE;
36 }
37
38 // move_make()
39
move_make(int from,int to)40 int move_make(int from, int to) {
41
42 ASSERT(square_is_ok(from));
43 ASSERT(square_is_ok(to));
44
45 return (square_to_64(from) << 6) | square_to_64(to);
46 }
47
48 // move_make_flags()
49
move_make_flags(int from,int to,int flags)50 int move_make_flags(int from, int to, int flags) {
51
52 ASSERT(square_is_ok(from));
53 ASSERT(square_is_ok(to));
54 ASSERT((flags&~0xF000)==0);
55
56 ASSERT(to!=from);
57
58 return (square_to_64(from) << 6) | square_to_64(to) | flags;
59 }
60
61 // move_from()
62
move_from(int move)63 int move_from(int move) {
64
65 int from_64;
66
67 ASSERT(move_is_ok(move));
68
69 from_64 = (move >> 6) & 077;
70
71 return square_from_64(from_64);
72 }
73
74 // move_to()
75
move_to(int move)76 int move_to(int move) {
77
78 int to_64;
79
80 ASSERT(move_is_ok(move));
81
82 to_64 = move & 077;
83
84 return square_from_64(to_64);
85 }
86
87 // move_promote_hack()
88
move_promote_hack(int move)89 int move_promote_hack(int move) {
90
91 int code;
92
93 ASSERT(move_is_ok(move));
94
95 ASSERT(move_is_promote(move));
96
97 code = move >> 12;
98 ASSERT(code>=1&&code<=4);
99
100 return PromotePiece[code];
101 }
102
103 // move_is_capture()
104
move_is_capture(int move,const board_t * board)105 bool move_is_capture(int move, const board_t * board) {
106
107 ASSERT(move_is_ok(move));
108 ASSERT(board_is_ok(board));
109
110 if (move_is_en_passant(move,board)) return TRUE;
111 if (board->square[move_to(move)] != Empty) return TRUE;
112
113 return FALSE;
114 }
115
116 // move_is_promote()
117
move_is_promote(int move)118 bool move_is_promote(int move) {
119
120 ASSERT(move_is_ok(move));
121
122 return (move & MoveFlags) != 0;
123 }
124
125 // move_is_en_passant()
126
move_is_en_passant(int move,const board_t * board)127 bool move_is_en_passant(int move, const board_t * board) {
128
129 ASSERT(move_is_ok(move));
130 ASSERT(board_is_ok(board));
131
132 return piece_is_pawn(move_piece(move,board))
133 && move_to(move) == board->ep_square;
134 }
135
136 // move_is_castle()
137
move_is_castle(int move,const board_t * board)138 bool move_is_castle(int move, const board_t * board) {
139
140 ASSERT(move_is_ok(move));
141 ASSERT(board_is_ok(board));
142
143 return colour_equal(board->square[move_to(move)],board->turn);
144 }
145
146 // move_piece()
147
move_piece(int move,const board_t * board)148 int move_piece(int move, const board_t * board) {
149
150 ASSERT(move_is_ok(move));
151 ASSERT(board_is_ok(board));
152
153 return board->square[move_from(move)];
154 }
155
156 // move_capture()
157
move_capture(int move,const board_t * board)158 int move_capture(int move, const board_t * board) {
159
160 ASSERT(move_is_ok(move));
161 ASSERT(board_is_ok(board));
162
163 if (move_is_en_passant(move,board)) {
164 return piece_pawn_opp(move_piece(move,board));
165 }
166
167 return board->square[move_to(move)];
168 }
169
170 // move_promote()
171
move_promote(int move,const board_t * board)172 int move_promote(int move, const board_t * board) {
173
174 int code;
175
176 ASSERT(move_is_ok(move));
177 ASSERT(board_is_ok(board));
178
179 if (move_is_promote(move)) {
180 code = move >> 12;
181 ASSERT(code>=1&&code<=4);
182 return PromotePiece[code] | board->turn;
183 }
184
185 return Empty;
186 }
187
188 // move_is_check()
189
move_is_check(int move,const board_t * board)190 bool move_is_check(int move, const board_t * board) {
191
192 board_t new_board[1];
193
194 ASSERT(move_is_ok(move));
195 ASSERT(board_is_ok(board));
196
197 board_copy(new_board,board);
198 move_do(new_board,move);
199 ASSERT(!is_in_check(new_board,colour_opp(new_board->turn)));
200
201 return board_is_check(new_board);
202 }
203
204 // move_is_mate()
205
move_is_mate(int move,const board_t * board)206 bool move_is_mate(int move, const board_t * board) {
207
208 board_t new_board[1];
209
210 ASSERT(move_is_ok(move));
211 ASSERT(board_is_ok(board));
212
213 board_copy(new_board,board);
214 move_do(new_board,move);
215 ASSERT(!is_in_check(new_board,colour_opp(new_board->turn)));
216
217 return board_is_mate(new_board);
218 }
219
220 // move_to_can()
221
move_to_can(int move,const board_t * board,char string[],int size)222 bool move_to_can(int move, const board_t * board, char string[], int size) {
223
224 int from, to;
225
226 ASSERT(move_is_ok(move));
227 ASSERT(board_is_ok(board));
228 ASSERT(string!=NULL);
229 ASSERT(size>=6);
230
231 ASSERT(move_is_legal(move,board));
232
233 if (size < 6) return FALSE;
234
235 // init
236
237 from = move_from(move);
238 to = move_to(move);
239
240 // king-slide castling
241
242 if (move_is_castle(move,board) && !option_get_bool(Option,"Chess960")) {
243 if (FALSE) {
244 } else if (from == E1 && to == H1) {
245 to = G1;
246 } else if (from == E1 && to == A1) {
247 to = C1;
248 } else if (from == E8 && to == H8) {
249 to = G8;
250 } else if (from == E8 && to == A8) {
251 to = C8;
252 }
253 }
254
255 // normal moves
256
257 if (!square_to_string(from,&string[0],3)) ASSERT(FALSE);
258 if (!square_to_string(to,&string[2],3)) ASSERT(FALSE);
259 ASSERT(strlen(string)==4);
260
261 // promotes
262
263 if (move_is_promote(move)) {
264 string[4] = piece_to_char(move_promote_hack(move)|Black); // HACK: black => lower-case
265 string[5] = '\0';
266 }
267
268 // debug
269
270 ASSERT(move_from_can(string,board)==move);
271
272 return TRUE;
273 }
274
275 // move_from_can()
276
move_from_can(const char string[],const board_t * board)277 int move_from_can(const char string[], const board_t * board) {
278
279 char tmp_string[256];
280 int from, to;
281 int side;
282 int move;
283
284 ASSERT(string!=NULL);
285 ASSERT(board_is_ok(board));
286
287 // from
288
289 tmp_string[0] = string[0];
290 tmp_string[1] = string[1];
291 tmp_string[2] = '\0';
292
293 from = square_from_string(tmp_string);
294 if (from == SquareNone) return MoveNone;
295
296 // to
297
298 tmp_string[0] = string[2];
299 tmp_string[1] = string[3];
300 tmp_string[2] = '\0';
301
302 to = square_from_string(tmp_string);
303 if (to == SquareNone) return MoveNone;
304
305 // convert "king slide" castling to KxR
306
307 if (piece_is_king(board->square[from])
308 && square_rank(to) == square_rank(from)
309 && abs(to-from) > 1) {
310 side = (to > from) ? SideH : SideA;
311 to = board->castle[board->turn][side];
312 if (to == SquareNone) return MoveNone;
313 }
314 // move
315
316 move = move_make(from,to);
317
318 // promote
319 switch (string[4]) {
320 case '\0': // not a promotion
321 if (piece_is_pawn(board->square[from])
322 && square_side_rank(to,board->turn) == Rank8
323 && option_get_bool(Option,"PromoteWorkAround")) {
324 move |= MovePromoteQueen;
325 }
326 break;
327 case 'N':
328 case 'n':
329 move |= MovePromoteKnight;
330 break;
331 case 'B':
332 case 'b':
333 move |= MovePromoteBishop;
334 break;
335 case 'R':
336 case 'r':
337 move |= MovePromoteRook;
338 break;
339 case 'Q':
340 case 'q':
341 move |= MovePromoteQueen;
342 break;
343 default:
344 return MoveNone;
345 break;
346 }
347 // debug
348
349 ASSERT(move_is_legal(move,board));
350 return move;
351 }
352
353 // move_order()
354
move_order(int move)355 int move_order(int move) {
356
357 ASSERT(move_is_ok(move));
358
359 return ((move & 07777) << 3) | (move >> 12); // from, to, promote
360 }
361
362 // move_disp()
363
move_disp(int move,const board_t * board)364 void move_disp(int move, const board_t * board) {
365
366 char string[256];
367
368 ASSERT(move_is_ok(move));
369 ASSERT(board_is_ok(board));
370
371 if (!move_to_can(move,board,string,256)) ASSERT(FALSE);
372 my_log("POLYGLOT %s\n",string);
373 }
374
375 // end of move.cpp
376
377