Subversion Repositories Games.Chess Giants

Rev

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