Subversion Repositories Games.Chess Giants

Rev

Rev 44 | Details | Compare with Previous | Last modification | View Log | RSS feed

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