Rev 44 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | pmbaty | 1 | // move.cpp |
2 | |||
3 | #include "common.h" |
||
4 | |||
5 | |||
6 | // handy macros |
||
7 | #define IS_VALID(li,co) (((li) >= 0) && ((li) < 8) && ((co) >= 0) && ((co) < 8)) |
||
8 | #define IS_FREE(li,co) (IS_VALID ((li), (co)) && (move->slots[(li)][(co)].part == PART_NONE)) |
||
9 | #define CAN_PLAY(li,co) (IS_VALID ((li), (co)) && ((move->slots[(li)][(co)].part == PART_NONE) || (move->slots[(li)][(co)].color != boardslot->color))) |
||
10 | |||
11 | |||
12 | // prototypes of local functions |
||
74 | pmbaty | 13 | static bool Move_IsWayClearBetween (boardmove_t *move, int source_line, int source_column, int target_line, int target_column); |
1 | pmbaty | 14 | static void AddPossibleMove (boardmove_t **possiblemoves, int *possiblemove_count, int color, int part, int source_line, int source_column, int target_line, int target_column, int promotion_type, bool has_captured, bool is_enpassant); |
15 | |||
16 | |||
17 | void Move_SetSlot (boardmove_t *move, int line, int column, int color, int part_type) |
||
18 | { |
||
19 | // this function populates a board's slot at the given line,column coordinates with the |
||
20 | // given part of the given color |
||
21 | |||
22 | move->slots[line][column].flags = 0; // reset flags |
||
23 | move->slots[line][column].color = color; // set part color |
||
24 | move->slots[line][column].part = part_type; // set part type |
||
25 | |||
26 | return; // finished, board slot is set |
||
27 | } |
||
28 | |||
29 | |||
30 | bool Move_IsKingThreatenedAtLocation (boardmove_t *move, int color, int at_line, int at_column, int *threat_line, int *threat_column) |
||
31 | { |
||
32 | // this function returns TRUE if the specified color is safe at the specified location. |
||
33 | // In case it is not, it returns FALSE and sets the threat's line and column parameters. |
||
34 | // Note the use of the threat_line and threat_column output parameters as iterator |
||
35 | // variables. |
||
36 | |||
37 | boardslot_t *boardslot; |
||
38 | int movement_direction; |
||
39 | int line; |
||
40 | int column; |
||
41 | int index_line; |
||
42 | int index_column; |
||
43 | |||
44 | // cycle through all the board |
||
45 | for (line = 0; line < 8; line++) |
||
46 | for (column = 0; column < 8; column++) |
||
47 | { |
||
48 | boardslot = &move->slots[line][column]; // quick access to grid slot |
||
49 | |||
50 | if ((boardslot->part == PART_NONE) || (boardslot->color == color)) |
||
51 | continue; // if this location is empty or ours, it doesn't threaten us |
||
52 | |||
53 | // update new possible threat position |
||
54 | *threat_line = line; |
||
55 | *threat_column = column; |
||
56 | |||
57 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
58 | ////////////////////////////////////////// PAWN ////////////////////////////////////////// |
||
59 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
60 | // is it a pawn ? (note: pawns can only threaten kings normally, never "en passant") |
||
61 | if (boardslot->part == PART_PAWN) |
||
62 | { |
||
63 | // figure out movement direction |
||
64 | if (boardslot->color == COLOR_WHITE) |
||
65 | movement_direction = 1; |
||
66 | else |
||
67 | movement_direction = -1; |
||
68 | |||
69 | // see if pawn can take our piece on either of its sides |
||
70 | if ((column > 0) && (line + movement_direction == at_line) && (column - 1 == at_column)) |
||
71 | return (true); // this part threatens us, it can take our piece on its left |
||
72 | else if ((column < 7) && (line + movement_direction == at_line) && (column + 1 == at_column)) |
||
73 | return (true); // this part threatens us, it can take our piece on its right |
||
74 | } |
||
75 | |||
76 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
77 | ////////////////////////////////////////// ROOK ////////////////////////////////////////// |
||
78 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
79 | // else is it a rook ? |
||
80 | else if (boardslot->part == PART_ROOK) |
||
81 | { |
||
82 | // is rook in the same column as our king ? |
||
83 | if (column == at_column) |
||
84 | { |
||
85 | // is our king above ? |
||
86 | if (at_line > line) |
||
87 | { |
||
88 | // see if rook can threaten our king by moving upwards |
||
89 | for (index_line = line + 1; index_line < 8; index_line++) |
||
90 | if (index_line == at_line) |
||
91 | return (true); // this part threatens us |
||
92 | else if (!IS_FREE (index_line, column)) |
||
93 | break; // if part can no longer move this way, stop searching |
||
94 | } |
||
95 | |||
96 | // else our king must be below |
||
97 | else |
||
98 | { |
||
99 | // see if rook can threaten our king by moving downwards |
||
100 | for (index_line = line - 1; index_line >= 0; index_line--) |
||
101 | if (index_line == at_line) |
||
102 | return (true); // this part threatens us |
||
103 | else if (!IS_FREE (index_line, column)) |
||
104 | break; // if part can no longer move this way, stop searching |
||
105 | } |
||
106 | } |
||
107 | |||
108 | // else is rook in the same line as our king ? |
||
109 | else if (line == at_line) |
||
110 | { |
||
111 | // is our king on the right ? |
||
112 | if (at_column > column) |
||
113 | { |
||
114 | // see if rook can threaten our king by moving right |
||
115 | for (index_column = column + 1; index_column < 8; index_column++) |
||
116 | if (index_column == at_column) |
||
117 | return (true); // this part threatens us |
||
118 | else if (!IS_FREE (line, index_column)) |
||
119 | break; // if part can no longer move this way, stop searching |
||
120 | } |
||
121 | |||
122 | // else our king must be on the left |
||
123 | else |
||
124 | { |
||
125 | // see if rook can threaten our king by moving left |
||
126 | for (index_column = column - 1; index_column >= 0; index_column--) |
||
127 | if (index_column == at_column) |
||
128 | return (true); // this part threatens us |
||
129 | else if (!IS_FREE (line, index_column)) |
||
130 | break; // if part can no longer move this way, stop searching |
||
131 | } |
||
132 | } |
||
133 | } |
||
134 | |||
135 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
136 | ///////////////////////////////////////// KNIGHT ///////////////////////////////////////// |
||
137 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
138 | // else is it a knight ? |
||
139 | else if (boardslot->part == PART_KNIGHT) |
||
140 | { |
||
141 | if ((column > 0) && (line < 6) && (line + 2 == at_line) && (column - 1 == at_column)) |
||
142 | return (true); // this part threatens us on its NNW move |
||
143 | else if ((column < 7) && (line < 6) && (line + 2 == at_line) && (column + 1 == at_column)) |
||
144 | return (true); // this part threatens us on its NNE move |
||
145 | else if ((column < 6) && (line < 7) && (line + 1 == at_line) && (column + 2 == at_column)) |
||
146 | return (true); // this part threatens us on its ENE move |
||
147 | else if ((column < 6) && (line > 0) && (line - 1 == at_line) && (column + 2 == at_column)) |
||
148 | return (true); // this part threatens us on its ESE move |
||
149 | else if ((column > 0) && (line > 1) && (line - 2 == at_line) && (column - 1 == at_column)) |
||
150 | return (true); // this part threatens us on its SSW move |
||
151 | else if ((column < 7) && (line > 1) && (line - 2 == at_line) && (column + 1 == at_column)) |
||
152 | return (true); // this part threatens us on its SSE move |
||
153 | else if ((column > 1) && (line < 7) && (line + 1 == at_line) && (column - 2 == at_column)) |
||
154 | return (true); // this part threatens us on its WNW move |
||
155 | else if ((column > 1) && (line > 0) && (line - 1 == at_line) && (column - 2 == at_column)) |
||
156 | return (true); // this part threatens us on its WSW move |
||
157 | } |
||
158 | |||
159 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
160 | ///////////////////////////////////////// BISHOP ///////////////////////////////////////// |
||
161 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
162 | // else is it a bishop ? |
||
163 | else if (boardslot->part == PART_BISHOP) |
||
164 | { |
||
165 | // is bishop in the same SWNE diagonal as our king ? |
||
166 | if (line - at_line == column - at_column) |
||
167 | { |
||
168 | // is our king NE ? |
||
169 | if (at_line > line) |
||
170 | { |
||
171 | // see how far bishop can move NE |
||
172 | for (index_line = line + 1, index_column = column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++) |
||
173 | if ((index_line == at_line) && (index_column == at_column)) |
||
174 | return (true); // this part threatens us |
||
175 | else if (!IS_FREE (index_line, index_column)) |
||
176 | break; // if part can no longer move this way, stop searching |
||
177 | } |
||
178 | |||
179 | // else our king must be SW |
||
180 | else |
||
181 | { |
||
182 | // see how far bishop can move SW |
||
183 | for (index_line = line - 1, index_column = column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--) |
||
184 | if ((index_line == at_line) && (index_column == at_column)) |
||
185 | return (true); // this part threatens us |
||
186 | else if (!IS_FREE (index_line, index_column)) |
||
187 | break; // if part can no longer move this way, stop searching |
||
188 | } |
||
189 | } |
||
190 | |||
191 | // else is bishop in the same SENW diagonal as our king ? |
||
192 | else if (line - at_line == -(column - at_column)) |
||
193 | { |
||
194 | // is our king NW ? |
||
195 | if (at_line > line) |
||
196 | { |
||
197 | // see how far bishop can move NW |
||
198 | for (index_line = line + 1, index_column = column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--) |
||
199 | if ((index_line == at_line) && (index_column == at_column)) |
||
200 | return (true); // this part threatens us |
||
201 | else if (!IS_FREE (index_line, index_column)) |
||
202 | break; // if part can no longer move this way, stop searching |
||
203 | } |
||
204 | |||
205 | // else our king must be SE |
||
206 | else |
||
207 | { |
||
208 | // see how far bishop can move SE |
||
209 | for (index_line = line - 1, index_column = column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++) |
||
210 | if ((index_line == at_line) && (index_column == at_column)) |
||
211 | return (true); // this part threatens us |
||
212 | else if (!IS_FREE (index_line, index_column)) |
||
213 | break; // if part can no longer move this way, stop searching |
||
214 | } |
||
215 | } |
||
216 | } |
||
217 | |||
218 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
219 | ///////////////////////////////////////// QUEEN ////////////////////////////////////////// |
||
220 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
221 | // else is it a queen ? |
||
222 | else if (boardslot->part == PART_QUEEN) |
||
223 | { |
||
224 | // is queen in the same column as our king ? |
||
225 | if (column == at_column) |
||
226 | { |
||
227 | // is our king above ? |
||
228 | if (at_line > line) |
||
229 | { |
||
230 | // see if queen can threaten our king by moving upwards |
||
231 | for (index_line = line + 1; index_line < 8; index_line++) |
||
232 | if (index_line == at_line) |
||
233 | return (true); // this part threatens us |
||
234 | else if (!IS_FREE (index_line, column)) |
||
235 | break; // if part can no longer move this way, stop searching |
||
236 | } |
||
237 | |||
238 | // else our king must be below |
||
239 | else |
||
240 | { |
||
241 | // see if queen can threaten our king by moving downwards |
||
242 | for (index_line = line - 1; index_line >= 0; index_line--) |
||
243 | if (index_line == at_line) |
||
244 | return (true); // this part threatens us |
||
245 | else if (!IS_FREE (index_line, column)) |
||
246 | break; // if part can no longer move this way, stop searching |
||
247 | } |
||
248 | } |
||
249 | |||
250 | // else is queen in the same line as our king ? |
||
251 | else if (line == at_line) |
||
252 | { |
||
253 | // is our king on the right ? |
||
254 | if (at_column > column) |
||
255 | { |
||
256 | // see if queen can threaten our king by moving right |
||
257 | for (index_column = column + 1; index_column < 8; index_column++) |
||
258 | if (index_column == at_column) |
||
259 | return (true); // this part threatens us |
||
260 | else if (!IS_FREE (line, index_column)) |
||
261 | break; // if part can no longer move this way, stop searching |
||
262 | } |
||
263 | |||
264 | // else our king must be on the left |
||
265 | else |
||
266 | { |
||
267 | // see if queen can threaten our king by moving left |
||
268 | for (index_column = column - 1; index_column >= 0; index_column--) |
||
269 | if (index_column == at_column) |
||
270 | return (true); // this part threatens us |
||
271 | else if (!IS_FREE (line, index_column)) |
||
272 | break; // if part can no longer move this way, stop searching |
||
273 | } |
||
274 | } |
||
275 | |||
276 | // else is queen in the same SWNE diagonal as our king ? |
||
277 | else if (line - at_line == column - at_column) |
||
278 | { |
||
279 | // is our king NE ? |
||
280 | if (at_line > line) |
||
281 | { |
||
282 | // see how far queen can move NE |
||
283 | for (index_line = line + 1, index_column = column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++) |
||
284 | if ((index_line == at_line) && (index_column == at_column)) |
||
285 | return (true); // this part threatens us |
||
286 | else if (!IS_FREE (index_line, index_column)) |
||
287 | break; // if part can no longer move this way, stop searching |
||
288 | } |
||
289 | |||
290 | // else our king must be SW |
||
291 | else |
||
292 | { |
||
293 | // see how far queen can move SW |
||
294 | for (index_line = line - 1, index_column = column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--) |
||
295 | if ((index_line == at_line) && (index_column == at_column)) |
||
296 | return (true); // this part threatens us |
||
297 | else if (!IS_FREE (index_line, index_column)) |
||
298 | break; // if part can no longer move this way, stop searching |
||
299 | } |
||
300 | } |
||
301 | |||
302 | // else is queen in the same SENW diagonal as our king ? |
||
303 | else if (line - at_line == -(column - at_column)) |
||
304 | { |
||
305 | // is our king NW ? |
||
306 | if (at_line > line) |
||
307 | { |
||
308 | // see how far queen can move NW |
||
309 | for (index_line = line + 1, index_column = column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--) |
||
310 | if ((index_line == at_line) && (index_column == at_column)) |
||
311 | return (true); // this part threatens us |
||
312 | else if (!IS_FREE (index_line, index_column)) |
||
313 | break; // if part can no longer move this way, stop searching |
||
314 | } |
||
315 | |||
316 | // else our king must be SE |
||
317 | else |
||
318 | { |
||
319 | // see how far queen can move SE |
||
320 | for (index_line = line - 1, index_column = column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++) |
||
321 | if ((index_line == at_line) && (index_column == at_column)) |
||
322 | return (true); // this part threatens us |
||
323 | else if (!IS_FREE (index_line, index_column)) |
||
324 | break; // if part can no longer move this way, stop searching |
||
325 | } |
||
326 | } |
||
327 | } |
||
328 | |||
329 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
330 | ////////////////////////////////////////// KING ////////////////////////////////////////// |
||
331 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
332 | // else is it a king ? |
||
333 | else if (boardslot->part == PART_KING) |
||
334 | { |
||
335 | if ((line < 7) && (column < 7) && (line + 1 == at_line) && (column + 1 == at_column)) |
||
336 | return (true); // this part threatens us on its NE move |
||
337 | else if ((line > 0) && (column < 7) && (line - 1 == at_line) && (column + 1 == at_column)) |
||
338 | return (true); // this part threatens us on its SE move |
||
339 | else if ((line < 7) && (column > 0) && (line + 1 == at_line) && (column - 1 == at_column)) |
||
340 | return (true); // this part threatens us on its NW move |
||
341 | else if ((line > 0) && (column > 0) && (line - 1 == at_line) && (column - 1 == at_column)) |
||
342 | return (true); // this part threatens us on its SW move |
||
343 | else if ((line < 7) && (line + 1 == at_line) && (column == at_column)) |
||
344 | return (true); // this part threatens us on an upwards move |
||
345 | else if ((line > 0) && (line - 1 == at_line) && (column == at_column)) |
||
346 | return (true); // this part threatens us on a downwards move |
||
347 | else if ((column < 7) && (line == at_line) && (column + 1 == at_column)) |
||
348 | return (true); // this part threatens us on a right move |
||
349 | else if ((column > 0) && (line == at_line) && (column - 1 == at_column)) |
||
350 | return (true); // this part threatens us on a left move |
||
351 | } |
||
352 | } |
||
353 | |||
354 | return (false); // this king looks safe at this location |
||
355 | } |
||
356 | |||
357 | |||
358 | bool Move_IsCheck (boardmove_t *move, int color) |
||
359 | { |
||
360 | // this function returns TRUE if the king of the specified color is under check |
||
361 | |||
362 | boardslot_t *boardslot; |
||
363 | int line; |
||
364 | int column; |
||
365 | int threat_line; |
||
366 | int threat_column; |
||
367 | |||
368 | // cycle through all the grid again and see if the king we want is in check |
||
369 | for (line = 0; line < 8; line++) |
||
370 | for (column = 0; column < 8; column++) |
||
371 | { |
||
372 | boardslot = &move->slots[line][column]; // quick access to grid slot |
||
373 | |||
374 | if ((boardslot->color != color) || (boardslot->part != PART_KING)) |
||
375 | continue; // if this slot is not our king, skip it |
||
376 | |||
377 | // is this king currently threatened ? |
||
378 | if (Move_IsKingThreatenedAtLocation (move, color, line, column, &threat_line, &threat_column)) |
||
379 | return (true); // yes, it is |
||
380 | else |
||
381 | return (false); // no, this king is safe |
||
382 | } |
||
383 | |||
384 | // code should never reach here (it would mean that no king is on the board) |
||
385 | |||
386 | return (false); // no king of such color found on board, no check possible, return FALSE |
||
387 | } |
||
388 | |||
389 | |||
390 | bool Move_IsStaleMate (boardmove_t *move, int color) |
||
391 | { |
||
392 | // this function returns TRUE if the specified color is stalemate (no valid move possible) |
||
393 | |||
394 | boardslot_t *boardslot; |
||
395 | int movement_direction; |
||
396 | int line; |
||
397 | int column; |
||
398 | int index_line; |
||
399 | int index_column; |
||
400 | |||
401 | // cycle through all the board and find our parts |
||
402 | for (line = 0; line < 8; line++) |
||
403 | for (column = 0; column < 8; column++) |
||
404 | { |
||
405 | boardslot = &move->slots[line][column]; // quick access to grid slot |
||
406 | |||
407 | if ((boardslot->part == PART_NONE) || (boardslot->color != color)) |
||
408 | continue; // if this location is empty or not ours, we aren't interested in it |
||
409 | |||
410 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
411 | ////////////////////////////////////////// PAWN ////////////////////////////////////////// |
||
412 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
413 | // is it a pawn ? |
||
414 | if (boardslot->part == PART_PAWN) |
||
415 | { |
||
416 | // figure out movement direction |
||
417 | if (boardslot->color == COLOR_WHITE) |
||
418 | movement_direction = 1; |
||
419 | else |
||
420 | movement_direction = -1; |
||
421 | |||
422 | // see if pawn can move forward |
||
423 | if ((((movement_direction == 1) && (line < 7)) || ((movement_direction == -1) && (line > 0))) |
||
424 | && (move->slots[line + movement_direction][column].part == PART_NONE) // target slot free |
||
425 | && !Move_IsColorInCheckAfterTestMove (move, line, column, line + movement_direction, column, color)) |
||
426 | return (false); // this move is possible |
||
427 | |||
428 | // see if pawn can take a piece on its left |
||
429 | if ((((movement_direction == 1) && (line < 7)) || ((movement_direction == -1) && (line > 0))) |
||
430 | && (column > 0) // has room |
||
431 | && (move->slots[line + movement_direction][column - 1].color != color) // target slot NOT our color |
||
432 | && (move->slots[line + movement_direction][column - 1].part != PART_NONE) // target slot occupied |
||
433 | && !Move_IsColorInCheckAfterTestMove (move, line, column, line + movement_direction, column - 1, color)) |
||
434 | return (false); // this move is possible |
||
435 | |||
436 | // see if pawn can take a piece on its right |
||
437 | if ((((movement_direction == 1) && (line < 7)) || ((movement_direction == -1) && (line > 0))) |
||
438 | && (column < 7) // has room |
||
439 | && (move->slots[line + movement_direction][column + 1].color != color) // target slot NOT our color |
||
440 | && (move->slots[line + movement_direction][column + 1].part != PART_NONE) // target slot occupied |
||
441 | && !Move_IsColorInCheckAfterTestMove (move, line, column, line + movement_direction, column + 1, color)) |
||
442 | return (false); // this move is possible |
||
443 | |||
444 | // if previous move was a pawn rush, see if pawn can take "en passant" |
||
445 | if ((move->part == PART_PAWN) // last move was a pawn |
||
446 | && (move->target[1] == move->source[1]) // pawn moved in column |
||
447 | && (abs (move->target[0] - move->source[0]) == 2) // pawn rushed |
||
448 | && (move->target[0] == line) // pawn is in line with us |
||
449 | && (move->target[1] - column == -1) // pawn is left to us |
||
450 | && !Move_IsColorInCheckAfterTestMoveEP (move, line, column, line + movement_direction, column - 1, move->target[0], move->target[1], color)) |
||
451 | return (false); // this move is possible |
||
452 | else if ((move->part == PART_PAWN) // last move was a pawn |
||
453 | && (move->target[1] == move->source[1]) // pawn moved in column |
||
454 | && (abs (move->target[0] - move->source[0]) == 2) // pawn rushed |
||
455 | && (move->target[0] == line) // pawn is in line with us |
||
456 | && (move->target[1] - column == 1) // pawn is right to us |
||
457 | && !Move_IsColorInCheckAfterTestMoveEP (move, line, column, line + movement_direction, column + 1, move->target[0], move->target[1], color)) |
||
458 | return (false); // this move is possible |
||
459 | } |
||
460 | |||
461 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
462 | ////////////////////////////////////////// ROOK ////////////////////////////////////////// |
||
463 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
464 | // else is it a rook ? |
||
465 | else if (boardslot->part == PART_ROOK) |
||
466 | { |
||
467 | // see if rook can move upwards |
||
468 | for (index_line = line + 1; index_line < 8; index_line++) |
||
469 | if (!CAN_PLAY (index_line, column)) |
||
470 | break; // if part can no longer move this way, stop searching |
||
471 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color)) |
||
472 | return (false); // this move is possible |
||
74 | pmbaty | 473 | else if (move->slots[index_line][column].part != PART_NONE) |
474 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 475 | |
476 | // see if rook can move downwards |
||
477 | for (index_line = line - 1; index_line >= 0; index_line--) |
||
478 | if (!CAN_PLAY (index_line, column)) |
||
479 | break; // if part can no longer move this way, stop searching |
||
480 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color)) |
||
481 | return (false); // this move is possible |
||
74 | pmbaty | 482 | else if (move->slots[index_line][column].part != PART_NONE) |
483 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 484 | |
485 | // see if rook can move right |
||
486 | for (index_column = column + 1; index_column < 8; index_column++) |
||
487 | if (!CAN_PLAY (line, index_column)) |
||
488 | break; // if part can no longer move this way, stop searching |
||
489 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color)) |
||
490 | return (false); // this move is possible |
||
74 | pmbaty | 491 | else if (move->slots[line][index_column].part != PART_NONE) |
492 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 493 | |
494 | // see if rook can move left |
||
495 | for (index_column = column - 1; index_column >= 0; index_column--) |
||
496 | if (!CAN_PLAY (line, index_column)) |
||
497 | break; // if part can no longer move this way, stop searching |
||
498 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color)) |
||
499 | return (false); // this move is possible |
||
74 | pmbaty | 500 | else if (move->slots[line][index_column].part != PART_NONE) |
501 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 502 | } |
503 | |||
504 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
505 | ///////////////////////////////////////// KNIGHT ///////////////////////////////////////// |
||
506 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
507 | // else is it a knight ? |
||
508 | else if (boardslot->part == PART_KNIGHT) |
||
509 | { |
||
510 | // see if knight can move in either of his allowed directions NNW |
||
511 | if (CAN_PLAY (line + 2, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 2, column - 1, color)) |
||
512 | return (false); // knight can move NNW, we are not stalemate |
||
513 | else if (CAN_PLAY (line + 2, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 2, column + 1, color)) |
||
514 | return (false); // knight can move NNE, we are not stalemate |
||
515 | else if (CAN_PLAY (line + 1, column + 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column + 2, color)) |
||
516 | return (false); // knight can move ENE, we are not stalemate |
||
517 | else if (CAN_PLAY (line - 1, column + 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column + 2, color)) |
||
518 | return (false); // knight can move ESE, we are not stalemate |
||
519 | else if (CAN_PLAY (line - 2, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 2, column - 1, color)) |
||
520 | return (false); // knight can move SSW, we are not stalemate |
||
521 | else if (CAN_PLAY (line - 2, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 2, column + 1, color)) |
||
522 | return (false); // knight can move SSE, we are not stalemate |
||
523 | else if (CAN_PLAY (line + 1, column - 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column - 2, color)) |
||
524 | return (false); // knight can move WNW, we are not stalemate |
||
525 | else if (CAN_PLAY (line - 1, column - 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column - 2, color)) |
||
526 | return (false); // knight can move WSW, we are not stalemate |
||
527 | } |
||
528 | |||
529 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
530 | ///////////////////////////////////////// BISHOP ///////////////////////////////////////// |
||
531 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
532 | // else is it a bishop ? |
||
533 | else if (boardslot->part == PART_BISHOP) |
||
534 | { |
||
535 | // see if bishop can move NE |
||
536 | for (index_line = line + 1, index_column = column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++) |
||
537 | if (!CAN_PLAY (index_line, index_column)) |
||
538 | break; // if part can no longer move this way, stop searching |
||
539 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
540 | return (false); // this move is possible |
||
74 | pmbaty | 541 | else if (move->slots[index_line][index_column].part != PART_NONE) |
542 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 543 | |
544 | // see if bishop can move SE |
||
545 | for (index_line = line - 1, index_column = column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++) |
||
546 | if (!CAN_PLAY (index_line, index_column)) |
||
547 | break; // if part can no longer move this way, stop searching |
||
548 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
549 | return (false); // this move is possible |
||
74 | pmbaty | 550 | else if (move->slots[index_line][index_column].part != PART_NONE) |
551 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 552 | |
553 | // see if bishop can move NW |
||
554 | for (index_line = line + 1, index_column = column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--) |
||
555 | if (!CAN_PLAY (index_line, index_column)) |
||
556 | break; // if part can no longer move this way, stop searching |
||
557 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
558 | return (false); // this move is possible |
||
74 | pmbaty | 559 | else if (move->slots[index_line][index_column].part != PART_NONE) |
560 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 561 | |
562 | // see if bishop can move SW |
||
563 | for (index_line = line - 1, index_column = column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--) |
||
564 | if (!CAN_PLAY (index_line, index_column)) |
||
565 | break; // if part can no longer move this way, stop searching |
||
566 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
567 | return (false); // this move is possible |
||
74 | pmbaty | 568 | else if (move->slots[index_line][index_column].part != PART_NONE) |
569 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 570 | } |
571 | |||
572 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
573 | ///////////////////////////////////////// QUEEN ////////////////////////////////////////// |
||
574 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
575 | // else is it a queen ? |
||
576 | else if (boardslot->part == PART_QUEEN) |
||
577 | { |
||
578 | // see if queen can move upwards |
||
579 | for (index_line = line + 1; index_line < 8; index_line++) |
||
580 | if (!CAN_PLAY (index_line, column)) |
||
581 | break; // if part can no longer move this way, stop searching |
||
582 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color)) |
||
583 | return (false); // this move is possible |
||
74 | pmbaty | 584 | else if (move->slots[index_line][column].part != PART_NONE) |
585 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 586 | |
587 | // see if queen can move downwards |
||
588 | for (index_line = line - 1; index_line >= 0; index_line--) |
||
589 | if (!CAN_PLAY (index_line, column)) |
||
590 | break; // if part can no longer move this way, stop searching |
||
591 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color)) |
||
592 | return (false); // this move is possible |
||
74 | pmbaty | 593 | else if (move->slots[index_line][column].part != PART_NONE) |
594 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 595 | |
596 | // see if queen can move right |
||
597 | for (index_column = column + 1; index_column < 8; index_column++) |
||
598 | if (!CAN_PLAY (line, index_column)) |
||
599 | break; // if part can no longer move this way, stop searching |
||
600 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color)) |
||
601 | return (false); // this move is possible |
||
74 | pmbaty | 602 | else if (move->slots[line][index_column].part != PART_NONE) |
603 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 604 | |
605 | // see if queen can move left |
||
606 | for (index_column = column - 1; index_column >= 0; index_column--) |
||
607 | if (!CAN_PLAY (line, index_column)) |
||
608 | break; // if part can no longer move this way, stop searching |
||
609 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color)) |
||
610 | return (false); // this move is possible |
||
74 | pmbaty | 611 | else if (move->slots[line][index_column].part != PART_NONE) |
612 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 613 | |
614 | // see if queen can move NE |
||
615 | for (index_line = line + 1, index_column = column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++) |
||
616 | if (!CAN_PLAY (index_line, index_column)) |
||
617 | break; // if part can no longer move this way, stop searching |
||
618 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
619 | return (false); // this move is possible |
||
74 | pmbaty | 620 | else if (move->slots[index_line][index_column].part != PART_NONE) |
621 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 622 | |
623 | // see if queen can move SE |
||
624 | for (index_line = line - 1, index_column = column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++) |
||
625 | if (!CAN_PLAY (index_line, index_column)) |
||
626 | break; // if part can no longer move this way, stop searching |
||
627 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
628 | return (false); // this move is possible |
||
74 | pmbaty | 629 | else if (move->slots[index_line][index_column].part != PART_NONE) |
630 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 631 | |
632 | // see if queen can move NW |
||
633 | for (index_line = line + 1, index_column = column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--) |
||
634 | if (!CAN_PLAY (index_line, index_column)) |
||
635 | break; // if part can no longer move this way, stop searching |
||
636 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
637 | return (false); // this move is possible |
||
74 | pmbaty | 638 | else if (move->slots[index_line][index_column].part != PART_NONE) |
639 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 640 | |
641 | // see if queen can move SW |
||
642 | for (index_line = line - 1, index_column = column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--) |
||
643 | if (!CAN_PLAY (index_line, index_column)) |
||
644 | break; // if part can no longer move this way, stop searching |
||
645 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
646 | return (false); // this move is possible |
||
74 | pmbaty | 647 | else if (move->slots[index_line][index_column].part != PART_NONE) |
648 | break; // no further moves are possible in the same direction |
||
1 | pmbaty | 649 | } |
650 | |||
651 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
652 | ////////////////////////////////////////// KING ////////////////////////////////////////// |
||
653 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
654 | // else is it a king ? |
||
655 | else if (boardslot->part == PART_KING) |
||
656 | { |
||
657 | // see if king can move in either of his allowed directions |
||
658 | if (CAN_PLAY (line + 1, column) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column, color)) |
||
659 | return (false); // king can move up, we are not stalemate |
||
660 | else if (CAN_PLAY (line - 1, column) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column, color)) |
||
661 | return (false); // king can move down, we are not stalemate |
||
662 | else if (CAN_PLAY (line, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line, column + 1, color)) |
||
663 | return (false); // king can move right, we are not stalemate |
||
664 | else if (CAN_PLAY (line, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line, column - 1, color)) |
||
665 | return (false); // king can move left, we are not stalemate |
||
666 | else if (CAN_PLAY (line + 1, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column + 1, color)) |
||
667 | return (false); // king can move NE, we are not stalemate |
||
668 | else if (CAN_PLAY (line - 1, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column + 1, color)) |
||
669 | return (false); // king can move SE, we are not stalemate |
||
670 | else if (CAN_PLAY (line + 1, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column - 1, color)) |
||
671 | return (false); // king can move NW, we are not stalemate |
||
672 | else if (CAN_PLAY (line - 1, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column - 1, color)) |
||
673 | return (false); // king can move SW, we are not stalemate |
||
674 | } |
||
675 | } |
||
676 | |||
677 | return (true); // found no legal move, we are indeed stalemate |
||
678 | } |
||
679 | |||
680 | |||
681 | bool Move_IsMoveValid (boardmove_t *move, int from_line, int from_column, int to_line, int to_column) |
||
682 | { |
||
683 | // this function returns TRUE if the specified move is valid, FALSE otherwise |
||
684 | |||
685 | // FIXME: doesn't support castling testing so far! (even though it shouldn't be necessary) |
||
686 | |||
687 | boardslot_t *boardslot; |
||
688 | int movement_direction; |
||
689 | int index_line; |
||
690 | int index_column; |
||
691 | |||
692 | boardslot = &move->slots[from_line][from_column]; // quick access to grid slot |
||
693 | |||
694 | // consistency check |
||
695 | if (!IS_VALID (from_line, from_column) || !IS_VALID (to_line, to_column)) |
||
696 | return (false); // if movement is out of bounds, it's obviously invalid |
||
697 | |||
698 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
699 | ////////////////////////////////////////// PAWN ////////////////////////////////////////// |
||
700 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
701 | // is it a pawn ? |
||
702 | if (boardslot->part == PART_PAWN) |
||
703 | { |
||
704 | // figure out movement direction |
||
705 | if (boardslot->color == COLOR_WHITE) |
||
706 | movement_direction = 1; |
||
707 | else |
||
708 | movement_direction = -1; |
||
709 | |||
710 | // quick checks |
||
711 | if (abs (to_line - from_line) > 2) |
||
712 | return (false); // pawns cannot make moves longer than 2 rows |
||
713 | else if (abs (to_column - from_column) > 1) |
||
714 | return (false); // pawns cannot make moves aside more than 1 column |
||
715 | |||
716 | // do we want pawn to rush forward |
||
717 | // OR do we want pawn to move forward |
||
718 | // OR do we want pawn to take a piece on its left |
||
719 | // OR do we want pawn to take a piece on its right ? |
||
720 | if ((((from_line == 1) || (from_line == 6)) // pawn on its initial slot |
||
721 | && (from_line + 2 * movement_direction == to_line) && (from_column == to_column) // target position is the position we want |
||
722 | && (move->slots[from_line + movement_direction][to_column].part == PART_NONE) // intermediate slot free |
||
723 | && (move->slots[to_line][to_column].part == PART_NONE)) // target slot free |
||
724 | || ((((movement_direction == 1) && (from_line < 7)) || ((movement_direction == -1) && (from_line > 0))) // has room |
||
725 | && (from_line + movement_direction == to_line) && (from_column == to_column) // target position is the position we want |
||
726 | && (move->slots[to_line][to_column].part == PART_NONE)) // target slot free |
||
727 | || ((((movement_direction == 1) && (from_line < 7)) || ((movement_direction == -1) && (from_line > 0))) |
||
728 | && (from_column > 0) // has room |
||
729 | && (from_line + movement_direction == to_line) && (from_column - 1 == to_column) // target position is the position we want |
||
730 | && (move->slots[to_line][to_column].color != boardslot->color) // target slot NOT our color |
||
731 | && (move->slots[to_line][to_column].part != PART_NONE)) // target slot occupied |
||
732 | || ((((movement_direction == 1) && (from_line < 7)) || ((movement_direction == -1) && (from_line > 0))) |
||
733 | && (from_column < 7) // has room |
||
734 | && (from_line + movement_direction == to_line) && (from_column + 1 == to_column) // target position is the position we want |
||
735 | && (move->slots[to_line][to_column].color != boardslot->color) // target slot NOT our color |
||
736 | && (move->slots[to_line][to_column].part != PART_NONE))) // target slot occupied |
||
737 | { |
||
738 | if (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)) |
||
739 | return (true); // this move is possible |
||
740 | |||
741 | return (false); // else this pawn can't move in the claimed way (his king would be in check) |
||
742 | } |
||
743 | |||
744 | // if previous move was a pawn rush, see if pawn can take "en passant" |
||
745 | if (IS_VALID (move->target[0], move->target[1]) // last move is valid |
||
746 | && (move->part == PART_PAWN) // last move was a pawn |
||
747 | && (move->target[1] == move->source[1]) // pawn moved in column |
||
748 | && (abs (move->target[0] - move->source[0]) == 2) // pawn rushed |
||
749 | && (move->target[0] == from_line) // pawn is in line with us |
||
750 | && (move->target[1] - from_column == -1) // pawn is left to us |
||
751 | && (from_line + movement_direction == to_line) && (from_column - 1 == to_column) // target position is the position we want |
||
752 | && !Move_IsColorInCheckAfterTestMoveEP (move, from_line, from_column, to_line, to_column, move->target[0], move->target[1], boardslot->color)) |
||
753 | return (true); // this move is possible |
||
754 | else if (IS_VALID (move->target[0], move->target[1]) // last move is valid |
||
755 | && (move->part == PART_PAWN) // last move was a pawn |
||
756 | && (move->target[1] == move->source[1]) // pawn moved in column |
||
757 | && (abs (move->target[0] - move->source[0]) == 2) // pawn rushed |
||
758 | && (move->target[0] == from_line) // pawn is in line with us |
||
759 | && (move->target[1] - from_column == 1) // pawn is right to us |
||
760 | && (from_line + movement_direction == to_line) && (from_column + 1 == to_column) // target position is the position we want |
||
761 | && !Move_IsColorInCheckAfterTestMoveEP (move, from_line, from_column, to_line, to_column, move->target[0], move->target[1], boardslot->color)) |
||
762 | return (true); // this move is possible |
||
763 | |||
764 | return (false); // this pawn can't move in the claimed way |
||
765 | } |
||
766 | |||
767 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
768 | ////////////////////////////////////////// ROOK ////////////////////////////////////////// |
||
769 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
770 | // else is it a rook ? |
||
771 | else if (boardslot->part == PART_ROOK) |
||
772 | { |
||
773 | // quick checks |
||
774 | if ((to_column != from_column) && (to_line != from_line)) |
||
775 | return (false); // rooks can only move horizontally or vertically |
||
74 | pmbaty | 776 | else if (!Move_IsWayClearBetween (move, from_line, from_column, to_line, to_column)) |
777 | return (false); // way must be clear between source and target |
||
1 | pmbaty | 778 | |
779 | // do we want the rook to move upwards ? |
||
780 | if (to_line > from_line) |
||
781 | { |
||
782 | // see if rook can move upwards |
||
783 | for (index_line = from_line + 1; index_line < 8; index_line++) |
||
784 | if (!CAN_PLAY (index_line, to_column)) |
||
785 | return (false); // if rook can no longer move this way, stop searching |
||
786 | else if (index_line == to_line) |
||
74 | pmbaty | 787 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 788 | } |
789 | |||
790 | // else do we want the rook to move downwards ? |
||
791 | else if (to_line < from_line) |
||
792 | { |
||
793 | // see if rook can move downwards |
||
794 | for (index_line = from_line - 1; index_line >= 0; index_line--) |
||
795 | if (!CAN_PLAY (index_line, to_column)) |
||
796 | return (false); // if rook can no longer move this way, stop searching |
||
797 | else if (index_line == to_line) |
||
74 | pmbaty | 798 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 799 | } |
800 | |||
801 | // else do we want the rook to move right ? |
||
802 | else if (to_column > from_column) |
||
803 | { |
||
804 | // see if rook can move right |
||
805 | for (index_column = from_column + 1; index_column < 8; index_column++) |
||
806 | if (!CAN_PLAY (to_line, index_column)) |
||
807 | return (false); // if rook can no longer move this way, stop searching |
||
808 | else if (index_column == to_column) |
||
74 | pmbaty | 809 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 810 | } |
811 | |||
812 | // else do we want the rook to move left ? |
||
813 | else if (to_column < from_column) |
||
814 | { |
||
815 | // see if rook can move left |
||
816 | for (index_column = from_column - 1; index_column >= 0; index_column--) |
||
817 | if (!CAN_PLAY (to_line, index_column)) |
||
818 | return (false); // if rook can no longer move this way, stop searching |
||
819 | else if (index_column == to_column) |
||
74 | pmbaty | 820 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 821 | } |
822 | |||
823 | return (false); // this rook can't move in the claimed way |
||
824 | } |
||
825 | |||
826 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
827 | ///////////////////////////////////////// KNIGHT ///////////////////////////////////////// |
||
828 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
829 | // else is it a knight ? |
||
830 | else if (boardslot->part == PART_KNIGHT) |
||
831 | { |
||
832 | // do we want to move that knight in one of the allowed directions ? |
||
74 | pmbaty | 833 | if ( ((from_line + 2 == to_line) && (from_column - 1 == to_column)) // NNW |
1 | pmbaty | 834 | || ((from_line + 2 == to_line) && (from_column + 1 == to_column)) // NNE |
835 | || ((from_line + 1 == to_line) && (from_column + 2 == to_column)) // ENE |
||
836 | || ((from_line - 1 == to_line) && (from_column + 2 == to_column)) // ESE |
||
837 | || ((from_line - 2 == to_line) && (from_column - 1 == to_column)) // SSW |
||
838 | || ((from_line - 2 == to_line) && (from_column + 1 == to_column)) // SSE |
||
839 | || ((from_line + 1 == to_line) && (from_column - 2 == to_column)) // WNW |
||
840 | || ((from_line - 1 == to_line) && (from_column - 2 == to_column))) // WSW |
||
841 | { |
||
842 | if (!CAN_PLAY (to_line, to_column)) |
||
843 | return (false); // if knight can't move there (out of board, or some of our parts there), return false |
||
844 | else if (Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)) |
||
845 | return (false); // if knight would leave his king in check there, return false |
||
846 | |||
847 | return (true); // else this move is safe |
||
848 | } |
||
849 | |||
850 | return (false); // this knight can't move in the claimed way |
||
851 | } |
||
852 | |||
853 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
854 | ///////////////////////////////////////// BISHOP ///////////////////////////////////////// |
||
855 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
856 | // else is it a bishop ? |
||
857 | else if (boardslot->part == PART_BISHOP) |
||
858 | { |
||
859 | // quick checks |
||
860 | if (abs (to_column - from_column) != abs (to_line - from_line)) |
||
861 | return (false); // bishops can only move diagonally |
||
74 | pmbaty | 862 | else if (!Move_IsWayClearBetween (move, from_line, from_column, to_line, to_column)) |
863 | return (false); // way must be clear between source and target |
||
1 | pmbaty | 864 | |
865 | // do we want to move the bishop NE ? |
||
866 | if ((to_line > from_line) && (to_column > from_column)) |
||
867 | { |
||
868 | // see if bishop can move NE |
||
869 | for (index_line = from_line + 1, index_column = from_column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++) |
||
870 | if (!CAN_PLAY (index_line, index_column)) |
||
871 | return (false); // if bishop can no longer move this way, stop searching |
||
872 | else if ((index_line == to_line) && (index_column == to_column)) |
||
74 | pmbaty | 873 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 874 | } |
875 | |||
876 | // else do we want to move the bishop SE ? |
||
877 | else if ((to_line < from_line) && (to_column > from_column)) |
||
878 | { |
||
879 | // see if bishop can move SE |
||
880 | for (index_line = from_line - 1, index_column = from_column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++) |
||
881 | if (!CAN_PLAY (index_line, index_column)) |
||
882 | return (false); // if bishop can no longer move this way, stop searching |
||
883 | else if ((index_line == to_line) && (index_column == to_column)) |
||
74 | pmbaty | 884 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 885 | } |
886 | |||
887 | // else do we want to move the bishop NW ? |
||
888 | else if ((to_line > from_line) && (to_column < from_column)) |
||
889 | { |
||
890 | // see if bishop can move NW |
||
891 | for (index_line = from_line + 1, index_column = from_column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--) |
||
892 | if (!CAN_PLAY (index_line, index_column)) |
||
893 | return (false); // if bishop can no longer move this way, stop searching |
||
894 | else if ((index_line == to_line) && (index_column == to_column)) |
||
74 | pmbaty | 895 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 896 | } |
897 | |||
898 | // else do we want to move the bishop SW ? |
||
899 | else if ((to_line < from_line) && (to_column < from_column)) |
||
900 | { |
||
901 | // see if bishop can move SW |
||
902 | for (index_line = from_line - 1, index_column = from_column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--) |
||
903 | if (!CAN_PLAY (index_line, index_column)) |
||
904 | return (false); // if bishop can no longer move this way, stop searching |
||
905 | else if ((index_line == to_line) && (index_column == to_column)) |
||
74 | pmbaty | 906 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 907 | } |
908 | |||
909 | return (false); // this bishop can't move in the claimed way |
||
910 | } |
||
911 | |||
912 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
913 | ///////////////////////////////////////// QUEEN ////////////////////////////////////////// |
||
914 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
915 | // else is it a queen ? |
||
916 | else if (boardslot->part == PART_QUEEN) |
||
917 | { |
||
918 | // quick checks |
||
919 | if ((to_column != from_column) && (to_line != from_line) |
||
920 | && (abs (to_column - from_column) != abs (to_line - from_line))) |
||
921 | return (false); // queens can only move horizontally, vertically or diagonally |
||
74 | pmbaty | 922 | else if (!Move_IsWayClearBetween (move, from_line, from_column, to_line, to_column)) |
923 | return (false); // way must be clear between source and target |
||
1 | pmbaty | 924 | |
925 | // do we want to move that queen vertically ? |
||
926 | if (from_column == to_column) |
||
927 | { |
||
928 | // do we want to move her upwards ? |
||
929 | if (to_line > from_line) |
||
930 | { |
||
931 | // see if queen can move upwards |
||
932 | for (index_line = from_line + 1; index_line < 8; index_line++) |
||
933 | if (!CAN_PLAY (index_line, to_column)) |
||
934 | return (false); // if queen can no longer move this way, stop searching |
||
935 | else if (index_line == to_line) |
||
74 | pmbaty | 936 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 937 | } |
938 | |||
939 | // else do we want to move her downwards ? |
||
940 | else if (to_line < from_line) |
||
941 | { |
||
942 | // see if queen can move downwards |
||
943 | for (index_line = from_line - 1; index_line >= 0; index_line--) |
||
944 | if (!CAN_PLAY (index_line, to_column)) |
||
945 | return (false); // if queen can no longer move this way, stop searching |
||
946 | else if (index_line == to_line) |
||
74 | pmbaty | 947 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 948 | } |
949 | |||
950 | return (false); // this queen can't move in the claimed way |
||
951 | } |
||
952 | |||
953 | // else do we want to move that queen horizontally ? |
||
954 | else if (from_line == to_line) |
||
955 | { |
||
956 | // do we want this queen to move right ? |
||
957 | if (to_column > from_column) |
||
958 | { |
||
959 | // see if queen can move right |
||
960 | for (index_column = from_column + 1; index_column < 8; index_column++) |
||
961 | if (!CAN_PLAY (to_line, index_column)) |
||
962 | return (false); // if queen can no longer move this way, stop searching |
||
963 | else if (index_column == to_column) |
||
74 | pmbaty | 964 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 965 | } |
966 | |||
967 | // else do we want this queen to move left ? |
||
968 | else if (to_column < from_column) |
||
969 | { |
||
970 | // see if queen can move left |
||
971 | for (index_column = from_column - 1; index_column >= 0; index_column--) |
||
972 | if (!CAN_PLAY (to_line, index_column)) |
||
973 | return (false); // if queen can no longer move this way, stop searching |
||
974 | else if (index_column == to_column) |
||
74 | pmbaty | 975 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 976 | } |
977 | |||
978 | return (false); // this queen can't move in the claimed way |
||
979 | } |
||
980 | |||
981 | // else do we want to move the queen NE ? |
||
982 | else if ((to_line > from_line) && (to_column > from_column)) |
||
983 | { |
||
984 | // see if queen can move NE |
||
985 | for (index_line = from_line + 1, index_column = from_column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++) |
||
986 | if (!CAN_PLAY (index_line, index_column)) |
||
987 | return (false); // if queen can no longer move this way, stop searching |
||
988 | else if ((index_line == to_line) && (index_column == to_column)) |
||
74 | pmbaty | 989 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 990 | } |
991 | |||
992 | // else do we want to move the queen SE ? |
||
993 | else if ((to_line < from_line) && (to_column > from_column)) |
||
994 | { |
||
995 | // see if queen can move SE |
||
996 | for (index_line = from_line - 1, index_column = from_column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++) |
||
997 | if (!CAN_PLAY (index_line, index_column)) |
||
998 | return (false); // if queen can no longer move this way, stop searching |
||
999 | else if ((index_line == to_line) && (index_column == to_column)) |
||
74 | pmbaty | 1000 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 1001 | } |
1002 | |||
1003 | // else do we want to move the queen NW ? |
||
1004 | else if ((to_line > from_line) && (to_column < from_column)) |
||
1005 | { |
||
1006 | // see if queen can move NW |
||
1007 | for (index_line = from_line + 1, index_column = from_column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--) |
||
1008 | if (!CAN_PLAY (index_line, index_column)) |
||
1009 | return (false); // if queen can no longer move this way, stop searching |
||
1010 | else if ((index_line == to_line) && (index_column == to_column)) |
||
74 | pmbaty | 1011 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 1012 | } |
1013 | |||
1014 | // else do we want to move the queen SW ? |
||
1015 | else if ((to_line < from_line) && (to_column < from_column)) |
||
1016 | { |
||
1017 | // see if queen can move SW |
||
1018 | for (index_line = from_line - 1, index_column = from_column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--) |
||
1019 | if (!CAN_PLAY (index_line, index_column)) |
||
1020 | return (false); // if queen can no longer move this way, stop searching |
||
1021 | else if ((index_line == to_line) && (index_column == to_column)) |
||
74 | pmbaty | 1022 | return (!Move_IsColorInCheckAfterTestMove (move, from_line, from_column, index_line, index_column, boardslot->color)); // if move is safe for king, then it's possible |
1 | pmbaty | 1023 | } |
1024 | |||
1025 | return (false); // this queen can't move in the claimed way |
||
1026 | } |
||
1027 | |||
1028 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
1029 | ////////////////////////////////////////// KING ////////////////////////////////////////// |
||
1030 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
1031 | // else is it a king ? |
||
1032 | else if (boardslot->part == PART_KING) |
||
1033 | { |
||
1034 | // do we want to move that king in one of the allowed directions ? |
||
1035 | if (((from_line + 1 == to_line) && (from_column == to_column)) // up |
||
1036 | || ((from_line - 1 == to_line) && (from_column == to_column)) // down |
||
1037 | || ((from_line == to_line) && (from_column + 1 == to_column)) // right |
||
1038 | || ((from_line == to_line) && (from_column - 1 == to_column)) // left |
||
1039 | || ((from_line + 1 == to_line) && (from_column + 1 == to_column)) // NE |
||
1040 | || ((from_line - 1 == to_line) && (from_column + 1 == to_column)) // SE |
||
1041 | || ((from_line + 1 == to_line) && (from_column - 1 == to_column)) // NW |
||
1042 | || ((from_line - 1 == to_line) && (from_column - 1 == to_column))) // SW |
||
1043 | { |
||
1044 | if (!CAN_PLAY (to_line, to_column)) |
||
1045 | return (false); // if king can't move there, return false |
||
1046 | else if (Move_IsColorInCheckAfterTestMove (move, from_line, from_column, to_line, to_column, boardslot->color)) |
||
1047 | return (false); // if king would be in check there, return false |
||
1048 | |||
1049 | return (true); // else this move is safe |
||
1050 | } |
||
1051 | |||
1052 | return (false); // if not, this king can't move in the claimed way |
||
1053 | } |
||
1054 | |||
1055 | return (false); // this move is not possible, else we'd have returned earlier |
||
1056 | } |
||
1057 | |||
1058 | |||
1059 | bool Move_FindRandomMove (boardmove_t *move, int color, boardmove_t *random_move) |
||
1060 | { |
||
1061 | // this function returns TRUE if it can find a random move (most of the time blunderous) |
||
1062 | // and sets its coordinates in the given output parameters |
||
1063 | |||
1064 | boardslot_t *boardslot; |
||
1065 | int movement_direction; |
||
1066 | int line; |
||
1067 | int column; |
||
1068 | int index_line; |
||
1069 | int index_column; |
||
1070 | boardmove_t *possiblemoves; // mallocated |
||
1071 | int possiblemove_count; |
||
1072 | int move_index; |
||
1073 | |||
1074 | // assume no possible move until told otherwise |
||
1075 | possiblemoves = NULL; |
||
1076 | possiblemove_count = 0; |
||
1077 | |||
1078 | // cycle through all the board and find our parts |
||
1079 | for (line = 0; line < 8; line++) |
||
1080 | for (column = 0; column < 8; column++) |
||
1081 | { |
||
1082 | boardslot = &move->slots[line][column]; // quick access to grid slot |
||
1083 | |||
1084 | if ((boardslot->part == PART_NONE) || (boardslot->color != color)) |
||
1085 | continue; // if this location is empty or not ours, we aren't interested in it |
||
1086 | |||
1087 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
1088 | ////////////////////////////////////////// PAWN ////////////////////////////////////////// |
||
1089 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
1090 | // is it a pawn ? |
||
1091 | if (boardslot->part == PART_PAWN) |
||
1092 | { |
||
1093 | // figure out movement direction |
||
1094 | if (boardslot->color == COLOR_WHITE) |
||
1095 | movement_direction = 1; |
||
1096 | else |
||
1097 | movement_direction = -1; |
||
1098 | |||
1099 | // see if pawn can move forward |
||
1100 | if ((((movement_direction == 1) && (line < 7)) || ((movement_direction == -1) && (line > 0))) |
||
1101 | && (move->slots[line + movement_direction][column].part == PART_NONE) // target slot free |
||
1102 | && !Move_IsColorInCheckAfterTestMove (move, line, column, line + movement_direction, column, color)) |
||
1103 | { |
||
1104 | if (((movement_direction == 1) && (line + movement_direction == 7)) |
||
1105 | || ((movement_direction == -1) && (line + movement_direction == 0))) |
||
1106 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_PAWN, line, column, line + movement_direction, column, PART_QUEEN, false, false); // save promotional move |
||
1107 | else |
||
1108 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_PAWN, line, column, line + movement_direction, column, PART_NONE, false, false); // save possible move |
||
1109 | } |
||
1110 | |||
1111 | // see if pawn can take a piece on its left |
||
1112 | if ((((movement_direction == 1) && (line < 7)) || ((movement_direction == -1) && (line > 0))) |
||
1113 | && (column > 0) // has room |
||
1114 | && (move->slots[line + movement_direction][column - 1].color != color) // target slot NOT our color |
||
1115 | && (move->slots[line + movement_direction][column - 1].part != PART_NONE) // target slot occupied |
||
1116 | && !Move_IsColorInCheckAfterTestMove (move, line, column, line + movement_direction, column - 1, color)) |
||
1117 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_PAWN, line, column, line + movement_direction, column - 1, PART_NONE, true, false); // save possible move |
||
1118 | |||
1119 | // see if pawn can take a piece on its right |
||
1120 | if ((((movement_direction == 1) && (line < 7)) || ((movement_direction == -1) && (line > 0))) |
||
1121 | && (column < 7) // has room |
||
1122 | && (move->slots[line + movement_direction][column + 1].color != color) // target slot NOT our color |
||
1123 | && (move->slots[line + movement_direction][column + 1].part != PART_NONE) // target slot occupied |
||
1124 | && !Move_IsColorInCheckAfterTestMove (move, line, column, line + movement_direction, column + 1, color)) |
||
1125 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_PAWN, line, column, line + movement_direction, column + 1, PART_NONE, true, false); // save possible move |
||
1126 | |||
1127 | // if previous move was a pawn rush, see if pawn can take "en passant" |
||
1128 | if ((move->part == PART_PAWN) // last move was a pawn |
||
1129 | && (move->target[1] == move->source[1]) // pawn moved in column |
||
1130 | && (abs (move->target[0] - move->source[0]) == 2) // pawn rushed |
||
1131 | && (move->target[0] == line) // pawn is in line with us |
||
1132 | && (move->target[1] - column == -1) // pawn is left to us |
||
1133 | && !Move_IsColorInCheckAfterTestMoveEP (move, line, column, line + movement_direction, column - 1, move->target[0], move->target[1], color)) |
||
1134 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_PAWN, line, column, line + movement_direction, column - 1, PART_NONE, true, true); // save possible move |
||
1135 | if ((move->part == PART_PAWN) // last move was a pawn |
||
1136 | && (move->target[1] == move->source[1]) // pawn moved in column |
||
1137 | && (abs (move->target[0] - move->source[0]) == 2) // pawn rushed |
||
1138 | && (move->target[0] == line) // pawn is in line with us |
||
1139 | && (move->target[1] - column == 1) // pawn is right to us |
||
1140 | && !Move_IsColorInCheckAfterTestMoveEP (move, line, column, line + movement_direction, column + 1, move->target[0], move->target[1], color)) |
||
1141 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_PAWN, line, column, line + movement_direction, column + 1, PART_NONE, true, true); // save possible move |
||
1142 | } |
||
1143 | |||
1144 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
1145 | ////////////////////////////////////////// ROOK ////////////////////////////////////////// |
||
1146 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
1147 | // else is it a rook ? |
||
1148 | else if (boardslot->part == PART_ROOK) |
||
1149 | { |
||
1150 | // see if rook can move upwards |
||
1151 | for (index_line = line + 1; index_line < 8; index_line++) |
||
1152 | if (!CAN_PLAY (index_line, column)) |
||
1153 | break; // if part can no longer move this way, stop searching |
||
1154 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color)) |
||
1155 | { |
||
1156 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_ROOK, line, column, index_line, column, PART_NONE, (move->slots[index_line][column].part != PART_NONE), false); // save possible move |
||
1157 | if (move->slots[index_line][column].part != PART_NONE) |
||
1158 | break; // this move is possible, but no further moves are possible in the same direction |
||
1159 | } |
||
1160 | |||
1161 | // see if rook can move downwards |
||
1162 | for (index_line = line - 1; index_line >= 0; index_line--) |
||
1163 | if (!CAN_PLAY (index_line, column)) |
||
1164 | break; // if part can no longer move this way, stop searching |
||
1165 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color)) |
||
1166 | { |
||
1167 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_ROOK, line, column, index_line, column, PART_NONE, (move->slots[index_line][column].part != PART_NONE), false); // save possible move |
||
1168 | if (move->slots[index_line][column].part != PART_NONE) |
||
1169 | break; // this move is possible, but no further moves are possible in the same direction |
||
1170 | } |
||
1171 | |||
1172 | // see if rook can move right |
||
1173 | for (index_column = column + 1; index_column < 8; index_column++) |
||
1174 | if (!CAN_PLAY (line, index_column)) |
||
1175 | break; // if part can no longer move this way, stop searching |
||
1176 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color)) |
||
1177 | { |
||
1178 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_ROOK, line, column, line, index_column, PART_NONE, (move->slots[line][index_column].part != PART_NONE), false); // save possible move |
||
1179 | if (move->slots[line][index_column].part != PART_NONE) |
||
1180 | break; // this move is possible, but no further moves are possible in the same direction |
||
1181 | } |
||
1182 | |||
1183 | // see if rook can move left |
||
1184 | for (index_column = column - 1; index_column >= 0; index_column--) |
||
1185 | if (!CAN_PLAY (line, index_column)) |
||
1186 | break; // if part can no longer move this way, stop searching |
||
1187 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color)) |
||
1188 | { |
||
1189 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_ROOK, line, column, line, index_column, PART_NONE, (move->slots[line][index_column].part != PART_NONE), false); // save possible move |
||
1190 | if (move->slots[line][index_column].part != PART_NONE) |
||
1191 | break; // this move is possible, but no further moves are possible in the same direction |
||
1192 | } |
||
1193 | } |
||
1194 | |||
1195 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
1196 | ///////////////////////////////////////// KNIGHT ///////////////////////////////////////// |
||
1197 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
1198 | // else is it a knight ? |
||
1199 | else if (boardslot->part == PART_KNIGHT) |
||
1200 | { |
||
1201 | // see if knight can move NNW |
||
1202 | if (CAN_PLAY (line + 2, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 2, column - 1, color)) |
||
1203 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line + 2, column - 1, PART_NONE, (move->slots[line + 2][column - 1].part != PART_NONE), false); // save possible move |
||
1204 | |||
1205 | // see if knight can move NNE |
||
1206 | if (CAN_PLAY (line + 2, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 2, column + 1, color)) |
||
1207 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line + 2, column + 1, PART_NONE, (move->slots[line + 2][column + 1].part != PART_NONE), false); // save possible move |
||
1208 | |||
1209 | // see if knight can move ENE |
||
1210 | if (CAN_PLAY (line + 1, column + 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column + 2, color)) |
||
1211 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line + 1, column + 2, PART_NONE, (move->slots[line + 1][column + 2].part != PART_NONE), false); // save possible move |
||
1212 | |||
1213 | // see if knight can move ESE |
||
1214 | if (CAN_PLAY (line - 1, column + 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column + 2, color)) |
||
1215 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line - 1, column + 2, PART_NONE, (move->slots[line - 1][column + 2].part != PART_NONE), false); // save possible move |
||
1216 | |||
1217 | // see if knight can move SSW |
||
1218 | if (CAN_PLAY (line - 2, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 2, column - 1, color)) |
||
1219 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line - 2, column - 1, PART_NONE, (move->slots[line - 2][column - 1].part != PART_NONE), false); // save possible move |
||
1220 | |||
1221 | // see if knight can move SSE |
||
1222 | if (CAN_PLAY (line - 2, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 2, column + 1, color)) |
||
1223 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line - 2, column + 1, PART_NONE, (move->slots[line - 2][column + 1].part != PART_NONE), false); // save possible move |
||
1224 | |||
1225 | // see if knight can move WNW |
||
1226 | if (CAN_PLAY (line + 1, column - 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column - 2, color)) |
||
1227 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line + 1, column - 2, PART_NONE, (move->slots[line + 1][column - 2].part != PART_NONE), false); // save possible move |
||
1228 | |||
1229 | // see if knight can move WSW |
||
1230 | if (CAN_PLAY (line - 1, column - 2) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column - 2, color)) |
||
1231 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KNIGHT, line, column, line - 1, column - 2, PART_NONE, (move->slots[line - 1][column - 2].part != PART_NONE), false); // save possible move |
||
1232 | } |
||
1233 | |||
1234 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
1235 | ///////////////////////////////////////// BISHOP ///////////////////////////////////////// |
||
1236 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
1237 | // else is it a bishop ? |
||
1238 | else if (boardslot->part == PART_BISHOP) |
||
1239 | { |
||
1240 | // see if bishop can move NE |
||
1241 | for (index_line = line + 1, index_column = column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++) |
||
1242 | if (!CAN_PLAY (index_line, index_column)) |
||
1243 | break; // if part can no longer move this way, stop searching |
||
1244 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
1245 | { |
||
1246 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_BISHOP, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move |
||
1247 | if (move->slots[index_line][index_column].part != PART_NONE) |
||
1248 | break; // this move is possible, but no further moves are possible in the same direction |
||
1249 | } |
||
1250 | |||
1251 | // see if bishop can move SE |
||
1252 | for (index_line = line - 1, index_column = column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++) |
||
1253 | if (!CAN_PLAY (index_line, index_column)) |
||
1254 | break; // if part can no longer move this way, stop searching |
||
1255 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
1256 | { |
||
1257 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_BISHOP, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move |
||
1258 | if (move->slots[index_line][index_column].part != PART_NONE) |
||
1259 | break; // this move is possible, but no further moves are possible in the same direction |
||
1260 | } |
||
1261 | |||
1262 | // see if bishop can move NW |
||
1263 | for (index_line = line + 1, index_column = column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--) |
||
1264 | if (!CAN_PLAY (index_line, index_column)) |
||
1265 | break; // if part can no longer move this way, stop searching |
||
1266 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
1267 | { |
||
1268 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_BISHOP, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move |
||
1269 | if (move->slots[index_line][index_column].part != PART_NONE) |
||
1270 | break; // this move is possible, but no further moves are possible in the same direction |
||
1271 | } |
||
1272 | |||
1273 | // see if bishop can move SW |
||
1274 | for (index_line = line - 1, index_column = column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--) |
||
1275 | if (!CAN_PLAY (index_line, index_column)) |
||
1276 | break; // if part can no longer move this way, stop searching |
||
1277 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
1278 | { |
||
1279 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_BISHOP, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move |
||
1280 | if (move->slots[index_line][index_column].part != PART_NONE) |
||
1281 | break; // this move is possible, but no further moves are possible in the same direction |
||
1282 | } |
||
1283 | } |
||
1284 | |||
1285 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
1286 | ///////////////////////////////////////// QUEEN ////////////////////////////////////////// |
||
1287 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
1288 | // else is it a queen ? |
||
1289 | else if (boardslot->part == PART_QUEEN) |
||
1290 | { |
||
1291 | // see if queen can move upwards |
||
1292 | for (index_line = line + 1; index_line < 8; index_line++) |
||
1293 | if (!CAN_PLAY (index_line, column)) |
||
1294 | break; // if part can no longer move this way, stop searching |
||
1295 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color)) |
||
1296 | { |
||
1297 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, index_line, column, PART_NONE, (move->slots[index_line][column].part != PART_NONE), false); // save possible move |
||
1298 | if (move->slots[index_line][column].part != PART_NONE) |
||
1299 | break; // this move is possible, but no further moves are possible in the same direction |
||
1300 | } |
||
1301 | |||
1302 | // see if queen can move downwards |
||
1303 | for (index_line = line - 1; index_line >= 0; index_line--) |
||
1304 | if (!CAN_PLAY (index_line, column)) |
||
1305 | break; // if part can no longer move this way, stop searching |
||
1306 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, column, color)) |
||
1307 | { |
||
1308 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, index_line, column, PART_NONE, (move->slots[index_line][column].part != PART_NONE), false); // save possible move |
||
1309 | if (move->slots[index_line][column].part != PART_NONE) |
||
1310 | break; // this move is possible, but no further moves are possible in the same direction |
||
1311 | } |
||
1312 | |||
1313 | // see if queen can move right |
||
1314 | for (index_column = column + 1; index_column < 8; index_column++) |
||
1315 | if (!CAN_PLAY (line, index_column)) |
||
1316 | break; // if part can no longer move this way, stop searching |
||
1317 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color)) |
||
1318 | { |
||
1319 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, line, index_column, PART_NONE, (move->slots[line][index_column].part != PART_NONE), false); // save possible move |
||
1320 | if (move->slots[line][index_column].part != PART_NONE) |
||
1321 | break; // this move is possible, but no further moves are possible in the same direction |
||
1322 | } |
||
1323 | |||
1324 | // see if queen can move left |
||
1325 | for (index_column = column - 1; index_column >= 0; index_column--) |
||
1326 | if (!CAN_PLAY (line, index_column)) |
||
1327 | break; // if part can no longer move this way, stop searching |
||
1328 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, line, index_column, color)) |
||
1329 | { |
||
1330 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, line, index_column, PART_NONE, (move->slots[line][index_column].part != PART_NONE), false); // save possible move |
||
1331 | if (move->slots[line][index_column].part != PART_NONE) |
||
1332 | break; // this move is possible, but no further moves are possible in the same direction |
||
1333 | } |
||
1334 | |||
1335 | // see if queen can move NE |
||
1336 | for (index_line = line + 1, index_column = column + 1; (index_line < 8) && (index_column < 8); index_line++, index_column++) |
||
1337 | if (!CAN_PLAY (index_line, index_column)) |
||
1338 | break; // if part can no longer move this way, stop searching |
||
1339 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
1340 | { |
||
1341 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move |
||
1342 | if (move->slots[index_line][index_column].part != PART_NONE) |
||
1343 | break; // this move is possible, but no further moves are possible in the same direction |
||
1344 | } |
||
1345 | |||
1346 | // see if queen can move SE |
||
1347 | for (index_line = line - 1, index_column = column + 1; (index_line >= 0) && (index_column < 8); index_line--, index_column++) |
||
1348 | if (!CAN_PLAY (index_line, index_column)) |
||
1349 | break; // if part can no longer move this way, stop searching |
||
1350 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
1351 | { |
||
1352 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move |
||
1353 | if (move->slots[index_line][index_column].part != PART_NONE) |
||
1354 | break; // this move is possible, but no further moves are possible in the same direction |
||
1355 | } |
||
1356 | |||
1357 | // see if queen can move NW |
||
1358 | for (index_line = line + 1, index_column = column - 1; (index_line < 8) && (index_column >= 0); index_line++, index_column--) |
||
1359 | if (!CAN_PLAY (index_line, index_column)) |
||
1360 | break; // if part can no longer move this way, stop searching |
||
1361 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
1362 | { |
||
1363 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move |
||
1364 | if (move->slots[index_line][index_column].part != PART_NONE) |
||
1365 | break; // this move is possible, but no further moves are possible in the same direction |
||
1366 | } |
||
1367 | |||
1368 | // see if queen can move SW |
||
1369 | for (index_line = line - 1, index_column = column - 1; (index_line >= 0) && (index_column >= 0); index_line--, index_column--) |
||
1370 | if (!CAN_PLAY (index_line, index_column)) |
||
1371 | break; // if part can no longer move this way, stop searching |
||
1372 | else if (!Move_IsColorInCheckAfterTestMove (move, line, column, index_line, index_column, color)) |
||
1373 | { |
||
1374 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_QUEEN, line, column, index_line, index_column, PART_NONE, (move->slots[index_line][index_column].part != PART_NONE), false); // save possible move |
||
1375 | if (move->slots[index_line][index_column].part != PART_NONE) |
||
1376 | break; // this move is possible, but no further moves are possible in the same direction |
||
1377 | } |
||
1378 | } |
||
1379 | |||
1380 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
1381 | ////////////////////////////////////////// KING ////////////////////////////////////////// |
||
1382 | ////////////////////////////////////////////////////////////////////////////////////////// |
||
1383 | // else is it a king ? |
||
1384 | else if (boardslot->part == PART_KING) |
||
1385 | { |
||
1386 | // see if king can move up |
||
1387 | if (CAN_PLAY (line + 1, column) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column, color)) |
||
1388 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line + 1, column, PART_NONE, (move->slots[line + 1][column].part != PART_NONE), false); // save possible move |
||
1389 | |||
1390 | // see if king can move down |
||
1391 | if (CAN_PLAY (line - 1, column) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column, color)) |
||
1392 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line - 1, column, PART_NONE, (move->slots[line - 1][column].part != PART_NONE), false); // save possible move |
||
1393 | |||
1394 | // see if king can move right |
||
1395 | if (CAN_PLAY (line, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line, column + 1, color)) |
||
1396 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line, column + 1, PART_NONE, (move->slots[line][column + 1].part != PART_NONE), false); // save possible move |
||
1397 | |||
1398 | // see if king can move left |
||
1399 | if (CAN_PLAY (line, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line, column - 1, color)) |
||
1400 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line, column - 1, PART_NONE, (move->slots[line][column - 1].part != PART_NONE), false); // save possible move |
||
1401 | |||
1402 | // see if king can move NE |
||
1403 | if (CAN_PLAY (line + 1, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column + 1, color)) |
||
1404 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line + 1, column + 1, PART_NONE, (move->slots[line + 1][column + 1].part != PART_NONE), false); // save possible move |
||
1405 | |||
1406 | // see if king can move SE |
||
1407 | if (CAN_PLAY (line - 1, column + 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column + 1, color)) |
||
1408 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line - 1, column + 1, PART_NONE, (move->slots[line - 1][column + 1].part != PART_NONE), false); // save possible move |
||
1409 | |||
1410 | // see if king can move NW |
||
1411 | if (CAN_PLAY (line + 1, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line + 1, column - 1, color)) |
||
1412 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line + 1, column - 1, PART_NONE, (move->slots[line + 1][column - 1].part != PART_NONE), false); // save possible move |
||
1413 | |||
1414 | // see if king can move SW |
||
1415 | if (CAN_PLAY (line - 1, column - 1) && !Move_IsColorInCheckAfterTestMove (move, line, column, line - 1, column - 1, color)) |
||
1416 | AddPossibleMove (&possiblemoves, &possiblemove_count, boardslot->color, PART_KING, line, column, line - 1, column - 1, PART_NONE, (move->slots[line - 1][column - 1].part != PART_NONE), false); // save possible move |
||
1417 | } |
||
1418 | } |
||
1419 | |||
1420 | // now that all the table has been parsed, see if we have some possible moves |
||
1421 | |||
1422 | if (possiblemove_count == 0) |
||
1423 | return (false); // if none, return FALSE (it means that we are stalemate, but there's a faster function to check that) |
||
1424 | |||
1425 | move_index = rand () % possiblemove_count; // select a possible move at random |
||
1426 | memcpy (random_move, &possiblemoves[move_index], sizeof (boardmove_t)); // copy it into destination variable |
||
1427 | |||
1428 | SAFE_free ((void **) &possiblemoves); // free the possible moves array, we no longer need them |
||
1429 | return (true); // we did find some possible moves |
||
1430 | } |
||
1431 | |||
1432 | |||
1433 | int Move_CountPartsByColorAndType (boardmove_t *move, int color, int part_type) |
||
1434 | { |
||
1435 | // this function returns the amount of parts of the specified color and type left on board |
||
1436 | |||
1437 | int line; |
||
1438 | int column; |
||
1439 | int count; |
||
1440 | |||
1441 | count = 0; // assume none so far |
||
1442 | |||
1443 | // cycle through all the board... |
||
1444 | for (line = 0; line < 8; line++) |
||
1445 | for (column = 0; column < 8; column++) |
||
1446 | if ((move->slots[line][column].color == color) && (move->slots[line][column].part == part_type)) |
||
1447 | count++; // sum up all the parts of the same colour and type we find |
||
1448 | |||
1449 | return (count); // and return their quantity |
||
1450 | } |
||
1451 | |||
1452 | |||
1453 | bool Move_IsColorInCheckAfterTestMove (boardmove_t *move, int source_line, int source_column, int target_line, int target_column, int color) |
||
1454 | { |
||
1455 | // helper function to play a test move on a temporary board (which must have been previously allocated) |
||
1456 | |||
1457 | static boardmove_t temp_move; // declare this static so as not to allocate/free it continuously |
||
1458 | |||
1459 | memcpy (temp_move.slots, move->slots, sizeof (move->slots)); // have a copy of the table, then make the move |
||
1460 | memcpy (&temp_move.slots[target_line][target_column], &temp_move.slots[source_line][source_column], sizeof (boardslot_t)); |
||
1461 | memset (&temp_move.slots[source_line][source_column], 0, sizeof (boardslot_t)); // erase the source slot |
||
1462 | |||
1463 | return (Move_IsCheck (&temp_move, color)); // return whether the final board has the given color in check |
||
1464 | } |
||
1465 | |||
1466 | |||
1467 | bool Move_IsColorInCheckAfterTestMoveEP (boardmove_t *move, int source_line, int source_column, int target_line, int target_column, int clear_line, int clear_column, int color) |
||
1468 | { |
||
1469 | // helper function to play a test move on a temporary board (which must have been previously allocated) |
||
1470 | // En Passant version -- cleans the specified target before testing |
||
1471 | |||
1472 | static boardmove_t temp_move; // declare this static so as not to allocate/free it continuously |
||
1473 | |||
1474 | memcpy (temp_move.slots, move->slots, sizeof (move->slots)); // have a copy of the table, then make the move |
||
1475 | memcpy (&temp_move.slots[target_line][target_column], &temp_move.slots[source_line][source_column], sizeof (boardslot_t)); |
||
1476 | memset (&temp_move.slots[source_line][source_column], 0, sizeof (boardslot_t)); // erase the source slot |
||
1477 | |||
1478 | memset (&temp_move.slots[clear_line][clear_column], 0, sizeof (boardslot_t)); // erase the "en passant" target |
||
1479 | |||
1480 | return (Move_IsCheck (&temp_move, color)); // return whether the final board has the given color in check |
||
1481 | } |
||
1482 | |||
1483 | |||
1484 | void Move_DescribeInFEN (boardmove_t *move) |
||
1485 | { |
||
1486 | // convert a board and its part placements into a Forsyth Edwards notation, writing in the fen_string buffer |
||
1487 | |||
1488 | boardslot_t *slot; |
||
1489 | int line; |
||
1490 | int column; |
||
1491 | int free_slots; |
||
1492 | int length; |
||
1493 | |||
1494 | // first reset the string |
||
1495 | move->fen_string[0] = 0; |
||
1496 | |||
1497 | //////////////////////////////////////////////////////// |
||
1498 | // first part of the FEN notation is the parts placement |
||
1499 | |||
1500 | // cycle through each column, line after line, starting up left and going downwards right |
||
1501 | for (line = 7; line >= 0; line--) |
||
1502 | { |
||
1503 | free_slots = 0; // no free slot in that line yet |
||
1504 | |||
1505 | for (column = 0; column < 8; column++) |
||
1506 | { |
||
1507 | slot = &move->slots[line][column]; // quick access to current slot |
||
1508 | |||
1509 | if (slot->part == PART_ROOK) |
||
1510 | { |
||
1511 | // if there are free slots to mention, do it |
||
1512 | if (free_slots > 0) |
||
1513 | { |
||
1514 | length = wcslen (move->fen_string); // append the free slots count |
||
1515 | swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", free_slots); |
||
1516 | free_slots = 0; // reset the free slots count |
||
1517 | } |
||
1518 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), (slot->color == COLOR_BLACK ? L"r" : (slot->color == COLOR_WHITE ? L"R": L"?"))); |
||
1519 | } |
||
1520 | else if (slot->part == PART_KNIGHT) |
||
1521 | { |
||
1522 | // if there are free slots to mention, do it |
||
1523 | if (free_slots > 0) |
||
1524 | { |
||
1525 | length = wcslen (move->fen_string); // append the free slots count |
||
1526 | swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", free_slots); |
||
1527 | free_slots = 0; // reset the free slots count |
||
1528 | } |
||
1529 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), (slot->color == COLOR_BLACK ? L"n" : (slot->color == COLOR_WHITE ? L"N": L"?"))); |
||
1530 | } |
||
1531 | else if (slot->part == PART_BISHOP) |
||
1532 | { |
||
1533 | // if there are free slots to mention, do it |
||
1534 | if (free_slots > 0) |
||
1535 | { |
||
1536 | length = wcslen (move->fen_string); // append the free slots count |
||
1537 | swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", free_slots); |
||
1538 | free_slots = 0; // reset the free slots count |
||
1539 | } |
||
1540 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), (slot->color == COLOR_BLACK ? L"b" : (slot->color == COLOR_WHITE ? L"B": L"?"))); |
||
1541 | } |
||
1542 | else if (slot->part == PART_QUEEN) |
||
1543 | { |
||
1544 | // if there are free slots to mention, do it |
||
1545 | if (free_slots > 0) |
||
1546 | { |
||
1547 | length = wcslen (move->fen_string); // append the free slots count |
||
1548 | swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", free_slots); |
||
1549 | free_slots = 0; // reset the free slots count |
||
1550 | } |
||
1551 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), (slot->color == COLOR_BLACK ? L"q" : (slot->color == COLOR_WHITE ? L"Q": L"?"))); |
||
1552 | } |
||
1553 | else if (slot->part == PART_KING) |
||
1554 | { |
||
1555 | // if there are free slots to mention, do it |
||
1556 | if (free_slots > 0) |
||
1557 | { |
||
1558 | length = wcslen (move->fen_string); // append the free slots count |
||
1559 | swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", free_slots); |
||
1560 | free_slots = 0; // reset the free slots count |
||
1561 | } |
||
1562 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), (slot->color == COLOR_BLACK ? L"k" : (slot->color == COLOR_WHITE ? L"K": L"?"))); |
||
1563 | } |
||
1564 | else if (slot->part == PART_PAWN) |
||
1565 | { |
||
1566 | // if there are free slots to mention, do it |
||
1567 | if (free_slots > 0) |
||
1568 | { |
||
1569 | length = wcslen (move->fen_string); // append the free slots count |
||
1570 | swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", free_slots); |
||
1571 | free_slots = 0; // reset the free slots count |
||
1572 | } |
||
1573 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), (slot->color == COLOR_BLACK ? L"p" : (slot->color == COLOR_WHITE ? L"P": L"?"))); |
||
1574 | } |
||
1575 | else |
||
1576 | free_slots++; // we found one free slot more |
||
1577 | |||
1578 | // are we at the end of a line ? |
||
1579 | if (column == 7) |
||
44 | pmbaty | 1580 | { |
1581 | // if there are free slots to mention, do it |
||
1582 | if (free_slots > 0) |
||
1583 | { |
||
1584 | length = wcslen (move->fen_string); // append the free slots count |
||
1585 | swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", free_slots); |
||
1586 | free_slots = 0; // reset the free slots count |
||
1587 | } |
||
1588 | if (line > 0) |
||
1589 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"/"); // at the end of each line, drop a slash (except on the last line) |
||
1590 | } |
||
1 | pmbaty | 1591 | } |
1592 | } |
||
1593 | |||
1594 | ////////////////////////////////////////////////////// |
||
1595 | // second part of the FEN notation is the side on move |
||
1596 | |||
1597 | // deduce the side to move according to last move's color |
||
1598 | if (move->color == COLOR_WHITE) |
||
1599 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L" b"); // black to move |
||
1600 | else |
||
1601 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L" w"); // white to move (this also catches the beginning of a game) |
||
1602 | |||
1603 | /////////////////////////////////////////////////////////////// |
||
1604 | // third part of the FEN notation is the castling possibilities |
||
1605 | |||
1606 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L" "); |
||
1607 | if (!(move->sides[COLOR_BLACK].longcastle_allowed | move->sides[COLOR_WHITE].longcastle_allowed | move->sides[COLOR_BLACK].shortcastle_allowed | move->sides[COLOR_WHITE].shortcastle_allowed)) |
||
1608 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"-"); // neither side can castle |
||
1609 | else |
||
1610 | { |
||
1611 | if (move->sides[COLOR_WHITE].shortcastle_allowed) |
||
1612 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"K"); // white can castle kingside |
||
1613 | if (move->sides[COLOR_WHITE].longcastle_allowed) |
||
1614 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"Q"); // white can castle queenside |
||
1615 | if (move->sides[COLOR_BLACK].shortcastle_allowed) |
||
1616 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"k"); // black can castle kingside |
||
1617 | if (move->sides[COLOR_BLACK].longcastle_allowed) |
||
1618 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"q"); // black can castle queenside |
||
1619 | } |
||
1620 | |||
1621 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
||
1622 | // fourth part of the FEN notation is the optional position for a pawn that can be taken en passant |
||
1623 | |||
40 | pmbaty | 1624 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L" "); // spacer |
1625 | |||
1 | pmbaty | 1626 | if ((move->part == PART_PAWN) // last move was a pawn |
1627 | && (move->target[1] == move->source[1]) // pawn moved in column |
||
1628 | && (abs (move->target[0] - move->source[0]) == 2)) // pawn rushed |
||
1629 | { |
||
1630 | // column |
||
1631 | if (move->source[1] == 0) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"a"); |
||
1632 | else if (move->source[1] == 1) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"b"); |
||
1633 | else if (move->source[1] == 2) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"c"); |
||
1634 | else if (move->source[1] == 3) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"d"); |
||
1635 | else if (move->source[1] == 4) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"e"); |
||
1636 | else if (move->source[1] == 5) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"f"); |
||
1637 | else if (move->source[1] == 6) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"g"); |
||
1638 | else if (move->source[1] == 7) wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"h"); |
||
1639 | else wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"?"); |
||
1640 | |||
1641 | // line (it's the line the pawn would be on if it had made a "normal" move) |
||
1642 | length = wcslen (move->fen_string); |
||
1643 | swprintf_s (&move->fen_string[length], WCHAR_SIZEOF (move->fen_string) - length, L"%d", 1 + (move->target[0] + move->source[0]) / 2); |
||
1644 | } |
||
40 | pmbaty | 1645 | else |
1646 | wcscat_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), L"-"); // last move was not a pawn rush |
||
1 | pmbaty | 1647 | |
1648 | return; // finished |
||
1649 | } |
||
1650 | |||
1651 | |||
1652 | bool Move_SetupFromFEN (boardmove_t *move, wchar_t *fen_string) |
||
1653 | { |
||
1654 | // this function sets up the given board according to the Forsyth-Edwards description fen_string makes of it |
||
1655 | |||
1656 | // FIXME : load fen, then load PGN, then back arrow. |
||
1657 | |||
1658 | int char_index; |
||
1659 | int length; |
||
1660 | int current_line; |
||
1661 | int current_column; |
||
1662 | int enpassant_line; |
||
1663 | int enpassant_column; |
||
1664 | |||
1665 | // reset the chess grid |
||
1666 | memset (&move->slots, 0, sizeof (move->slots)); |
||
1667 | |||
1668 | // reset the taken pieces for both sides |
||
1669 | SAFE_free ((void **) &move->sides[COLOR_WHITE].takenparts); // release memory space |
||
1670 | move->sides[COLOR_WHITE].takenpart_count = 0; |
||
1671 | SAFE_free ((void **) &move->sides[COLOR_BLACK].takenparts); // release memory space |
||
1672 | move->sides[COLOR_BLACK].takenpart_count = 0; |
||
1673 | |||
1674 | // reset the moves array comments and the moves array itself |
||
1675 | SAFE_free ((void **) &move->comment); |
||
1676 | |||
1677 | // DISallow both sides to castle, until told otherwise |
||
1678 | move->sides[COLOR_WHITE].shortcastle_allowed = false; |
||
1679 | move->sides[COLOR_WHITE].longcastle_allowed = false; |
||
1680 | move->sides[COLOR_BLACK].shortcastle_allowed = false; |
||
1681 | move->sides[COLOR_BLACK].longcastle_allowed = false; |
||
1682 | |||
1683 | // get the length of the FEN string |
||
1684 | length = wcslen (fen_string); |
||
1685 | |||
1686 | // now parse the board from top left to bottom right, placing parts on the fly |
||
1687 | current_line = 7; |
||
1688 | current_column = 0; |
||
1689 | for (char_index = 0; char_index < length; char_index++) |
||
1690 | { |
||
1691 | // is it a number ? |
||
1692 | if (iswdigit (fen_string[char_index])) |
||
1693 | { |
||
1694 | current_column += _wtoi (&fen_string[char_index]); // skip as many columns as needed |
||
1695 | if (current_column > 8) |
||
1696 | return (false); // consistency check: something's wrong with this notation, return FALSE |
||
1697 | } |
||
1698 | |||
1699 | // else is it a line skip ? |
||
1700 | else if (fen_string[char_index] == L'/') |
||
1701 | { |
||
1702 | // were we reading the last line ? |
||
1703 | if (current_line == 0) |
||
1704 | { |
||
1705 | char_index++; // skip this character |
||
1706 | break; // stop reading parts placement |
||
1707 | } |
||
1708 | |||
1709 | current_line--; // proceed to next line, decrescending |
||
1710 | current_column = 0; // and begin at the first column on that line |
||
1711 | } |
||
1712 | |||
1713 | // else is it a blank space ? meaning parts have been read |
||
1714 | else if (fen_string[char_index] == L' ') |
||
1715 | break; // stop reading parts placement |
||
1716 | |||
1717 | // else it's a part. Check first if the current line/column is valid |
||
1718 | else if (IS_VALID (current_line, current_column)) |
||
1719 | { |
||
1720 | if (fen_string[char_index] == L'r') |
||
1721 | Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_ROOK); // black rook |
||
1722 | else if (fen_string[char_index] == L'R') |
||
1723 | Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_ROOK); // white rook |
||
1724 | else if (fen_string[char_index] == L'n') |
||
1725 | Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_KNIGHT); // black knight |
||
1726 | else if (fen_string[char_index] == L'N') |
||
1727 | Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_KNIGHT); // white knight |
||
1728 | else if (fen_string[char_index] == L'b') |
||
1729 | Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_BISHOP); // black bishop |
||
1730 | else if (fen_string[char_index] == L'B') |
||
1731 | Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_BISHOP); // white bishop |
||
1732 | else if (fen_string[char_index] == L'q') |
||
1733 | Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_QUEEN); // black queen |
||
1734 | else if (fen_string[char_index] == L'Q') |
||
1735 | Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_QUEEN); // white queen |
||
1736 | else if (fen_string[char_index] == L'k') |
||
1737 | Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_KING); // black king |
||
1738 | else if (fen_string[char_index] == L'K') |
||
1739 | Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_KING); // white king |
||
1740 | else if (fen_string[char_index] == L'p') |
||
1741 | Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_PAWN); // black pawn |
||
1742 | else if (fen_string[char_index] == L'P') |
||
1743 | Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_PAWN); // white pawn |
||
1744 | |||
1745 | current_column++; // proceed to next column |
||
1746 | } |
||
1747 | else |
||
1748 | return (false); // invalid position, something's wrong with this notation, return FALSE |
||
1749 | } |
||
1750 | |||
1751 | // a space has been reached: next thing to read is the side on move |
||
1752 | char_index++; |
||
1753 | if (char_index >= length) |
||
1754 | return (false); // consistency check: something's wrong with this notation, return FALSE |
||
1755 | |||
1756 | if (towlower (fen_string[char_index]) == L'w') |
||
1757 | move->color = COLOR_BLACK; // white to move |
||
1758 | else if (towlower (fen_string[char_index]) == L'b') |
||
1759 | move->color = COLOR_WHITE; // black to move |
||
1760 | else |
||
1761 | return (false); // consistency check: something's wrong with this notation, return FALSE |
||
1762 | |||
1763 | // there should be a space after this |
||
1764 | char_index++; |
||
1765 | if ((char_index >= length) || (fen_string[char_index] != L' ')) |
||
1766 | return (false); // consistency check: something's wrong with this notation, return FALSE |
||
1767 | |||
1768 | // a space has been reached: next thing to read is the castling possibilities |
||
1769 | char_index++; |
||
1770 | if (char_index >= length) |
||
1771 | return (false); // consistency check: something's wrong with this notation, return FALSE |
||
1772 | for (; char_index < length; char_index++) |
||
1773 | { |
||
1774 | if (fen_string[char_index] == L'k') |
||
1775 | move->sides[COLOR_BLACK].shortcastle_allowed = true; // short castling allowed for black |
||
1776 | else if (fen_string[char_index] == L'K') |
||
1777 | move->sides[COLOR_WHITE].shortcastle_allowed = true; // short castling allowed for white |
||
1778 | else if (fen_string[char_index] == L'q') |
||
1779 | move->sides[COLOR_BLACK].longcastle_allowed = true; // long castling allowed for black |
||
1780 | else if (fen_string[char_index] == L'Q') |
||
1781 | move->sides[COLOR_WHITE].longcastle_allowed = true; // long castling allowed for white |
||
1782 | else if (fen_string[char_index] == L'-') |
||
1783 | continue; // no side can castle (explicitly) |
||
1784 | else if (fen_string[char_index] == L' ') |
||
1785 | break; // if blank space, stop reading castling possibilities |
||
1786 | } |
||
1787 | |||
1788 | // is there a free space after this ? |
||
1789 | if (char_index < length) |
||
1790 | { |
||
1791 | char_index++; // if so, skip it |
||
1792 | |||
1793 | // is there enough room for an en passant position AND is it specified ? |
||
1794 | if ((char_index + 2 <= length) && (fen_string[char_index] != L'-')) |
||
1795 | { |
||
1796 | // read column |
||
1797 | if (towlower (fen_string[char_index]) == L'a') enpassant_column = 0; |
||
1798 | else if (towlower (fen_string[char_index]) == L'b') enpassant_column = 1; |
||
1799 | else if (towlower (fen_string[char_index]) == L'c') enpassant_column = 2; |
||
1800 | else if (towlower (fen_string[char_index]) == L'd') enpassant_column = 3; |
||
1801 | else if (towlower (fen_string[char_index]) == L'e') enpassant_column = 4; |
||
1802 | else if (towlower (fen_string[char_index]) == L'f') enpassant_column = 5; |
||
1803 | else if (towlower (fen_string[char_index]) == L'g') enpassant_column = 6; |
||
1804 | else if (towlower (fen_string[char_index]) == L'h') enpassant_column = 7; |
||
1805 | else return (false); // consistency check: something's wrong with this notation, return FALSE |
||
1806 | |||
1807 | // read line |
||
1808 | enpassant_line = _wtoi (&fen_string[char_index + 1]) - 1; |
||
1809 | if ((enpassant_line != 2) && (enpassant_line != 5)) |
||
1810 | return (false); // consistency check: something's wrong with this notation, return FALSE |
||
1811 | |||
1812 | // setup move data |
||
1813 | move->part = PART_PAWN; |
||
1814 | if (enpassant_line == 2) |
||
1815 | { |
||
1816 | move->source[0] = 1; // rush from line 1 to line 3 |
||
1817 | move->target[0] = 3; |
||
1818 | move->color = COLOR_WHITE; |
||
1819 | } |
||
1820 | else |
||
1821 | { |
||
1822 | move->source[0] = 6; // rush from line 6 to line 4 |
||
1823 | move->target[0] = 4; |
||
1824 | move->color = COLOR_BLACK; |
||
1825 | } |
||
1826 | move->source[1] = enpassant_column; |
||
1827 | move->target[1] = enpassant_column; |
||
1828 | } |
||
1829 | } |
||
1830 | |||
1831 | // table was setup correctly, save FEN string in move structure |
||
1832 | wcscpy_s (move->fen_string, WCHAR_SIZEOF (move->fen_string), fen_string); |
||
1833 | return (true); // and return TRUE |
||
1834 | } |
||
1835 | |||
1836 | |||
1837 | bool Move_SetupFromStyle12 (boardmove_t *move, wchar_t *positions, int move_color, int pawnrush_column, |
||
1838 | bool can_white_castle_short, bool can_white_castle_long, bool can_black_castle_short, bool can_black_castle_long, wchar_t *pretty_movestring) |
||
1839 | { |
||
1840 | // this function sets up the given board according to the Style12 ICC/FICS description style12_string makes of it |
||
1841 | |||
1842 | int pos_index; |
||
1843 | int current_line; |
||
1844 | int current_column; |
||
1845 | |||
1846 | // reset the chess grid |
||
1847 | memset (&move->slots, 0, sizeof (move->slots)); |
||
1848 | |||
1849 | // now parse the line from left to right, placing parts on the fly |
||
1850 | for (current_line = 0; current_line < 8; current_line++) |
||
1851 | for (current_column = 0; current_column < 8; current_column++) |
||
1852 | { |
||
1853 | pos_index = (7 - current_line) * 8 + current_column; // compute position in line |
||
1854 | |||
1855 | if (positions[pos_index] == L'r') |
||
1856 | Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_ROOK); // black rook |
||
1857 | else if (positions[pos_index] == L'R') |
||
1858 | Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_ROOK); // white rook |
||
1859 | else if (positions[pos_index] == L'n') |
||
1860 | Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_KNIGHT); // black knight |
||
1861 | else if (positions[pos_index] == L'N') |
||
1862 | Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_KNIGHT); // white knight |
||
1863 | else if (positions[pos_index] == L'b') |
||
1864 | Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_BISHOP); // black bishop |
||
1865 | else if (positions[pos_index] == L'B') |
||
1866 | Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_BISHOP); // white bishop |
||
1867 | else if (positions[pos_index] == L'q') |
||
1868 | Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_QUEEN); // black queen |
||
1869 | else if (positions[pos_index] == L'Q') |
||
1870 | Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_QUEEN); // white queen |
||
1871 | else if (positions[pos_index] == L'k') |
||
1872 | Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_KING); // black king |
||
1873 | else if (positions[pos_index] == L'K') |
||
1874 | Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_KING); // white king |
||
1875 | else if (positions[pos_index] == L'p') |
||
1876 | Move_SetSlot (move, current_line, current_column, COLOR_BLACK, PART_PAWN); // black pawn |
||
1877 | else if (positions[pos_index] == L'P') |
||
1878 | Move_SetSlot (move, current_line, current_column, COLOR_WHITE, PART_PAWN); // white pawn |
||
1879 | } |
||
1880 | |||
1881 | // save move color |
||
1882 | move->color = move_color; |
||
1883 | |||
1884 | // allow or disallow both sides to castle, as told |
||
1885 | move->sides[COLOR_WHITE].shortcastle_allowed = can_white_castle_short; |
||
1886 | move->sides[COLOR_WHITE].longcastle_allowed = can_white_castle_long; |
||
1887 | move->sides[COLOR_BLACK].shortcastle_allowed = can_black_castle_short; |
||
1888 | move->sides[COLOR_BLACK].longcastle_allowed = can_black_castle_long; |
||
1889 | |||
1890 | // is the last move a pawn rush ? |
||
1891 | if (pawnrush_column != -1) |
||
1892 | { |
||
1893 | if ((pawnrush_column < 0) || (pawnrush_column > 7)) |
||
1894 | return (false); // consistency check: something's wrong with this notation, return FALSE |
||
1895 | |||
1896 | move->part = PART_PAWN; |
||
1897 | if (move->color == COLOR_WHITE) |
||
1898 | { |
||
1899 | move->source[0] = 1; // rush from line 1 to line 3 |
||
1900 | move->target[0] = 3; |
||
1901 | } |
||
1902 | else |
||
1903 | { |
||
1904 | move->source[0] = 6; // rush from line 6 to line 4 |
||
1905 | move->target[0] = 4; |
||
1906 | } |
||
1907 | move->source[1] = pawnrush_column; |
||
1908 | move->target[1] = pawnrush_column; |
||
1909 | } |
||
1910 | |||
1911 | // finally, save the FEN string with which we initialized this board |
||
1912 | Move_DescribeInFEN (move); |
||
1913 | return (true); // finished, no error encountered |
||
1914 | } |
||
1915 | |||
1916 | |||
74 | pmbaty | 1917 | static bool Move_IsWayClearBetween (boardmove_t *move, int source_line, int source_column, int target_line, int target_column) |
1918 | { |
||
1919 | // helper function that checks and returns whether the way is clear between source and target. |
||
1920 | |||
1921 | int column_delta_step; |
||
1922 | int line_delta_step; |
||
1923 | int column_delta; |
||
1924 | int line_delta; |
||
1925 | int column; |
||
1926 | int line; |
||
1927 | |||
1928 | line_delta = target_line - source_line; |
||
1929 | line_delta_step = (line_delta != 0 ? line_delta / abs (line_delta) : 0); |
||
1930 | column_delta = target_column - source_column; |
||
1931 | column_delta_step = (column_delta != 0 ? column_delta / abs (column_delta) : 0); |
||
1932 | |||
1933 | // for each square that's between source and target... |
||
1934 | for (line = source_line + line_delta_step, column = source_column + column_delta_step; |
||
1935 | IS_VALID (line, column) && (line != target_line || column != target_column); |
||
1936 | line += line_delta_step, column += column_delta_step) |
||
1937 | if ((line == target_line) && (column == target_column)) |
||
1938 | break; // don't verify the target position's square |
||
1939 | else if (move->slots[line][column].part != PART_NONE) |
||
1940 | return (false); // there's something in the way... |
||
1941 | |||
1942 | if (!IS_VALID (line, column)) |
||
1943 | return (false); // we've gotten off board... |
||
1944 | |||
1945 | return (true); // the way looks clear between source and target |
||
1946 | } |
||
1947 | |||
1948 | |||
1 | pmbaty | 1949 | static void AddPossibleMove (boardmove_t **possiblemoves, int *possiblemove_count, int color, int part, int source_line, int source_column, int target_line, int target_column, int promotion_type, bool has_captured, bool is_enpassant) |
1950 | { |
||
1951 | // helper function that resizes the given possiblemoves array and adds a possible move to it |
||
1952 | |||
1953 | // TODO: raise or clear the is_check and is_stalemate move flags in the returned move. |
||
1954 | // Not crucial as this function is only called by Board_FindRandomMove(), the result is then |
||
1955 | // translated in SAN and then fed to the chess engine to order a blunderous move. The move |
||
1956 | // is then played normally using Board_AppendMove() using source and target locations, and this |
||
1957 | // call does evaluate the actual move and set the flags correctly in the final moves array. |
||
1958 | |||
1959 | *possiblemoves = (boardmove_t *) SAFE_realloc (*possiblemoves, *possiblemove_count, (*possiblemove_count) + 1, sizeof (boardmove_t), true); |
||
1960 | (*possiblemoves)[*possiblemove_count].color = color; |
||
1961 | (*possiblemoves)[*possiblemove_count].part = part; |
||
1962 | (*possiblemoves)[*possiblemove_count].source[0] = source_line; |
||
1963 | (*possiblemoves)[*possiblemove_count].source[1] = source_column; |
||
1964 | (*possiblemoves)[*possiblemove_count].target[0] = target_line; |
||
1965 | (*possiblemoves)[*possiblemove_count].target[1] = target_column; |
||
1966 | (*possiblemoves)[*possiblemove_count].promotion_type = promotion_type; |
||
1967 | (*possiblemoves)[*possiblemove_count].has_captured = has_captured; |
||
1968 | (*possiblemoves)[*possiblemove_count].is_enpassant = is_enpassant; |
||
1969 | (*possiblemove_count)++; // possible moves array holds now one move more |
||
1970 | |||
1971 | return; // finished |
||
1972 | } |