Implement Grand Chess
[capablanca.git] / lasker-2.2.3 / src / movecheck.c
1 /*
2    Copyright (c) 1993 Richard V. Nash.
3    Copyright (c) 2000 Dan Papasian
4    Copyright (C) Andrew Tridgell 2002
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 // [HGM] some explanation of the parser code:
24 // The routine parse_move() calls is_move() to recognize some simple cases,
25 // like OO-castle and long algebraic with or without dash. What does not fall
26 // in this class is handed to alg_is_move(), whch is really a continuation
27 // of is_move(), to recognize SAN.
28 // Depending on the type of move syntax, parse_move can extract from- and to-square
29 // immediately, or transate the OO-castling to internal from-to representation.
30 // Only for SAN syntax the routine alg_pars_move() is called to extract the
31 // given elements, (through get_move_info(), which is the same as alg_is_move(),
32 // xcept that it does not discard the value of the elements), and disambiguate 
33 // the move (i.e. determines the from-square) by looking for a piece of the given
34 // type on the board for which the move is pseudo-legal (using legal_move() ).
35 // Th
36
37 /* Simply tests if the input string is a move or not. */
38 /* If it matches patterns below */
39 /* Add to this list as you improve the move parser */
40 /* MS_COMP e2e4 */
41 /* MS_COMPDASH e2-e4 */
42 /* MS_CASTLE o-o, o-o-o */
43 /* Not done yet */
44 /* MS_ALG e4, Nd5 Ncd5 */
45 int is_move(const char *mstr)
46 {
47   int len = strlen(mstr);
48   if ((len > 3) && (mstr[len - 2] == '='))
49     len -= 2;
50
51   /* remove the 'mates' marker */
52   if (mstr[len - 1] == '#')
53     len--;
54
55   if (len == 4) {               /* Test for e2e4 */
56     if (isfile(mstr[0]) && isrank(mstr[1]) &&
57         isfile(mstr[2]) && isrank(mstr[3])) {
58       return MS_COMP;
59     }
60   }
61   if (len == 5) {               /* Test for e2-e4 */
62     if (isfile(mstr[0]) && isrank(mstr[1]) &&
63         (mstr[2] == '-') &&
64         isfile(mstr[3]) && isrank(mstr[4])) {
65       return MS_COMPDASH;
66     }
67   }
68   if (len == 3) {               /* Test for o-o */
69     if ((mstr[0] == 'o') && (mstr[1] == '-') && (mstr[2] == 'o')) {
70       return MS_KCASTLE;
71     }
72     if ((mstr[0] == 'O') && (mstr[1] == '-') && (mstr[2] == 'O')) {
73       return MS_KCASTLE;
74     }
75     if ((mstr[0] == '0') && (mstr[1] == '-') && (mstr[2] == '0')) {
76       return MS_KCASTLE;
77     }
78   }
79   if (len == 2) {               /* Test for oo */
80     if ((mstr[0] == 'o') && (mstr[1] == 'o')) {
81       return MS_KCASTLE;
82     }
83     if ((mstr[0] == 'O') && (mstr[1] == 'O')) {
84       return MS_KCASTLE;
85     }
86     if ((mstr[0] == '0') && (mstr[1] == '0')) {
87       return MS_KCASTLE;
88     }
89   }
90   if (len == 5) {               /* Test for o-o-o */
91     if ((mstr[0] == 'o') && (mstr[1] == '-') && (mstr[2] == 'o') && (mstr[3] == '-') && (mstr[4] == 'o')) {
92       return MS_QCASTLE;
93     }
94     if ((mstr[0] == 'O') && (mstr[1] == '-') && (mstr[2] == 'O') && (mstr[3] == '-') && (mstr[4] == 'O')) {
95       return MS_QCASTLE;
96     }
97     if ((mstr[0] == '0') && (mstr[1] == '-') && (mstr[2] == '0') && (mstr[3] == '-') && (mstr[4] == '0')) {
98       return MS_QCASTLE;
99     }
100   }
101   if (len == 3) {               /* Test for ooo */
102     if ((mstr[0] == 'o') && (mstr[1] == 'o') && (mstr[2] == 'o')) {
103       return MS_QCASTLE;
104     }
105     if ((mstr[0] == 'O') && (mstr[1] == 'O') && (mstr[2] == 'O')) {
106       return MS_QCASTLE;
107     }
108     if ((mstr[0] == '0') && (mstr[1] == '0') && (mstr[2] == '0')) {
109       return MS_QCASTLE;
110     }
111   }
112   return alg_is_move(mstr);
113 }
114
115
116 int NextPieceLoop(board_t b, int *f, int *r, int color, int w, int h)
117 {
118   for (;;) {
119     (*r) = (*r) + 1;
120     if (*r >= h) {
121       *r = 0;
122       *f = *f + 1;
123       if (*f >= w)
124         break;
125     }
126     if ((b[*f][*r] != NOPIECE) && iscolor(b[*f][*r], color))
127       return 1;
128   }
129   return 0;
130 }
131
132 int InitPieceLoop(board_t b, int *f, int *r, int color)
133 {
134   *f = 0;
135   *r = -1;
136   return 1;
137 }
138
139 /* All of the routines assume that the obvious problems have been checked */
140 /* See legal_move() */
141 static int legal_pawn_move( struct game_state_t *gs, int ff, int fr, int tf, int tr )
142 {
143   if (ff == tf) {\r
144     if (gs->board[tf][tr] != NOPIECE && !gs->palace && gs->promoType != 3) return 0; // [HGM] XQ and Shogi pawns can capture straight ahead\r
145     if (gs->onMove == WHITE) {\r
146       if (tr - fr == 1) return 1;\r
147       if ((fr <= gs->pawnDblStep) && (tr - fr == 2) && gs->board[ff][fr+1]==NOPIECE) return 1;
148     } else {\r
149       if (fr - tr == 1) return 1;\r
150       if ((fr >= gs->ranks - 1 - gs->pawnDblStep) && (fr - tr == 2) && gs->board[ff][fr-1]==NOPIECE) return 1;\r
151     }\r
152     return 0;\r
153   }\r
154   if (ff != tf && gs->promoType != 3) { /* Capture ? ([HGM] but not in Shogi) */
155     if ((ff - tf != 1) && (tf - ff != 1)) return 0;
156     if (gs->onMove == WHITE) {
157       if(gs->palace) return (fr >= gs->ranks/2 && fr == tr); // [HGM] XQ promoted pawns\r
158       if (tr != fr+1) return 0;
159       if ((gs->board[tf][tr] != NOPIECE) && iscolor(gs->board[tf][tr],BLACK))
160         return 1;
161       if (gs->ep_possible[0][ff] == 1) {
162         if ((tf==ff+1) && (gs->board[ff+1][fr] == B_PAWN)) return 1;
163       } else if (gs->ep_possible[0][ff] == -1) {
164         if ((tf==ff-1) && (gs->board[ff-1][fr] == B_PAWN)) return 1;
165       }
166     } else {
167       if(gs->palace) return (fr < gs->ranks/2 && fr == tr); // [HGM] XQ promoted pawns\r
168       if (tr != fr-1) return 0;
169       if ((gs->board[tf][tr] != NOPIECE) && iscolor(gs->board[tf][tr],WHITE))
170         return 1;
171       if (gs->ep_possible[1][ff] == 1) {
172         if ((tf==ff+1) && (gs->board[ff+1][fr] == W_PAWN)) return 1;
173       } else if (gs->ep_possible[1][ff] == -1) {
174         if ((tf==ff-1) && (gs->board[ff-1][fr] == W_PAWN)) return 1;
175       }
176     }
177   }
178   return 0;
179 }
180
181 static int legal_knight_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
182 {
183   int dx, dy;
184
185   dx = ff - tf;
186   dy = fr - tr;
187   if (abs(dx) == 2) {
188     if (abs(dy) == 1)
189       return 1;
190   }
191   if (abs(dy) == 2) {
192     if (abs(dx) == 1)
193       return 1;
194   }
195   return 0;
196 }
197
198 static int legal_horse_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
199 {
200   int dx, dy;
201
202   dx = ff - tf;
203   dy = fr - tr;
204   if (abs(dx) == 2) {
205     if (abs(dy) == 1 && gs->board[(ff+tf)/2][fr] == NOPIECE)
206       return 1;
207   }
208   if (abs(dy) == 2) {
209     if (abs(dx) == 1 && gs->board[ff][(fr+tr)/2] == NOPIECE)
210       return 1;
211   }
212   return 0;
213 }
214
215 static int legal_honorablehorse_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
216 {
217   int dx, dy;
218
219   dx = ff - tf;
220   dy = fr - tr;
221   if (dy == (gs->onMove == WHITE ? -2 : 2)) {
222     if (abs(dx) == 1)
223       return 1;
224   }
225   return 0;
226 }
227
228 static int legal_bishop_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
229 {
230   int dx, dy, x, y;
231   int startx, starty;
232   int count;
233   int incx, incy;
234
235   if (ff > tf) {
236     dx = ff - tf;
237     incx = -1;
238   } else {
239     dx = tf - ff;
240     incx = 1;
241   }
242   startx = ff + incx;
243   if (fr > tr) {
244     dy = fr - tr;
245     incy = -1;
246   } else {
247     dy = tr - fr;
248     incy = 1;
249   }
250   starty = fr + incy;
251   if (dx != dy)
252     return 0;                   /* Not diagonal */
253   if (dx == 1)
254     return 1;                   /* One square, ok */
255   count = dx - 1;
256   for (x = startx, y = starty; count; x += incx, y += incy, count--) {
257     if (gs->board[x][y] != NOPIECE)
258       return 0;
259   }
260   return 1;
261 }
262
263 static int legal_rook_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
264 {
265   int i;
266   int start, stop;
267
268   if (ff == tf) {
269     if (abs(fr - tr) == 1)
270       return 1;
271     if (fr < tr) {
272       start = fr + 1;
273       stop = tr - 1;
274     } else {
275       start = tr + 1;
276       stop = fr - 1;
277     }
278     for (i = start; i <= stop; i++) {
279       if (gs->board[ff][i] != NOPIECE)
280         return 0;
281     }
282     return 1;
283   } else if (fr == tr) {
284     if (abs(ff - tf) == 1)
285       return 1;
286     if (ff < tf) {
287       start = ff + 1;
288       stop = tf - 1;
289     } else {
290       start = tf + 1;
291       stop = ff - 1;
292     }
293     for (i = start; i <= stop; i++) {
294       if (gs->board[i][fr] != NOPIECE)
295         return 0;
296     }
297     return 1;
298   } else {
299     return 0;
300   }
301 }
302
303 static int legal_cannon_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
304 {
305   int i, cnt=0;
306   int start, stop;
307
308   if (ff == tf) {
309     if (fr < tr) {
310       start = fr + 1;
311       stop = tr - 1;
312     } else {
313       start = tr + 1;
314       stop = fr - 1;
315     }
316     for (i = start; i <= stop; i++) {
317       if (gs->board[ff][i] != NOPIECE) cnt++;
318     }
319     return (cnt == 0 && gs->board[tf][tr] == NOPIECE) ||
320            (cnt == 1 && gs->board[tf][tr] != NOPIECE);
321   } else if (fr == tr) {
322     if (ff < tf) {
323       start = ff + 1;
324       stop = tf - 1;
325     } else {
326       start = tf + 1;
327       stop = ff - 1;
328     }
329     for (i = start; i <= stop; i++) {
330       if (gs->board[i][fr] != NOPIECE) cnt++;
331     }
332     return (cnt == 0 && gs->board[tf][tr] == NOPIECE) ||
333            (cnt == 1 && gs->board[tf][tr] != NOPIECE);
334   } else {
335     return 0;
336   }
337 }
338
339 static int legal_lance_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
340 {
341   int i;
342   int start, stop;
343
344   if (ff == tf) {
345     if (abs(fr - tr) == 1)
346       return 1;
347     if (fr < tr) {
348       if(gs->onMove != WHITE) return 0;
349       start = fr + 1;
350       stop = tr - 1;
351     } else {
352       if(gs->onMove == WHITE) return 0;
353       start = tr + 1;
354       stop = fr - 1;
355     }
356     for (i = start; i <= stop; i++) {
357       if (gs->board[ff][i] != NOPIECE)
358         return 0;
359     }
360     return 1;
361   }
362 }
363
364 static int legal_queen_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
365 {
366   return legal_rook_move(gs, ff, fr, tf, tr) || legal_bishop_move(gs, ff, fr, tf, tr);
367 }
368
369 static int legal_cardinal_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
370 {\r
371   return legal_knight_move(gs, ff, fr, tf, tr) || legal_bishop_move(gs, ff, fr, tf, tr);\r
372 }\r
373 \r
374 static int legal_marshall_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
375 {\r
376   return legal_rook_move(gs, ff, fr, tf, tr) || legal_knight_move(gs, ff, fr, tf, tr);\r
377 }\r
378 \r
379 /* Ckeck, if square (kf,kr) is attacked by enemy piece.
380  * Used in castling from/through check testing.
381  */
382
383 /* new one from soso: */
384 static int is_square_attacked (struct game_state_t *gs, int kf, int kr)
385 {
386   struct game_state_t fakeMove;
387   int oldk = gs->onMove == WHITE ? gs->wkmoved : gs->bkmoved;
388
389   fakeMove = *gs;
390   fakeMove.board[oldk][kr] = NOPIECE; // [HGM] castle: this routine is called only when King has not moved\r
391   fakeMove.board[kf][kr] = KING | fakeMove.onMove;
392   fakeMove.onMove = CToggle (fakeMove.onMove);
393   if (in_check(&fakeMove)) return 1;
394     else return 0;
395 }
396
397 /* old one:
398 static int is_square_attacked(struct game_state_t * gs, int kf, int kr)
399 {
400   int f, r;
401   gs->onMove = CToggle(gs->onMove);
402
403   for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
404        NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {
405     if (legal_move(gs, f, r, kf, kr)) {
406       gs->onMove = CToggle(gs->onMove);
407       return 1;
408     }
409   }
410   gs->onMove = CToggle(gs->onMove);
411   return 0;
412 }
413 */
414
415 static int legal_man_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
416 {\r
417   if (abs(ff - tf) > 1)\r
418     return 0;\r
419   if (abs(fr - tr) > 1)\r
420     return 0;\r
421   return 1;\r
422 }\r
423 \r
424 static int legal_wazir_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
425 {\r
426   if(gs->palace && (tr > gs->palace && tr < gs->ranks - gs->palace ||
427      tf < (gs->files - gs->palace)/2 || tf >= (gs->files + gs->palace)/2))
428     return 0;\r
429   if (abs(ff - tf) == 1 && fr == tr)\r
430     return 1;\r
431   if (abs(fr - tr) == 1 && ff == tf)\r
432     return 1;\r
433   return 0;\r
434 }\r
435 \r
436 static int legal_dababba_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
437 {\r
438   if (abs(ff - tf) == 2 && fr == tr)\r
439     return 1;\r
440   if (abs(fr - tr) == 2 && ff == tf)\r
441     return 1;\r
442   return 0;\r
443 }\r
444 \r
445 static int legal_ferz_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
446 {\r
447   if (abs(ff - tf) != 1)\r
448     return 0;\r
449   if (abs(fr - tr) != 1)\r
450     return 0;\r
451   return 1;\r
452 }\r
453
454 static int legal_mandarin_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
455 {\r
456   if(gs->palace && (tr > gs->palace && tr < gs->ranks - gs->palace ||
457      tf < (gs->files - gs->palace)/2 || tf >= (gs->files + gs->palace)/2))
458     return 0;\r
459   if (abs(ff - tf) != 1)\r
460     return 0;\r
461   if (abs(fr - tr) != 1)\r
462     return 0;\r
463   return 1;\r
464 }\r
465 \r
466 static int legal_alfil_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
467 {
468   if (abs(ff - tf) != 2)\r
469     return 0;\r
470   if (abs(fr - tr) != 2)\r
471     return 0;\r
472   return 1;\r
473 }\r
474 \r
475 static int legal_elephant_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
476 {\r
477   if (abs(ff - tf) != 2)\r
478     return 0;\r
479   if (abs(fr - tr) != 2)\r
480     return 0;
481   if(gs->board[(ff+tf)/2][(fr+tr)/2] != NOPIECE) return 0; // blocked
482   if((tr >= gs->ranks/2) != (fr >= gs->ranks/2)) return 0; // do not cross river\r
483   return 1;\r
484 }\r
485 \r
486 static int legal_gold_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
487 {\r
488   return legal_wazir_move(gs, ff, fr, tf, tr) || (abs(ff-tf) == 1 && tr == fr + (gs->onMove==WHITE ? 1 : -1));\r
489 }\r
490 \r
491 static int legal_silver_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
492 {\r
493   return legal_ferz_move(gs, ff, fr, tf, tr) || (tf == ff && tr == fr + (gs->onMove==WHITE ? 1 : -1) );\r
494 }\r
495 \r
496 static int legal_woody_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
497 {\r
498   return legal_wazir_move(gs, ff, fr, tf, tr) || legal_dababba_move(gs, ff, fr, tf, tr);\r
499 }\r
500 \r
501 static int legal_squirrel_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
502 {\r
503   return legal_alfil_move(gs, ff, fr, tf, tr) || legal_dababba_move(gs, ff, fr, tf, tr) 
504                                                         || legal_knight_move(gs, ff, fr, tf, tr);\r
505 }\r
506 \r
507 static int legal_mastodon_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
508 {\r
509   return legal_man_move(gs, ff, fr, tf, tr) || legal_alfil_move(gs, ff, fr, tf, tr)
510                                                         || legal_dababba_move(gs, ff, fr, tf, tr);\r
511 }\r
512 \r
513 static int legal_centaur_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
514 {\r
515   return legal_man_move(gs, ff, fr, tf, tr) || legal_knight_move(gs, ff, fr, tf, tr);\r
516 }\r
517 \r
518 static int legal_amazon_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
519 {\r
520   return legal_queen_move(gs, ff, fr, tf, tr) || legal_knight_move(gs, ff, fr, tf, tr);\r
521 }\r
522 \r
523 static int legal_dragonking_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
524 {\r
525   return legal_rook_move(gs, ff, fr, tf, tr) || legal_ferz_move(gs, ff, fr, tf, tr);\r
526 }\r
527 \r
528 static int legal_dragonhorse_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
529 {\r
530   return legal_bishop_move(gs, ff, fr, tf, tr) || legal_wazir_move(gs, ff, fr, tf, tr);\r
531 }\r
532 \r
533 static int legal_modernelephant_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
534 {\r
535   return legal_ferz_move(gs, ff, fr, tf, tr) || legal_alfil_move(gs, ff, fr, tf, tr);\r
536 }\r
537 \r
538 static int legal_priestess_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
539 {\r
540   return legal_knight_move(gs, ff, fr, tf, tr) || legal_ferz_move(gs, ff, fr, tf, tr)
541                                                 || legal_alfil_move(gs, ff, fr, tf, tr);\r
542 }\r
543 \r
544 static int legal_minister_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
545 {\r
546   return legal_knight_move(gs, ff, fr, tf, tr) || legal_wazir_move(gs, ff, fr, tf, tr)
547                                                 || legal_dababba_move(gs, ff, fr, tf, tr);\r
548 }\r
549 \r
550 static int legal_king_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
551 {
552   int result;
553
554   // [HGM] castle: test first if valid as regular King move; result = 1 or 0
555   if(gs->royalKnight)\r
556     result = legal_knight_move(gs, ff, fr, tf, tr);\r
557   else if(gs->palace) {
558     result = legal_wazir_move(gs, ff, fr, tf, tr);
559     if(!result && ff == tf && piecetype(gs->board[tf][tr]) == KING) { // XQ regicide
560       int i, d = (tr>fr ? 1 : -1);
561       for(i=fr+d; i!=tr; i+=d) 
562         if(gs->board[ff][i] != NOPIECE) return 0; // line of sight blocked
563       return 1;
564     }
565   } else\r
566     result = legal_man_move(gs, ff, fr, tf, tr);
567
568   if(result) return 1;\r
569   // [HGM] castle: orthodox legal castlings given as King move return 2
570
571   if (gs->onMove == WHITE) {\r
572     /* King side castling */\r
573     if ((fr == 0) && (tr == 0) && (ff == gs->files/2) && (tf == gs->files-2) && (gs->wkmoved >= 0)\r
574         && (gs->wkrmoved >= 0) && (gs->board[gs->files-3][0] == NOPIECE) &&\r
575         (gs->board[gs->files-2][0] == NOPIECE) && (gs->board[gs->files-1][0] == W_ROOK) &&\r
576         (gs->board[gs->files/2+1][0] == NOPIECE) && (!is_square_attacked(gs, gs->files/2+1, 0)) &&\r
577         (!is_square_attacked(gs, gs->files/2, 0)) && (!is_square_attacked(gs, gs->files-3, 0))) {\r
578       return 2;\r
579     }\r
580     /* Queen side castling */\r
581     if ((fr == 0) && (tr == 0) && (ff == gs->files/2) && (tf == 2) && (gs->wkmoved >= 0)\r
582         && (gs->wqrmoved >= 0) && (gs->board[3][0] == NOPIECE) &&\r
583         (gs->board[2][0] == NOPIECE) && (gs->board[1][0] == NOPIECE) &&\r
584         (gs->board[0][0] == W_ROOK) &&\r
585         (gs->board[gs->files/2-1][0] == NOPIECE) && (!is_square_attacked(gs, gs->files/2-1, 0)) &&\r
586         (!is_square_attacked(gs, gs->files/2, 0)) && (!is_square_attacked(gs, 3, 0))) {\r
587       return 2;\r
588     }\r
589   } else {                      /* Black */\r
590     /* King side castling */\r
591     if ((fr == gs->ranks-1) && (tr == gs->ranks-1) && (ff == gs->files/2) && (tf == gs->files-2) && (gs->bkmoved >= 0)\r
592         && (gs->bkrmoved >= 0) && (gs->board[gs->files-3][7] == NOPIECE) &&\r
593         (gs->board[gs->files-2][gs->ranks-1] == NOPIECE) && (gs->board[gs->files-1][gs->ranks-1] == B_ROOK) &&\r
594         (gs->board[gs->files/2+1][gs->ranks-1] == NOPIECE) && (!is_square_attacked(gs, gs->files/2+1, gs->ranks-1)) &&\r
595         (!is_square_attacked(gs, gs->files/2, gs->ranks-1)) && (!is_square_attacked(gs, gs->files-3, gs->ranks-1))) {\r
596       return 2;\r
597     }\r
598     /* Queen side castling */\r
599     if ((fr == gs->ranks-1) && (tr == gs->ranks-1) && (ff == gs->files/2) && (tf == 2) && (gs->bkmoved >= 0)\r
600         && (gs->bqrmoved >= 0) && (gs->board[3][gs->ranks-1] == NOPIECE) &&\r
601         (gs->board[2][gs->ranks-1] == NOPIECE) && (gs->board[1][gs->ranks-1] == NOPIECE) &&\r
602         (gs->board[0][gs->ranks-1] == B_ROOK) &&\r
603         (gs->board[gs->files/2-1][gs->ranks-1] == NOPIECE) && (!is_square_attacked(gs, gs->files/2-1, gs->ranks-1)) &&\r
604         (!is_square_attacked(gs, gs->files/2, gs->ranks-1)) && (!is_square_attacked(gs, 3, gs->ranks-1))) {\r
605       return 2;\r
606     }\r
607   }
608 \r
609   return 0; // neither regular King move nor castling
610 }
611
612 static void add_pos(int tof, int tor, int *posf, int *posr, int *numpos)
613 {
614   posf[*numpos] = tof;
615   posr[*numpos] = tor;
616   (*numpos)++;
617 }
618
619 static void possible_pawn_moves(struct game_state_t * gs,
620                                   int onf, int onr,
621                                   int *posf, int *posr, int *numpos)
622 {
623   if (gs->onMove == WHITE) {\r
624     if (gs->board[onf][onr + 1] == NOPIECE || gs->palace || gs->promoType == 3) {\r
625       add_pos(onf, onr + 1, posf, posr, numpos);\r
626       if ((onr <= gs->pawnDblStep) && (gs->board[onf][onr + 2] == NOPIECE))\r
627         add_pos(onf, onr + 2, posf, posr, numpos);\r
628     }\r
629     if (onf > 0) {
630       if (gs->board[onf - 1][onr + 1] != NOPIECE &&\r
631           iscolor(gs->board[onf - 1][onr + 1], BLACK) &&
632           !gs->palace && gs->promoType != 3) // no diagonal capture in XQ and Shogi\r
633         add_pos(onf - 1, onr + 1, posf, posr, numpos);
634       if(gs->palace && onr >= gs->ranks/2 && (gs->board[onf-1][onr] || iscolor(gs->board[onf-1][onr], BLACK)))
635         add_pos(onf - 1, onr, posf, posr, numpos); // XQ promoted pawn
636     }\r
637     if (onf < gs->files-1) {
638       if (gs->board[onf + 1][onr + 1] != NOPIECE &&\r
639           iscolor(gs->board[onf + 1][onr + 1], BLACK) &&
640           !gs->palace && gs->promoType != 3) // no diagonal capture in XQ and Shogi\r
641         add_pos(onf + 1, onr + 1, posf, posr, numpos);
642       if(gs->palace && onr >= gs->ranks/2 && (gs->board[onf+1][onr] || iscolor(gs->board[onf+1][onr], BLACK)))
643         add_pos(onf + 1, onr, posf, posr, numpos); // XQ promoted pawn
644     }\r
645     if (gs->ep_possible[0][onf] == -1)\r
646       add_pos(onf - 1, onr + 1, posf, posr, numpos);\r
647     if (gs->ep_possible[0][onf] == 1)\r
648       add_pos(onf + 1, onr + 1, posf, posr, numpos);
649   } else {\r
650     if (gs->board[onf][onr - 1] == NOPIECE || gs->palace || gs->promoType == 3) {\r
651       add_pos(onf, onr - 1, posf, posr, numpos);\r
652       if ((onr >= gs->ranks - gs->pawnDblStep - 1) && (gs->board[onf][onr - 2] == NOPIECE))\r
653         add_pos(onf, onr - 2, posf, posr, numpos);\r
654     }\r
655     if (onf > 0) {
656       if (gs->board[onf - 1][onr - 1] != NOPIECE &&\r
657           iscolor(gs->board[onf - 1][onr - 1], WHITE) &&\r
658           !gs->palace && gs->promoType != 3) // no diagonal capture in XQ and Shogi\r
659         add_pos(onf - 1, onr - 1, posf, posr, numpos);
660       if(gs->palace && onr < gs->ranks/2 && !iscolor(gs->board[onf-1][onr], BLACK))
661         add_pos(onf - 1, onr, posf, posr, numpos); // XQ promoted pawn
662     }\r
663     if (onf < gs->files-1) {
664       if (gs->board[onf + 1][onr - 1] != NOPIECE &&\r
665           iscolor(gs->board[onf + 1][onr - 1], WHITE) &&\r
666           !gs->palace && gs->promoType != 3) // no diagonal capture in XQ and Shogi\r
667         add_pos(onf + 1, onr - 1, posf, posr, numpos);
668       if(gs->palace && onr < gs->ranks/2 && !iscolor(gs->board[onf+1][onr], BLACK))
669         add_pos(onf + 1, onr, posf, posr, numpos); // XQ promoted pawn
670     }\r
671     if (gs->ep_possible[1][onf] == -1)\r
672       add_pos(onf - 1, onr - 1, posf, posr, numpos);\r
673     if (gs->ep_possible[1][onf] == 1)\r
674       add_pos(onf + 1, onr - 1, posf, posr, numpos);\r
675   }\r
676 }
677
678 static void possible_knight_moves(struct game_state_t * gs,
679                                     int onf, int onr,
680                                     int *posf, int *posr, int *numpos)
681 {
682   static int knightJumps[8][2] = {{-1, 2}, {1, 2}, {2, -1}, {2, 1},\r
683   {-1, -2}, {1, -2}, {-2, 1}, {-2, -1}};\r
684   int f, r;\r
685   int j;\r
686 \r
687   for (j = 0; j < 8; j++) {\r
688     f = knightJumps[j][0] + onf;\r
689     r = knightJumps[j][1] + onr;\r
690     if ((f < 0) || (f >= gs->files))\r
691       continue;\r
692     if ((r < 0) || (r >= gs->ranks))\r
693       continue;\r
694     if ((gs->board[f][r] == NOPIECE) ||\r
695         (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
696       add_pos(f, r, posf, posr, numpos);\r
697   }\r
698 }
699
700 static void possible_horse_moves(struct game_state_t * gs,
701                                     int onf, int onr,
702                                     int *posf, int *posr, int *numpos)
703 {
704   static int knightJumps[8][4] = {{-1, 2, 0, 1}, {1, 2, 0, 1}, {2, -1, 1, 0}, {2, 1, 1, 0},\r
705   {-1, -2, 0, -1}, {1, -2, 0, -1}, {-2, 1, -1, 0}, {-2, -1, -1, 0}};\r
706   int f, r;\r
707   int j;\r
708 \r
709   for (j = 0; j < 8; j++) {\r
710     f = knightJumps[j][0] + onf;\r
711     r = knightJumps[j][1] + onr;\r
712     if ((f < 0) || (f >= gs->files))\r
713       continue;\r
714     if ((r < 0) || (r >= gs->ranks))\r
715       continue;\r
716     if ((gs->board[knightJumps[j][2] + onf][knightJumps[j][3] + onr] == NOPIECE) && 
717         ((gs->board[f][r] == NOPIECE) || (iscolor(gs->board[f][r], CToggle(gs->onMove)))))\r
718       add_pos(f, r, posf, posr, numpos);\r
719   }\r
720 }
721
722 static void possible_bishop_moves(struct game_state_t * gs,
723                                     int onf, int onr,
724                                     int *posf, int *posr, int *numpos)
725 {
726   int f, r;\r
727 \r
728   /* Up Left */\r
729   f = onf;\r
730   r = onr;\r
731   for (;;) {\r
732     f--;\r
733     r++;\r
734     if ((f < 0) || (f >= gs->files))\r
735       break;\r
736     if ((r < 0) || (r >= gs->ranks))\r
737       break;\r
738     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
739       break;\r
740     add_pos(f, r, posf, posr, numpos);\r
741     if (gs->board[f][r] != NOPIECE)\r
742       break;\r
743   }\r
744   /* Up Right */\r
745   f = onf;\r
746   r = onr;\r
747   for (;;) {\r
748     f++;\r
749     r++;\r
750     if ((f < 0) || (f >= gs->files))\r
751       break;\r
752     if ((r < 0) || (r >= gs->ranks))\r
753       break;\r
754     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
755       break;\r
756     add_pos(f, r, posf, posr, numpos);\r
757     if (gs->board[f][r] != NOPIECE)\r
758       break;\r
759   }\r
760   /* Down Left */\r
761   f = onf;\r
762   r = onr;\r
763   for (;;) {\r
764     f--;\r
765     r--;\r
766     if ((f < 0) || (f >= gs->files))\r
767       break;\r
768     if ((r < 0) || (r >= gs->ranks))\r
769       break;\r
770     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
771       break;\r
772     add_pos(f, r, posf, posr, numpos);\r
773     if (gs->board[f][r] != NOPIECE)\r
774       break;\r
775   }\r
776   /* Down Right */\r
777   f = onf;\r
778   r = onr;\r
779   for (;;) {\r
780     f++;\r
781     r--;\r
782     if ((f < 0) || (f >= gs->files))\r
783       break;\r
784     if ((r < 0) || (r >= gs->ranks))\r
785       break;\r
786     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
787       break;\r
788     add_pos(f, r, posf, posr, numpos);\r
789     if (gs->board[f][r] != NOPIECE)\r
790       break;\r
791   }\r
792 }
793
794 static void possible_rook_moves(struct game_state_t * gs,
795                                   int onf, int onr,
796                                   int *posf, int *posr, int *numpos)
797 {
798   int f, r;\r
799 \r
800   /* Left */\r
801   f = onf;\r
802   r = onr;\r
803   for (;;) {\r
804     f--;\r
805     if ((f < 0) || (f >= gs->files))\r
806       break;\r
807     if ((r < 0) || (r >= gs->ranks))\r
808       break;\r
809     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
810       break;\r
811     add_pos(f, r, posf, posr, numpos);\r
812     if (gs->board[f][r] != NOPIECE)\r
813       break;\r
814   }\r
815   /* Right */\r
816   f = onf;\r
817   r = onr;\r
818   for (;;) {\r
819     f++;\r
820     if ((f < 0) || (f >= gs->files))\r
821       break;\r
822     if ((r < 0) || (r >= gs->ranks))\r
823       break;\r
824     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
825       break;\r
826     add_pos(f, r, posf, posr, numpos);\r
827     if (gs->board[f][r] != NOPIECE)\r
828       break;\r
829   }\r
830   /* Up */\r
831   f = onf;\r
832   r = onr;\r
833   for (;;) {\r
834     r++;\r
835     if ((f < 0) || (f >= gs->files))\r
836       break;\r
837     if ((r < 0) || (r >= gs->ranks))\r
838       break;\r
839     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
840       break;\r
841     add_pos(f, r, posf, posr, numpos);\r
842     if (gs->board[f][r] != NOPIECE)\r
843       break;\r
844   }\r
845   /* Down */\r
846   f = onf;\r
847   r = onr;\r
848   for (;;) {\r
849     r--;\r
850     if ((f < 0) || (f >= gs->files))\r
851       break;\r
852     if ((r < 0) || (r >= gs->ranks))\r
853       break;\r
854     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
855       break;\r
856     add_pos(f, r, posf, posr, numpos);\r
857     if (gs->board[f][r] != NOPIECE)\r
858       break;\r
859   }\r
860 }
861
862 static void possible_cannon_moves(struct game_state_t * gs,
863                                   int onf, int onr,
864                                   int *posf, int *posr, int *numpos)
865 {
866   int f, r, i;\r
867 \r
868   /* Left */\r
869   f = onf;\r
870   r = onr;\r
871   for (i=0;;) {\r
872     f--;\r
873     if ((f < 0) || (f >= gs->files))\r
874       break;\r
875     if ((r < 0) || (r >= gs->ranks))\r
876       break;\r
877     if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
878     if(i == 0)
879         add_pos(f, r, posf, posr, numpos); // no hop: non-capt
880     else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) 
881         add_pos(f, r, posf, posr, numpos); // hop: capt\r
882     if (gs->board[f][r] != NOPIECE)\r
883       break;\r
884   }\r
885   /* Right */\r
886   f = onf;\r
887   r = onr;\r
888   for (i=0;;) {\r
889     f++;\r
890     if ((f < 0) || (f >= gs->files))\r
891       break;\r
892     if ((r < 0) || (r >= gs->ranks))\r
893       break;\r
894     if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
895     if(i == 0)
896         add_pos(f, r, posf, posr, numpos); // no hop: non-capt
897     else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) 
898         add_pos(f, r, posf, posr, numpos); // hop: capt\r
899     if (gs->board[f][r] != NOPIECE)\r
900       break;\r
901   }\r
902   /* Up */\r
903   f = onf;\r
904   r = onr;\r
905   for (i=0;;) {\r
906     r++;\r
907     if ((f < 0) || (f >= gs->files))\r
908       break;\r
909     if ((r < 0) || (r >= gs->ranks))\r
910       break;\r
911     if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
912     if(i == 0)
913         add_pos(f, r, posf, posr, numpos); // no hop: non-capt
914     else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) 
915         add_pos(f, r, posf, posr, numpos); // hop: capt\r
916     if (gs->board[f][r] != NOPIECE)\r
917       break;\r
918   }\r
919   /* Down */\r
920   f = onf;\r
921   r = onr;\r
922   for (i=0;;) {\r
923     r--;\r
924     if ((f < 0) || (f >= gs->files))\r
925       break;\r
926     if ((r < 0) || (r >= gs->ranks))\r
927       break;\r
928     if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
929     if(i == 0)
930         add_pos(f, r, posf, posr, numpos); // no hop: non-capt
931     else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) 
932         add_pos(f, r, posf, posr, numpos); // hop: capt\r
933     if (gs->board[f][r] != NOPIECE)\r
934       break;\r
935   }\r
936 }
937
938 static void possible_lance_moves(struct game_state_t * gs,
939                                   int onf, int onr,
940                                   int *posf, int *posr, int *numpos)
941 {
942   int f, r;\r
943 \r
944   /* Up */\r
945   f = onf;\r
946   r = onr;\r
947   for (;gs->onMove == WHITE;) {\r
948     r++;\r
949     if ((f < 0) || (f >= gs->files))\r
950       break;\r
951     if ((r < 0) || (r >= gs->ranks))\r
952       break;\r
953     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
954       break;\r
955     add_pos(f, r, posf, posr, numpos);\r
956     if (gs->board[f][r] != NOPIECE)\r
957       break;\r
958   }\r
959   /* Down */\r
960   f = onf;\r
961   r = onr;\r
962   for (;gs->onMove == BLACK;) {\r
963     r--;\r
964     if ((f < 0) || (f >= gs->files))\r
965       break;\r
966     if ((r < 0) || (r >= gs->ranks))\r
967       break;\r
968     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
969       break;\r
970     add_pos(f, r, posf, posr, numpos);\r
971     if (gs->board[f][r] != NOPIECE)\r
972       break;\r
973   }\r
974 }
975
976 static void possible_cardinal_moves(struct game_state_t * gs,\r
977                                    int onf, int onr,\r
978                                    int *posf, int *posr, int *numpos)\r
979 {\r
980   possible_knight_moves(gs, onf, onr, posf, posr, numpos);\r
981   possible_bishop_moves(gs, onf, onr, posf, posr, numpos);\r
982 }\r
983 \r
984 static void possible_marshall_moves(struct game_state_t * gs,\r
985                                    int onf, int onr,\r
986                                    int *posf, int *posr, int *numpos)\r
987 {\r
988   possible_rook_moves(gs, onf, onr, posf, posr, numpos);\r
989   possible_knight_moves(gs, onf, onr, posf, posr, numpos);\r
990 }\r
991 \r
992 static void possible_queen_moves(struct game_state_t * gs,
993                                    int onf, int onr,
994                                    int *posf, int *posr, int *numpos)
995 {
996   possible_rook_moves(gs, onf, onr, posf, posr, numpos);
997   possible_bishop_moves(gs, onf, onr, posf, posr, numpos);
998 }
999
1000 static void possible_alfil_moves(struct game_state_t * gs,\r
1001                                   int onf, int onr,\r
1002                                   int *posf, int *posr, int *numpos)\r
1003 {\r
1004   static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};\r
1005   int f, r;\r
1006   int j;\r
1007 \r
1008   for (j = 0; j < 4; j++) {\r
1009     f = 2*kingJumps[j][0] + onf;\r
1010     r = 2*kingJumps[j][1] + onr;\r
1011     if ((f < 0) || (f >= gs->files))\r
1012       continue;\r
1013     if ((r < 0) || (r >= gs->ranks))\r
1014       continue;\r
1015     if ((gs->board[f][r] == NOPIECE) ||\r
1016         (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
1017       add_pos(f, r, posf, posr, numpos);\r
1018   }\r
1019 }\r
1020 \r
1021 static void possible_ferz_moves(struct game_state_t * gs,\r
1022                                   int onf, int onr,\r
1023                                   int *posf, int *posr, int *numpos)\r
1024 {\r
1025   static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};\r
1026   int f, r;\r
1027   int j;\r
1028 \r
1029   for (j = 0; j < 4; j++) {\r
1030     f = kingJumps[j][0] + onf;\r
1031     r = kingJumps[j][1] + onr;\r
1032     if ((f < 0) || (f >= gs->files))\r
1033       continue;\r
1034     if ((r < 0) || (r >= gs->ranks))\r
1035       continue;
1036     if ((gs->board[f][r] == NOPIECE) ||\r
1037         (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
1038       add_pos(f, r, posf, posr, numpos);\r
1039   }\r
1040 }\r
1041 \r
1042 static void possible_mandarin_moves(struct game_state_t * gs,\r
1043                                   int onf, int onr,\r
1044                                   int *posf, int *posr, int *numpos)\r
1045 {\r
1046   static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};\r
1047   int f, r;\r
1048   int j;\r
1049 \r
1050   for (j = 0; j < 4; j++) {\r
1051     f = kingJumps[j][0] + onf;\r
1052     r = kingJumps[j][1] + onr;\r
1053     if ((f < 0) || (f >= gs->files))\r
1054       continue;\r
1055     if ((r < 0) || (r >= gs->ranks))\r
1056       continue;
1057     if(gs->palace && (r >= gs->palace && r < gs->ranks - gs->palace ||
1058        f < (gs->files - gs->palace)/2 || f >= (gs->files + gs->palace)/2))
1059       continue;\r
1060     if ((gs->board[f][r] == NOPIECE) ||\r
1061         (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
1062       add_pos(f, r, posf, posr, numpos);\r
1063   }\r
1064 }\r
1065 \r
1066 static void possible_wazir_moves(struct game_state_t * gs,\r
1067                                   int onf, int onr,\r
1068                                   int *posf, int *posr, int *numpos)\r
1069 {\r
1070   static int kingJumps[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};\r
1071   int f, r;\r
1072   int j;\r
1073 \r
1074   for (j = 0; j < 4; j++) {\r
1075     f = kingJumps[j][0] + onf;\r
1076     r = kingJumps[j][1] + onr;\r
1077     if ((f < 0) || (f >= gs->files))\r
1078       continue;\r
1079     if ((r < 0) || (r >= gs->ranks))\r
1080       continue;\r
1081     if(gs->palace && (r >= gs->palace && r < gs->ranks - gs->palace ||
1082        f < (gs->files - gs->palace)/2 || f >= (gs->files + gs->palace)/2))
1083       continue;\r
1084     if ((gs->board[f][r] == NOPIECE) ||\r
1085         (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
1086       add_pos(f, r, posf, posr, numpos);\r
1087   }\r
1088 }\r
1089 \r
1090 static void possible_dababba_moves(struct game_state_t * gs,\r
1091                                   int onf, int onr,\r
1092                                   int *posf, int *posr, int *numpos)\r
1093 {\r
1094   static int kingJumps[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};\r
1095   int f, r;\r
1096   int j;\r
1097 \r
1098   for (j = 0; j < 4; j++) {\r
1099     f = 2*kingJumps[j][0] + onf;\r
1100     r = 2*kingJumps[j][1] + onr;\r
1101     if ((f < 0) || (f >= gs->files))\r
1102       continue;\r
1103     if ((r < 0) || (r >= gs->ranks))\r
1104       continue;\r
1105     if ((gs->board[f][r] == NOPIECE) ||\r
1106         (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
1107       add_pos(f, r, posf, posr, numpos);\r
1108   }\r
1109 }\r
1110 \r
1111 static void possible_man_moves(struct game_state_t * gs,\r
1112                                    int onf, int onr,
1113                                    int *posf, int *posr, int *numpos)
1114 {
1115   possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1116   possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1117 }
1118
1119 static void possible_dragonking_moves(struct game_state_t * gs,\r
1120                                    int onf, int onr,
1121                                    int *posf, int *posr, int *numpos)
1122 {
1123   possible_rook_moves(gs, onf, onr, posf, posr, numpos);
1124   possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1125 }
1126
1127 static void possible_dragonhorse_moves(struct game_state_t * gs,\r
1128                                    int onf, int onr,
1129                                    int *posf, int *posr, int *numpos)
1130 {
1131   possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1132   possible_bishop_moves(gs, onf, onr, posf, posr, numpos);
1133 }
1134
1135 static void possible_centaur_moves(struct game_state_t * gs,\r
1136                                    int onf, int onr,
1137                                    int *posf, int *posr, int *numpos)
1138 {
1139   possible_man_moves(gs, onf, onr, posf, posr, numpos);
1140   possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1141 }
1142
1143 static void possible_woody_moves(struct game_state_t * gs,\r
1144                                    int onf, int onr,
1145                                    int *posf, int *posr, int *numpos)
1146 {
1147   possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1148   possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
1149 }
1150
1151 static void possible_squirrel_moves(struct game_state_t * gs,\r
1152                                    int onf, int onr,
1153                                    int *posf, int *posr, int *numpos)
1154 {
1155   possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
1156   possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
1157   possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1158 }
1159
1160 static void possible_mastodon_moves(struct game_state_t * gs,\r
1161                                    int onf, int onr,
1162                                    int *posf, int *posr, int *numpos)
1163 {
1164   possible_man_moves(gs, onf, onr, posf, posr, numpos);
1165   possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
1166   possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
1167 }
1168
1169 static void possible_amazon_moves(struct game_state_t * gs,\r
1170                                    int onf, int onr,
1171                                    int *posf, int *posr, int *numpos)
1172 {
1173   possible_queen_moves(gs, onf, onr, posf, posr, numpos);
1174   possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1175 }
1176
1177 static void possible_modernelephant_moves(struct game_state_t * gs,\r
1178                                    int onf, int onr,
1179                                    int *posf, int *posr, int *numpos)
1180 {
1181   possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1182   possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
1183 }
1184
1185 static void possible_priestess_moves(struct game_state_t * gs,\r
1186                                    int onf, int onr,
1187                                    int *posf, int *posr, int *numpos)
1188 {
1189   possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1190   possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
1191   possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1192 }
1193
1194 static void possible_minister_moves(struct game_state_t * gs,\r
1195                                    int onf, int onr,
1196                                    int *posf, int *posr, int *numpos)
1197 {
1198   possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1199   possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
1200   possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1201 }
1202
1203 static void possible_gold_moves(struct game_state_t * gs,\r
1204                                    int onf, int onr,
1205                                    int *posf, int *posr, int *numpos)
1206 {
1207   possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1208   if(gs->onMove == WHITE) {
1209     if(onr < gs->ranks-1)
1210       if(onf > 0 && !iscolor(gs->board[onf-1][onr+1], WHITE))
1211         add_pos(onf-1, onr+1, posf, posr, numpos);\r
1212       if(onf < gs->files-1 && !iscolor(gs->board[onf+1][onr+1], WHITE))
1213         add_pos(onf+1, onr+1, posf, posr, numpos);\r
1214   } else {
1215     if(onr > 0)
1216       if(onf > 0 && !iscolor(gs->board[onf-1][onr-1], BLACK))
1217         add_pos(onf-1, onr-1, posf, posr, numpos);\r
1218       if(onf < gs->files-1 && !iscolor(gs->board[onf+1][onr-1], BLACK))
1219         add_pos(onf+1, onr-1, posf, posr, numpos);\r
1220   }
1221 }
1222
1223 static void possible_silver_moves(struct game_state_t * gs,\r
1224                                    int onf, int onr,
1225                                    int *posf, int *posr, int *numpos)
1226 {
1227   possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1228   if(gs->onMove == WHITE) {
1229     if(onr < gs->ranks-1 && !iscolor(gs->board[onf][onr+1], WHITE))
1230       add_pos(onf, onr+1, posf, posr, numpos);\r
1231   } else {
1232     if(onr > 0 && !iscolor(gs->board[onf][onr-1], BLACK))
1233       add_pos(onf, onr-1, posf, posr, numpos);\r
1234   }
1235 }
1236
1237 static void possible_honorablehorse_moves(struct game_state_t * gs,\r
1238                                   int onf, int onr,\r
1239                                   int *posf, int *posr, int *numpos)\r
1240 {\r
1241   int f, r = onr + (gs->onMove == WHITE ? 2 : -2);\r
1242
1243   if(r < 0 || r >= gs->ranks) return;\r
1244   if(onf > 0) {
1245     if ((gs->board[onf-1][r] == NOPIECE) ||\r
1246         (iscolor(gs->board[onf-1][r], CToggle(gs->onMove))))\r
1247       add_pos(onf - 1, r, posf, posr, numpos);\r
1248   }\r
1249   if(onf < gs->files - 1) {
1250     if ((gs->board[onf+1][r] == NOPIECE) ||\r
1251         (iscolor(gs->board[onf+1][r], CToggle(gs->onMove))))\r
1252       add_pos(onf + 1, r, posf, posr, numpos);\r
1253   }\r
1254 }\r
1255 \r
1256 static void possible_king_moves(struct game_state_t * gs,
1257                                   int onf, int onr,
1258                                   int *posf, int *posr, int *numpos)
1259 {
1260   if(gs->royalKnight)\r
1261     possible_knight_moves(gs, onf, onr, posf, posr, numpos);\r
1262   else if(gs->palace)
1263     possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1264   else\r
1265     possible_man_moves(gs, onf, onr, posf, posr, numpos);\r
1266 }
1267
1268 static void possible_elephant_moves(struct game_state_t * gs,
1269                                    int onf, int onr,
1270                                    int *posf, int *posr, int *numpos)
1271 {\r
1272   static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};\r
1273   int f, r;\r
1274   int j;\r
1275 \r
1276   for (j = 0; j < 4; j++) {\r
1277     f = 2*kingJumps[j][0] + onf;\r
1278     r = 2*kingJumps[j][1] + onr;\r
1279     if ((f < 0) || (f >= gs->files))\r
1280       continue;\r
1281     if ((r < 0) || (r >= gs->ranks))\r
1282       continue;\r
1283     if ((gs->board[(f+onf)/2][(r+onr)/2] == NOPIECE) && ((gs->board[f][r] == NOPIECE) ||\r
1284         (iscolor(gs->board[f][r], CToggle(gs->onMove)))))\r
1285       add_pos(f, r, posf, posr, numpos);\r
1286   }\r
1287 }\r
1288
1289 /* Doesn't check for check */
1290 int legal_move(struct game_state_t * gs,
1291                int fFile, int fRank,
1292                int tFile, int tRank)
1293 {
1294   int move_piece;
1295   int legal;
1296
1297   if (fFile == ALG_DROP) {
1298     move_piece = fRank;
1299     if(!gs->drops) return 0; // [HGM] variants: no drops in this variant
1300     if (move_piece == KING)
1301       return 0;
1302     if (gs->holding[gs->onMove==WHITE ? 0 : 1][move_piece-1] == 0)
1303       return 0;
1304     if (gs->board[tFile][tRank] != NOPIECE)
1305       return 0;
1306     if (gs->promoType == 3) { // Shogi
1307       int r;
1308       switch(move_piece) {
1309         case PAWN:  // check for own Pawn in same file
1310           for(r=0; r<gs->ranks; r++) if(gs->board[tFile][r] == (gs->onMove|PAWN)) return 0;
1311         case LANCE: // Pawns and Lances not on last rank
1312           if(gs->onMove == WHITE && tRank >= gs->ranks-1) return 0;
1313           if(gs->onMove == BLACK && tRank < 1) return 0;
1314           break;
1315         case HONORABLEHORSE: // Knights at least two ranks from edge
1316           if(gs->onMove == WHITE && tRank >= gs->ranks-2) return 0;
1317           if(gs->onMove == BLACK && tRank < 2) return 0;
1318         default: ;
1319       }
1320     } else
1321     if (move_piece == PAWN && (tRank == 0 || tRank == gs->ranks-1))
1322       return 0;
1323     return 1;
1324   } else if(fFile == ALG_CASTLE) {
1325         // [HGM] castle: this code can handle any type of free castling
1326         // it does not check if Rook and King from squares correspond to the rights, as the
1327         // user never enters such squares, but they are copied from the rights on entering o-o-o
1328         int backRank, kRook, qRook, fKing, leftEmpty, rightEmpty, leftCheck, rightCheck, f;
1329         if(!gs->castlingStyle) return 0;   // no castling in this variant
1330         if(gs->onMove == WHITE) {
1331                 if(gs->wkmoved < 0) return 0; // King moved
1332                 fKing = gs->wkmoved;
1333                 backRank = 0;
1334                 kRook = gs->wkrmoved;
1335                 qRook = gs->wqrmoved;
1336         } else {
1337                 if(gs->bkmoved < 0) return 0; // King moved
1338                 fKing = gs->bkmoved;
1339                 backRank = gs->ranks-1;
1340                 kRook = gs->bkrmoved;
1341                 qRook = gs->bqrmoved;
1342         }
1343         if((tRank > tFile ? qRook : kRook) < 0) return 0; // Rook moved
1344         // here we verified rights do exist, so from squares (fRank and fKing) must be valid
1345         if(gs->board[fRank][backRank] != (ROOK | gs->onMove) ) return 0; // only with own Rook
1346         if(gs->board[fKing][backRank] != (KING | gs->onMove) ) return 0; // only with own King
1347
1348         // by now we know that K and R are in correct position, and still have rights
1349         if(tRank > tFile) { // R ends right of K: q-side
1350                 leftEmpty  = fRank < tFile ? fRank+1 : tFile+1;
1351                 rightEmpty = tRank < fKing ? fKing-1 : tRank-1;
1352         } else { // k-side
1353                 leftEmpty  = tRank < fKing ? tRank+1 : fKing+1;
1354                 rightEmpty = fRank < tFile ? fRank-1 : tFile-1;
1355         }
1356         for(f=leftEmpty; f<=rightEmpty; f++) // check if other pieces block castling
1357                 if(f != fRank && f != fKing && gs->board[f][backRank] != NOPIECE) return 0;
1358
1359         leftCheck  = fKing < tFile ? fKing : tFile+1;
1360         rightCheck = fKing < tFile ? tFile-1 : fKing;
1361         for(f=leftCheck; f<=rightCheck; f++) // check if King passes attacked square or was in check
1362                 if(is_square_attacked(gs, f, backRank)) return 0;
1363
1364         return 1; // passed all tests
1365   } else {
1366     move_piece = piecetype(gs->board[fFile][fRank]);
1367   }
1368   if (gs->board[fFile][fRank] == NOPIECE)
1369     return 0;
1370   if (!iscolor(gs->board[fFile][fRank], gs->onMove))    /* Wrong color */
1371     return 0;
1372   if ((gs->board[tFile][tRank] != NOPIECE) &&
1373       iscolor(gs->board[tFile][tRank], gs->onMove))     /* Can't capture own */
1374     return 0;
1375   if ((fFile == tFile) && (fRank == tRank))     /* Same square */
1376     return 0;
1377   switch (move_piece) {
1378   case PAWN:
1379     legal = legal_pawn_move(gs, fFile, fRank, tFile, tRank);
1380     break;
1381   case KNIGHT:
1382     legal = legal_knight_move(gs, fFile, fRank, tFile, tRank);
1383     break;
1384   case BISHOP:
1385     legal = legal_bishop_move(gs, fFile, fRank, tFile, tRank);
1386     break;
1387   case ROOK:
1388     legal = legal_rook_move(gs, fFile, fRank, tFile, tRank);
1389     break;
1390   case CARDINAL:\r
1391   case PRINCESS:\r
1392     legal = legal_cardinal_move(gs, fFile, fRank, tFile, tRank);\r
1393     break;\r
1394   case MARSHALL:\r
1395   case EMPRESS:\r
1396     legal = legal_marshall_move(gs, fFile, fRank, tFile, tRank);\r
1397     break;\r
1398   case MAN:\r
1399   case MAN2:\r
1400     legal = legal_man_move(gs, fFile, fRank, tFile, tRank);\r
1401     break;\r
1402   case QUEEN:
1403     legal = legal_queen_move(gs, fFile, fRank, tFile, tRank);
1404     break;
1405   case ELEPHANT:
1406     legal = legal_elephant_move(gs, fFile, fRank, tFile, tRank);
1407     break;
1408   case AMAZON:
1409     legal = legal_amazon_move(gs, fFile, fRank, tFile, tRank);
1410     break;
1411   case WOODY:
1412     legal = legal_woody_move(gs, fFile, fRank, tFile, tRank);
1413     break;
1414   case SQUIRREL:
1415     legal = legal_squirrel_move(gs, fFile, fRank, tFile, tRank);
1416     break;
1417   case MASTODON:
1418     legal = legal_mastodon_move(gs, fFile, fRank, tFile, tRank);
1419     break;
1420   case CENTAUR:
1421     legal = legal_centaur_move(gs, fFile, fRank, tFile, tRank);
1422     break;
1423   case HORSE:
1424     legal = legal_horse_move(gs, fFile, fRank, tFile, tRank);
1425     break;
1426   case FERZ:
1427   case FERZ2:
1428     legal = legal_ferz_move(gs, fFile, fRank, tFile, tRank);
1429     break;
1430   case MANDARIN:
1431     legal = legal_mandarin_move(gs, fFile, fRank, tFile, tRank);
1432     break;
1433   case WAZIR:
1434     legal = legal_wazir_move(gs, fFile, fRank, tFile, tRank);
1435     break;
1436   case ALFIL:
1437   case ALFIL2:
1438     legal = legal_alfil_move(gs, fFile, fRank, tFile, tRank);
1439     break;
1440   case MODERNELEPHANT:
1441     legal = legal_modernelephant_move(gs, fFile, fRank, tFile, tRank);
1442     break;
1443   case PRIESTESS:
1444     legal = legal_priestess_move(gs, fFile, fRank, tFile, tRank);
1445     break;
1446   case MINISTER:
1447     legal = legal_minister_move(gs, fFile, fRank, tFile, tRank);
1448     break;
1449   case SILVER:
1450     legal = legal_silver_move(gs, fFile, fRank, tFile, tRank);
1451     break;
1452   case GOLD:
1453     legal = legal_gold_move(gs, fFile, fRank, tFile, tRank);
1454     break;
1455   case LANCE:
1456     legal = legal_lance_move(gs, fFile, fRank, tFile, tRank);
1457     break;
1458   case CANNON:
1459     legal = legal_cannon_move(gs, fFile, fRank, tFile, tRank);
1460     break;
1461   case DRAGONHORSE:
1462     legal = legal_dragonhorse_move(gs, fFile, fRank, tFile, tRank);
1463     break;
1464   case DRAGONKING:
1465     legal = legal_dragonking_move(gs, fFile, fRank, tFile, tRank);
1466     break;
1467   case HONORABLEHORSE:
1468     legal = legal_honorablehorse_move(gs, fFile, fRank, tFile, tRank);
1469     break;
1470   case KING:
1471     legal = legal_king_move(gs, fFile, fRank, tFile, tRank);
1472     break;
1473   default:
1474     return 0;
1475     break;
1476   }
1477   return legal;
1478 }
1479
1480 #define DROP_CHAR '@'
1481
1482 /* This fills in the rest of the mt structure once it is determined that
1483  * the move is legal. Returns MOVE_ILLEGAL if move leaves you in check */
1484 static int move_calculate(struct game_state_t * gs, struct move_t * mt, int promote)
1485 {
1486   struct game_state_t fakeMove;\r
1487 \r
1488   mt->pieceCaptured = gs->board[mt->toFile][mt->toRank];\r
1489   mt->enPassant = 0;            /* Don't know yet, let execute move take care\r
1490                                    of it */\r
1491   if (mt->fromFile == ALG_DROP) {\r
1492     mt->piecePromotionTo = NOPIECE;\r
1493     sprintf(mt->moveString, "%s/%c%c-%c%d",\r
1494             wpstring[mt->fromRank],\r
1495                 DROP_CHAR, DROP_CHAR,\r
1496             mt->toFile + 'a', mt->toRank + 1 - (gs->ranks>9));\r
1497   } else if(mt->fromFile == ALG_CASTLE) { 
1498         // [HGM] castle: generalized castling, fr and tr give from and to file of Rook.
1499             sprintf(mt->moveString, mt->toRank > mt->toFile ? "o-o-o" : "o-o");
1500   } else {
1501   if(gs->promoType == 3) { // Shogi-style promotions: not just Pawns, but many pieces can promote
1502     int piece = gs->board[mt->fromFile][mt->fromRank];
1503     mt->piecePromotionTo = NOPIECE;
1504     if(colorval(piece) == WHITE && mt->fromRank < gs->ranks - gs->ranks/3
1505                                 && mt->toRank   < gs->ranks - gs->ranks/3 ||
1506        colorval(piece) == BLACK && mt->fromRank >= gs->ranks/3
1507                                 && mt->toRank   >= gs->ranks/3 )
1508         promote = NOPIECE; // suppress promotion outside zone
1509     if(promote) { // promotion piece determined by original, no matter what was requested
1510       switch(piecetype(piece)) {
1511         case PAWN:
1512         case LANCE:
1513         case HONORABLEHORSE:
1514         case SILVER:
1515           promote = GOLD; break;
1516         case BISHOP:
1517           promote = DRAGONHORSE; break;
1518         case ROOK:
1519           promote = DRAGONKING; break;
1520         default: promote = NOPIECE; // not a promotion
1521       }
1522     } else
1523       switch(piecetype(piece)) { // force mandatory promotions
1524         case HONORABLEHORSE:
1525           if(mt->toRank == 1 || mt->toRank == gs->files-2) promote = GOLD;
1526         case PAWN:
1527         case LANCE:
1528           if(mt->toRank == 0 || mt->toRank == gs->files-1) promote = GOLD;
1529         default: break;
1530       }
1531     if(promote) mt->piecePromotionTo = promote | (colorval(gs->board[mt->fromFile][mt->fromRank]));\r
1532   } else
1533   if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) && 
1534         !gs->palace && // [HGM] XQ: no promotions in xiangqi\r
1535       ((mt->toRank < gs->promoZone) || (mt->toRank >= gs->ranks - gs->promoZone))) {
1536     int stm = colorval(gs->board[mt->fromFile][mt->fromRank]);
1537     if(!promote && (mt->toRank == 0 || mt->toRank == gs->ranks-1)) { // promotion obligatory, but not specified
1538         if(gs->promoType != 2) promote = QUEEN; else { // choose a default
1539             for(promote=KING-1; promote>PAWN; promote--) if(gs->holding[stm == BLACK][promote-1]) break;
1540             if(promote == PAWN) return MOVE_ILLEGAL; // nothing available
1541         }
1542     } // if not obligatory, we defer unless promoton was explicitly specified!
1543     if(!gs->pawnDblStep && promote == PRINCESS) promote = MAN2;
1544     if(!gs->pawnDblStep && promote != FERZ2 && promote != MAN2) promote = FERZ; // [HGM] kludge to recognize shatranj
1545     // non-promotion can still be an option for deeper promotion zones
1546     mt->piecePromotionTo = promote ? (promote | stm) : NOPIECE;
1547     if(promote && gs->promoType == 2 && !gs->holding[stm == BLACK][promote-1]) return MOVE_ILLEGAL; // unavailable piece specified
1548   } else {\r
1549     mt->piecePromotionTo = NOPIECE;\r
1550   }\r
1551   if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) &&\r
1552    ((mt->fromRank - mt->toRank == 2) || (mt->toRank - mt->fromRank == 2))) {\r
1553     mt->doublePawn = mt->fromFile;\r
1554   } else {\r
1555     mt->doublePawn = -1;\r
1556   }
1557 #if 0
1558   if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) &&\r
1559       (mt->fromFile == gs->files/2) && (mt->toFile == 2) &&
1560        mt->fromRank == mt->toRank) {\r
1561     sprintf(mt->moveString, "o-o-o");\r
1562   } else if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) &&\r
1563              (mt->fromFile == gs->files/2) && (mt->toFile == gs->files-2) &&
1564                 mt->fromRank == mt->toRank) {\r
1565     sprintf(mt->moveString, "o-o");
1566   } else {
1567 #else
1568   {
1569 #endif\r
1570     sprintf(mt->moveString, "%s/%c%d-%c%d",\r
1571             wpstring[piecetype(gs->board[mt->fromFile][mt->fromRank])],\r
1572             mt->fromFile + 'a', mt->fromRank + 1 - (gs->ranks>9),\r
1573             mt->toFile + 'a', mt->toRank + 1 - (gs->ranks>9));\r
1574   }\r
1575   }\r
1576   /* Replace this with an algabraic de-parser */\r
1577 \r
1578   sprintf(mt->algString, alg_unparse(gs, mt));\r
1579   fakeMove = *gs;\r
1580   /* Calculates enPassant also */
1581   execute_move(&fakeMove, mt, 0);\r
1582 \r
1583   /* Does making this move leave ME in check? */\r
1584   if (in_check(&fakeMove))\r
1585     return MOVE_ILLEGAL;\r
1586   /* IanO: bughouse variants: drop cannot be check/checkmate */\r
1587 \r
1588   return MOVE_OK;\r
1589 }
1590
1591 int legal_andcheck_move(struct game_state_t * gs,
1592                         int fFile, int fRank,
1593                         int tFile, int tRank)
1594 {
1595   struct move_t mt;
1596
1597   if (!legal_move(gs, fFile, fRank, tFile, tRank))
1598     return 0;
1599   mt.color = gs->onMove;
1600   mt.fromFile = fFile;
1601   mt.fromRank = fRank;
1602   mt.toFile = tFile;
1603   mt.toRank = tRank;
1604   /* This should take into account a pawn promoting to another piece */
1605   if (move_calculate(gs, &mt, NOPIECE) == MOVE_OK) 
1606     return 1;
1607   else
1608     return 0;
1609 }
1610
1611 /* in_check: checks if the side that is NOT about to move is in check 
1612  */
1613 int in_check(struct game_state_t * gs)
1614 {
1615   int f, r;\r
1616   int kf = -1, kr = -1;\r
1617 \r
1618   /* Find the king */\r
1619   if (gs->onMove == WHITE) {\r
1620     for (f = 0; f < gs->files && kf < 0; f++)\r
1621       for (r = 0; r < gs->ranks && kf < 0; r++)\r
1622         if (gs->board[f][r] == B_KING) {\r
1623           kf = f;\r
1624           kr = r;\r
1625         }\r
1626   } else {\r
1627     for (f = 0; f < gs->files && kf < 0; f++)\r
1628       for (r = 0; r < gs->ranks && kf < 0; r++)\r
1629         if (gs->board[f][r] == W_KING) {\r
1630           kf = f;\r
1631           kr = r;\r
1632         }\r
1633   }\r
1634   if (kf < 0) {\r
1635     d_printf( "CHESSD: Error game with no king!\n");\r
1636     return 0;\r
1637   }\r
1638   for (InitPieceLoop(gs->board, &f, &r, gs->onMove);\r
1639        NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {\r
1640     if (legal_move(gs, f, r, kf, kr)) { /* In Check? */
1641       return 1;\r
1642     }\r
1643   }\r
1644   return 0;\r
1645 }
1646
1647 int has_legal_move(struct game_state_t * gs)
1648 {
1649   int i;
1650   int f, r;
1651   int kf = 0, kr = 0;
1652   int possiblef[500], possibler[500];
1653   int numpossible = 0;
1654
1655   for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
1656        NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {
1657     switch (piecetype(gs->board[f][r])) {
1658     case PAWN:
1659       possible_pawn_moves(gs, f, r, possiblef, possibler, &numpossible);
1660       break;
1661     case KNIGHT:
1662       possible_knight_moves(gs, f, r, possiblef, possibler, &numpossible);
1663       break;
1664     case BISHOP:
1665       possible_bishop_moves(gs, f, r, possiblef, possibler, &numpossible);
1666       break;
1667     case ROOK:
1668       possible_rook_moves(gs, f, r, possiblef, possibler, &numpossible);
1669       break;
1670     case CARDINAL:\r
1671     case PRINCESS:\r
1672       possible_cardinal_moves(gs, f, r, possiblef, possibler, &numpossible);\r
1673       break;\r
1674     case MARSHALL:\r
1675     case EMPRESS:\r
1676       possible_marshall_moves(gs, f, r, possiblef, possibler, &numpossible);\r
1677       break;\r
1678     case MAN:\r
1679     case MAN2:\r
1680       possible_man_moves(gs, f, r, possiblef, possibler, &numpossible);\r
1681       break;\r
1682     case QUEEN:
1683       possible_queen_moves(gs, f, r, possiblef, possibler, &numpossible);
1684       break;
1685     case ELEPHANT:
1686       possible_elephant_moves(gs, f, r, possiblef, possibler, &numpossible);
1687       break;
1688     case AMAZON:
1689       possible_amazon_moves(gs, f, r, possiblef, possibler, &numpossible);
1690       break;
1691     case WOODY:
1692       possible_woody_moves(gs, f, r, possiblef, possibler, &numpossible);
1693       break;
1694     case SQUIRREL:
1695       possible_squirrel_moves(gs, f, r, possiblef, possibler, &numpossible);
1696       break;
1697     case MASTODON:
1698       possible_mastodon_moves(gs, f, r, possiblef, possibler, &numpossible);
1699       break;
1700     case CENTAUR:
1701       possible_centaur_moves(gs, f, r, possiblef, possibler, &numpossible);
1702       break;
1703     case HORSE:
1704       possible_horse_moves(gs, f, r, possiblef, possibler, &numpossible);
1705       break;
1706     case FERZ:
1707     case FERZ2:
1708       possible_ferz_moves(gs, f, r, possiblef, possibler, &numpossible);
1709       break;
1710     case MANDARIN:
1711       possible_mandarin_moves(gs, f, r, possiblef, possibler, &numpossible);
1712       break;
1713     case WAZIR:
1714       possible_wazir_moves(gs, f, r, possiblef, possibler, &numpossible);
1715       break;
1716     case ALFIL:
1717     case ALFIL2:
1718       possible_alfil_moves(gs, f, r, possiblef, possibler, &numpossible);
1719       break;
1720     case MODERNELEPHANT:
1721       possible_modernelephant_moves(gs, f, r, possiblef, possibler, &numpossible);
1722       break;
1723     case PRIESTESS:
1724       possible_priestess_moves(gs, f, r, possiblef, possibler, &numpossible);
1725       break;
1726     case MINISTER:
1727       possible_minister_moves(gs, f, r, possiblef, possibler, &numpossible);
1728       break;
1729     case SILVER:
1730       possible_silver_moves(gs, f, r, possiblef, possibler, &numpossible);
1731       break;
1732     case GOLD:
1733       possible_gold_moves(gs, f, r, possiblef, possibler, &numpossible);
1734       break;
1735     case CANNON:
1736       possible_cannon_moves(gs, f, r, possiblef, possibler, &numpossible);
1737       break;
1738     case LANCE:
1739       possible_lance_moves(gs, f, r, possiblef, possibler, &numpossible);
1740       break;
1741     case DRAGONHORSE:
1742       possible_dragonhorse_moves(gs, f, r, possiblef, possibler, &numpossible);
1743       break;
1744     case DRAGONKING:
1745       possible_dragonking_moves(gs, f, r, possiblef, possibler, &numpossible);
1746       break;
1747     case HONORABLEHORSE:
1748       possible_honorablehorse_moves(gs, f, r, possiblef, possibler, &numpossible);
1749       break;
1750     case KING:
1751       kf = f;
1752       kr = r;
1753       possible_king_moves(gs, f, r, possiblef, possibler, &numpossible);
1754       break;
1755     }
1756     if (numpossible >= 500) {
1757       d_printf( "CHESSD: Possible move overrun\n");
1758     }
1759     for (i = 0; i < numpossible; i++)
1760       if (legal_andcheck_move(gs, f, r, possiblef[i], possibler[i])) {
1761         return 1;
1762       }
1763   }
1764
1765   /* IanO:  if we got here, then kf and kr must be set */\r
1766   if (gs->gameNum >=0 && game_globals.garray[gs->gameNum].link >= 0
1767         || gs->holdings) { // [HGM] zh: also in 2-player games with drops\r
1768     /* bughouse: potential drops as check interpositions */\r
1769     gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]++;\r
1770     for (f=kf-1; f<=kf+1; f++) for (r=kr-1; r<=kr+1; r++) {\r
1771       if (f>=0 && f<gs->files && r>=0 && r<gs->ranks && gs->board[f][r] == NOPIECE) {\r
1772         /* try a drop next to the king */\r
1773         if (legal_andcheck_move(gs, ALG_DROP, QUEEN, f, r)) {\r
1774           gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--;
1775           // OK, so we have an interposing drop. But do we have something to drop?
1776           if(game_globals.garray[gs->gameNum].link < 0) {
1777                 // we have no partner, so we must have something to drop now
1778                 for(i=QUEEN; i>=PAWN; i--)
1779                         if (legal_andcheck_move(gs, ALG_DROP, i, f, r)) return 1;\r
1780                 return 0;
1781           }\r
1782           return 1;\r
1783         }\r
1784       }\r
1785     }\r
1786     gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--;\r
1787   }\r
1788
1789   return 0;
1790 }
1791
1792 /* This will end up being a very complicated function */
1793 int parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt, int promote)
1794 {
1795   int type = is_move(mstr);\r
1796   int result;\r
1797 \r
1798   mt->piecePromotionTo = NOPIECE;\r
1799   mt->color = gs->onMove;\r
1800   switch (type) {\r
1801   case MS_NOTMOVE:\r
1802     return MOVE_ILLEGAL;\r
1803     break;\r
1804   case MS_COMP:\r
1805     mt->fromFile = mstr[0] - 'a';\r
1806     mt->fromRank = mstr[1] - '1' + (gs->ranks>9);\r
1807     mt->toFile = mstr[2] - 'a';\r
1808     mt->toRank = mstr[3] - '1' + (gs->ranks>9);\r
1809     break;\r
1810   case MS_COMPDASH:\r
1811     mt->fromFile = mstr[0] - 'a';\r
1812     mt->fromRank = mstr[1] - '1' + (gs->ranks>9);\r
1813     mt->toFile = mstr[3] - 'a';\r
1814     mt->toRank = mstr[4] - '1' + (gs->ranks>9);\r
1815     break;\r
1816   case MS_KCASTLE:\r
1817 #if 0
1818     mt->fromFile = gs->files/2;\r
1819     mt->toFile = gs->files-2;\r
1820     if (gs->onMove == WHITE) {\r
1821       mt->fromRank = 0;\r
1822       mt->toRank = 0;\r
1823     } else {\r
1824       mt->fromRank = gs->ranks-1;\r
1825       mt->toRank = gs->ranks-1;\r
1826     }\r
1827     break;
1828 #endif
1829     // [HGM] castle: for now always assume Fischer-type castling (of which normal castling is a special case).
1830     mt->fromFile = ALG_CASTLE;\r
1831     mt->toFile = gs->files-2;\r
1832     mt->fromRank = gs->onMove == WHITE ? gs->wkrmoved : gs->bkrmoved;\r
1833     mt->toRank = mt->toFile-1; // R next to K\r
1834     break;    \r
1835   case MS_QCASTLE:
1836 #if 0\r
1837     mt->fromFile = gs->files/2;\r
1838     mt->toFile = 2;\r
1839     if (gs->onMove == WHITE) {\r
1840       mt->fromRank = 0;\r
1841       mt->toRank = 0;\r
1842     } else {\r
1843       mt->fromRank = gs->ranks-1;\r
1844       mt->toRank = gs->ranks-1;\r
1845     }\r
1846     break;
1847 #endif\r
1848     mt->fromFile = ALG_CASTLE;\r
1849     mt->toFile = 2;\r
1850     mt->fromRank = gs->onMove == WHITE ? gs->wqrmoved : gs->bqrmoved;\r
1851     mt->toRank = mt->toFile+1;
1852     break;\r
1853   case MS_ALG:\r
1854     /* Fills in the mt structure */\r
1855     if ((result = alg_parse_move(mstr, gs, mt)) != MOVE_OK)\r
1856       return result;\r
1857     break;\r
1858   default:\r
1859     return MOVE_ILLEGAL;\r
1860     break;\r
1861   }
1862   if((mt->fromRank >= gs->ranks || mt->fromRank < 0 || mt->fromFile >= gs->files) &&
1863      mt->fromFile != ALG_DROP && mt->fromFile != ALG_CASTLE\r
1864      || mt->toRank < 0 || mt->toRank >= gs->ranks || mt->toFile >= gs->files)\r
1865     return MOVE_ILLEGAL; // [HGM] make sure move stays on board
1866 \r
1867   if (!(result = legal_move(gs, mt->fromFile, mt->fromRank, mt->toFile, mt->toRank)))
1868     return MOVE_ILLEGAL;\r
1869
1870   if(result == 2) { // [HGM] castle: orthodox castling was given as King move; convert it to new format
1871         if(mt->fromFile - mt->toFile > 1) { // Q-side
1872                 mt->fromRank = 0; 
1873                 mt->toRank   = mt->toFile+1;
1874         } else if(mt->toFile - mt->fromFile > 1) { // K-side
1875                 mt->fromRank = gs->files-1;
1876                 mt->toRank   = mt->toFile-1;
1877         }
1878         mt->fromFile = ALG_CASTLE;
1879     }\r
1880 \r
1881   if (mt->piecePromotionTo != NOPIECE) {
1882           promote = piecetype(mt->piecePromotionTo);\r
1883   }\r
1884 \r
1885   return move_calculate(gs, mt, promote);\r
1886 }
1887
1888 /* Returns MOVE_OK, MOVE_NOMATERIAL, MOVE_CHECKMATE, or MOVE_STALEMATE */
1889 /* check_game_status prevents recursion */
1890 int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_status)
1891 {
1892   int movedPiece;
1893   int tookPiece;
1894   int i, j, foobar, wCnt, bCnt, king, rook;
1895
1896   if (mt->fromFile == ALG_DROP) {
1897     movedPiece = mt->fromRank;
1898     tookPiece = NOPIECE;
1899     gs->holding[gs->onMove==WHITE ? 0 : 1][movedPiece-1]--;
1900     gs->board[mt->toFile][mt->toRank] = movedPiece | gs->onMove;
1901     if (gs->gameNum >= 0)
1902       gs->lastIrreversable = game_globals.garray[gs->gameNum].numHalfMoves;
1903   } else if(mt->fromFile == ALG_CASTLE) {
1904     int backRank, fKing;
1905     // [HGM] castle: perform castling
1906     if(gs->onMove == WHITE) {
1907         backRank = 0;
1908         fKing = gs->wkmoved;
1909         gs->wkmoved = -gs->wkmoved-2;
1910     } else {
1911         backRank = gs->ranks-1;
1912         fKing = gs->bkmoved;
1913         gs->bkmoved = -gs->bkmoved-2;
1914     }
1915     // move Rook & King, in a way that is resistant to ending where they started (for FRC!)
1916     rook = gs->board[mt->fromRank][backRank];    // first remember\r
1917     king = gs->board[fKing][backRank];\r
1918     gs->board[mt->fromRank][backRank] = NOPIECE; // then erase\r    gs->board[fKing][backRank] = NOPIECE;\r    gs->board[mt->toRank][backRank] = rook;      // then put back
1919     gs->board[mt->toFile][backRank] = king;
1920   } else {
1921   movedPiece = gs->board[mt->fromFile][mt->fromRank];
1922   tookPiece = gs->board[mt->toFile][mt->toRank];
1923   if (mt->piecePromotionTo == NOPIECE) {
1924     gs->board[mt->toFile][mt->toRank] = gs->board[mt->fromFile][mt->fromRank];
1925   } else {
1926     gs->board[mt->toFile][mt->toRank] = mt->piecePromotionTo | gs->onMove;
1927     if(gs->promoType == 2) gs->holding[gs->onMove][mt->piecePromotionTo-1]--;
1928   }
1929   gs->board[mt->fromFile][mt->fromRank] = NOPIECE;
1930   /* Check if irreversable */
1931   if ((piecetype(movedPiece) == PAWN) && (mt->fromRank != mt->toRank) // [HGM] XQ: sideway Pawn move reversible!
1932                         || (tookPiece != NOPIECE)) {
1933     if (gs->gameNum >= 0)
1934       gs->lastIrreversable = game_globals.garray[gs->gameNum].numHalfMoves;
1935   }
1936   /* Check if this move is en-passant */
1937   if ((piecetype(movedPiece) == PAWN) && (mt->fromFile != mt->toFile) &&
1938       (tookPiece == NOPIECE) && !gs->palace) { // [HGM] XQ: no e.p. in sideway xiangqi moves
1939     if (gs->onMove == WHITE) {
1940       mt->pieceCaptured = B_PAWN;
1941     } else {
1942       mt->pieceCaptured = W_PAWN;
1943     }
1944     if (mt->fromFile > mt->toFile) {
1945       mt->enPassant = -1;
1946     } else {
1947       mt->enPassant = 1;
1948     }
1949     gs->board[mt->toFile][mt->fromRank] = NOPIECE;
1950   }
1951   /* Check en-passant flags for next moves */\r
1952   for (i = 0; i < gs->files; i++) {\r
1953     gs->ep_possible[0][i] = 0;\r
1954     gs->ep_possible[1][i] = 0;\r
1955   }
1956 /* Added by Sparky 3/16/95
1957
1958    From soso@Viktoria.drp.fmph.uniba.sk Thu Mar 16 13:08:51 1995
1959    Subject: Re: To DAV: enpassant prob. again
1960    To: chess@caissa.onenet.net (ICS)
1961    Date: Thu, 16 Mar 1995 20:06:20 +0100 (MET)
1962
1963    Yeah !
1964    There was bug in other part of code:
1965
1966    movecheck.c , line about 800:
1967
1968      if (gs->onMove == WHITE) {
1969         if ((mt->toFile+1 < 7 ) ....  should be : (mt->toFile < 7 ) }
1970 */
1971
1972   if ((piecetype(movedPiece) == PAWN) &&\r
1973    ((mt->fromRank == mt->toRank + 2) || (mt->fromRank + 2 == mt->toRank))) {\r
1974     /* Should turn on enpassent flag if possible */\r
1975     if (gs->onMove == WHITE) {\r
1976       if ((mt->toFile < gs->files-1) && gs->board[mt->toFile + 1][mt->toRank] == B_PAWN) {\r
1977         gs->ep_possible[1][mt->toFile + 1] = -1;\r
1978       }\r
1979       if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][mt->toRank] == B_PAWN) {\r
1980         gs->ep_possible[1][mt->toFile - 1] = 1;\r
1981       }\r
1982     } else {\r
1983       if ((mt->toFile < gs->files-1) && gs->board[mt->toFile + 1][mt->toRank] == W_PAWN) {\r
1984         gs->ep_possible[0][mt->toFile + 1] = -1;\r
1985       }\r
1986       if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][mt->toRank] == W_PAWN) {\r
1987         gs->ep_possible[0][mt->toFile - 1] = 1;\r
1988       }\r
1989     }\r
1990   }\r
1991   if ((piecetype(movedPiece) == ROOK) && (mt->fromRank == 0) && (gs->onMove == WHITE)) {\r
1992     if (mt->fromFile == gs->wqrmoved) // [HGM] castle: flip w.r.t. -1 to remember original\r
1993       gs->wqrmoved = -gs->wqrmoved-2;\r
1994     if (mt->fromFile == gs->wkrmoved)\r
1995       gs->wkrmoved = -gs->wkrmoved-2;\r
1996   }\r
1997   if ((piecetype(movedPiece) == ROOK) && (mt->fromRank == gs->ranks-1) && (gs->onMove == BLACK)) {\r
1998     if (mt->fromFile == gs->bqrmoved)\r
1999       gs->bqrmoved = -gs->bqrmoved-2;\r
2000     if (mt->fromFile == gs->bkrmoved)\r
2001       gs->bkrmoved = -gs->bkrmoved-2;\r
2002   }\r
2003   if (piecetype(movedPiece) == KING) {\r
2004     if ((gs->onMove == WHITE) && (mt->fromFile == gs->wkmoved))\r
2005       gs->wkmoved = -gs->wkmoved-2;\r
2006     if ((gs->onMove == BLACK) && (mt->fromFile == gs->bkmoved))\r
2007       gs->bkmoved = -gs->bkmoved-2;\r
2008   }
2009 #if 0\r
2010   if ((piecetype(movedPiece) == KING) &&\r
2011       ((mt->fromFile == gs->files/2) && (mt->toFile == gs->files-2)) &&
2012         mt->fromRank == mt->toRank) {   /* Check for KS castling */\r
2013     gs->board[gs->files-3][mt->toRank] = gs->board[gs->files-1][mt->toRank];\r
2014     gs->board[gs->files-1][mt->toRank] = NOPIECE;\r
2015   }\r
2016   if ((piecetype(movedPiece) == KING) &&\r
2017       ((mt->fromFile == gs->files/2) && (mt->toFile == 2)) &&
2018         mt->fromRank == mt->toRank) {   /* Check for QS castling */\r
2019     gs->board[3][mt->toRank] = gs->board[0][mt->toRank];\r
2020     gs->board[0][mt->toRank] = NOPIECE;\r
2021   }
2022 #endif\r
2023   }\r
2024   if (gs->onMove == BLACK)\r
2025     gs->moveNum++;\r
2026 \r
2027   if (check_game_status) {\r
2028     /* Does this move result in check? */\r
2029     if (in_check(gs)) {\r
2030       /* Check for checkmate */\r
2031       gs->onMove = CToggle(gs->onMove);\r
2032       if (!has_legal_move(gs))\r
2033         return MOVE_CHECKMATE;\r
2034     } else {\r
2035       /* Check for stalemate */\r
2036       gs->onMove = CToggle(gs->onMove);\r
2037       if (!has_legal_move(gs))\r
2038         return gs->stalemate ? MOVE_STALEMATE : MOVE_CHECKMATE; // [HGM] in XQ and shatranj stalemate loses\r
2039     }\r
2040 /* loon: check for insufficient mating material, first try */\r
2041       foobar = wCnt = bCnt = 0;\r
2042       for (i=0; i<gs->files; i++) {\r
2043         for (j=0; j<gs->ranks; j++) {
2044           int p = gs->board[i][j];\r
2045           switch(piecetype(p)) {\r
2046             case KNIGHT:\r
2047             case BISHOP:\r
2048               foobar++;\r
2049               break;\r
2050             case KING:\r
2051             case NOPIECE:\r
2052               break;\r
2053             default:\r
2054               foobar = 2;\r
2055               break;\r
2056           }
2057           if(p != NOPIECE && iscolor(p, WHITE)) wCnt++;
2058           if(iscolor(p, BLACK)) bCnt++;\r
2059         }\r
2060       }
2061       if(gs->bareKingLoses) { // [HGM] with bare-King-loses rule only KK is insuff. material
2062         if(gs->onMove == BLACK && wCnt == 1 && bCnt > 1) return MOVE_BARE;
2063         if(gs->onMove == WHITE && bCnt == 1 && wCnt > 1) return MOVE_BARE;
2064         if(bCnt == 1 && wCnt == 1) return MOVE_NOMATERIAL;
2065       } else if (foobar < 2)\r
2066         return MOVE_NOMATERIAL;\r
2067   } else {\r
2068     gs->onMove = CToggle(gs->onMove);\r
2069   }
2070 \r
2071   return MOVE_OK;\r
2072 }
2073
2074 int backup_move(int g, int mode)
2075 {
2076   struct game_state_t *gs;
2077   struct move_t *m, *m1;
2078   int now, i;
2079
2080   if (game_globals.garray[g].link >= 0) /*IanO: not implemented for bughouse yet */
2081     return MOVE_ILLEGAL;
2082   if (game_globals.garray[g].numHalfMoves < 1)
2083     return MOVE_ILLEGAL;
2084   gs = &game_globals.garray[g].game_state;
2085   m = (mode==REL_GAME) ? &game_globals.garray[g].moveList[game_globals.garray[g].numHalfMoves - 1] : 
2086                          &game_globals.garray[g].examMoveList[game_globals.garray[g].numHalfMoves - 1];
2087   if (m->toFile < 0) {
2088     return MOVE_ILLEGAL;
2089   }
2090   if(m->fromFile == ALG_CASTLE) {
2091     // [HGM] castling in new format. Derive K and R moves
2092     int rank, kingFromFile;
2093     if(m->color == WHITE) {
2094       rank = 0;
2095       kingFromFile = -gs->wkmoved-2;
2096       if(kingFromFile<0) kingFromFile = -kingFromFile-2; // safety catch; should never happen?
2097       gs->wkmoved = kingFromFile;
2098       if(m->toRank > m->toFile) gs->wqrmoved = m->fromRank;
2099       else gs->wkrmoved = m->fromRank;
2100     } else {
2101       rank = gs->ranks-1;
2102       kingFromFile = -gs->bkmoved-2;
2103       if(kingFromFile<0) kingFromFile = -kingFromFile-2; // safety catch; should never happen?
2104       gs->bkmoved = kingFromFile;
2105       if(m->toRank > m->toFile) gs->bqrmoved = m->fromRank;
2106       else gs->bkrmoved = m->fromRank;
2107     }
2108     // remove first, as one might come back to a square the other left
2109     gs->board[m->toFile  ][rank] = NOPIECE; // King toSqr
2110     gs->board[m->toRank  ][rank] = NOPIECE; // Rook toSqr
2111     gs->board[m->fromRank][rank] = ROOK | m->color; // Rook fromSqr
2112     gs->board[kingFromFile][rank] = KING | m->color; // King fromSquare
2113     goto cleanupMove;
2114   }
2115   gs->board[m->fromFile][m->fromRank] = gs->board[m->toFile][m->toRank];
2116   if (m->piecePromotionTo != NOPIECE) {
2117     gs->board[m->fromFile][m->fromRank] = PAWN |
2118       colorval(gs->board[m->fromFile][m->fromRank]);
2119   }
2120   /******************
2121      When takeback a _first_ move of rook, the ??rmoved variable
2122      must be cleared . To check, if the move is first, we should
2123      scan moveList.
2124   *******************/
2125   if (piecetype(gs->board[m->fromFile][m->fromRank]) == ROOK) {
2126     if (m->color == WHITE) {
2127       if ((m->fromFile == -gs->wqrmoved-2) && (m->fromRank == 0)) {
2128         for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
2129           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
2130           if ((m1->fromFile == -gs->wqrmoved-2) && (m1->fromRank == 0))
2131             break;
2132         }
2133         if (i == game_globals.garray[g].numHalfMoves - 1)
2134           gs->wqrmoved = m->fromFile;
2135       }
2136       if ((m->fromFile == -gs->wkrmoved-2) && (m->fromRank == 0)) {\r
2137         for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
2138           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
2139           if ((m1->fromFile == -gs->wkrmoved-2) && (m1->fromRank == 0))\r
2140             break;\r
2141         }\r
2142         if (i == game_globals.garray[g].numHalfMoves - 1)\r
2143           gs->wkrmoved = m->fromFile;\r
2144       }\r
2145     } else {\r
2146       if ((m->fromFile == -gs->bqrmoved-2) && (m->fromRank == gs->ranks-1)) {\r
2147         for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
2148           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
2149           if ((m1->fromFile == -gs->bkrmoved-2) && (m1->fromRank == gs->ranks-1))\r
2150             break;\r
2151         }\r
2152         if (i == game_globals.garray[g].numHalfMoves - 1)\r
2153           gs->bqrmoved = m->fromFile;\r
2154       }\r
2155       if ((m->fromFile == -gs->bkrmoved-2) && (m->fromRank == gs->ranks-1)) {\r
2156         for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
2157           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
2158           if ((m1->fromFile == -gs->wkrmoved-2) && (m1->fromRank == gs->ranks-1))\r
2159             break;\r
2160         }\r
2161         if (i == game_globals.garray[g].numHalfMoves - 1)\r
2162           gs->bkrmoved = m->fromFile;\r
2163       }\r
2164     }\r
2165   }\r
2166   if (piecetype(gs->board[m->fromFile][m->fromRank]) == KING) {
2167     gs->board[m->toFile][m->toRank] = m->pieceCaptured;
2168 #if 0
2169     /* [HGM] castlings are already intercepted due to new format; this code wrecks knightmate! */
2170     if (m->toFile - m->fromFile == 2) {
2171       gs->board[7][m->fromRank] = ROOK |
2172         colorval(gs->board[m->fromFile][m->fromRank]);
2173       gs->board[5][m->fromRank] = NOPIECE;
2174
2175       /********
2176          If takeback a castling, the appropriates ??moved variables
2177          must be cleared
2178       ********/
2179       if (m->color == WHITE) {
2180         gs->wkmoved = 0;
2181         gs->wkrmoved = 0;
2182       } else {
2183         gs->bkmoved = 0;
2184         gs->bkrmoved = 0;
2185       }
2186       goto cleanupMove;
2187     }
2188     if (m->fromFile - m->toFile == 2) {
2189       gs->board[0][m->fromRank] = ROOK |
2190         colorval(gs->board[m->fromFile][m->fromRank]);
2191       gs->board[3][m->fromRank] = NOPIECE;
2192
2193       /**********
2194          If takeback a castling, the appropriate ??moved variables
2195          must be cleared
2196       ***********/
2197       if (m->color == WHITE) {
2198         gs->wkmoved = 0;
2199         gs->wqrmoved = 0;
2200       } else {
2201         gs->bkmoved = 0;
2202         gs->bqrmoved = 0;
2203       }
2204       goto cleanupMove;
2205     }
2206 #endif
2207     /******************
2208        When takeback a _first_ move of king (not the castling),
2209        the ?kmoved variable must be cleared . To check, if the move is first,
2210        we should scan moveList.
2211     *******************/
2212
2213     if (m->color == WHITE) {\r
2214 \r
2215       if ((m->fromFile == -gs->wkmoved-2) && (m->fromRank == 0)) {\r
2216         for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
2217           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
2218           if ((m1->fromFile == gs->wkmoved-2) && (m1->fromRank == 0))\r
2219             break;\r
2220         }\r
2221         if (i == game_globals.garray[g].numHalfMoves - 1)\r
2222           gs->wkmoved = m->fromFile;\r
2223       }\r
2224     } else {\r
2225       if ((m->fromFile == -gs->bkmoved-2) && (m->fromRank == gs->ranks-1)) {\r
2226         for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
2227           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
2228           if ((m1->fromFile == -gs->bkmoved-2) && (m1->fromRank == gs->ranks-1))\r
2229             break;\r
2230         }\r
2231         if (i == game_globals.garray[g].numHalfMoves - 1)\r
2232           gs->bkmoved = m->fromFile;\r
2233       }\r
2234     }\r
2235   }\r
2236   if (m->enPassant) {           /* Do enPassant */
2237     gs->board[m->toFile][m->fromRank] = PAWN |
2238       (colorval(gs->board[m->fromFile][m->fromRank]) == WHITE ? BLACK : WHITE);
2239     gs->board[m->toFile][m->toRank] = NOPIECE;
2240     /* Should set the enpassant array, but I don't care right now */
2241     goto cleanupMove;
2242   }
2243   gs->board[m->toFile][m->toRank] = m->pieceCaptured;
2244 cleanupMove:
2245   if (game_globals.garray[g].status != GAME_EXAMINE) {
2246     game_update_time(g);
2247   }
2248   game_globals.garray[g].numHalfMoves--;
2249   if (game_globals.garray[g].status != GAME_EXAMINE) {
2250     if (game_globals.garray[g].wInitTime) {     /* Don't update times in untimed games */
2251       now = tenth_secs();
2252
2253       if (m->color == WHITE) {
2254         if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) {  /* white uses timeseal? */      
2255           game_globals.garray[g].wRealTime += (m->tookTime * 100); 
2256           game_globals.garray[g].wRealTime -= (game_globals.garray[g].wIncrement * 100);
2257           game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
2258           if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) { /* opp uses timeseal? */
2259             game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
2260           } else {    /* opp has no timeseal */
2261             game_globals.garray[g].bTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
2262           }
2263         } else {  /* white has no timeseal */
2264           game_globals.garray[g].wTime += m->tookTime;
2265           game_globals.garray[g].wTime -= game_globals.garray[g].wIncrement;
2266           if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) { /* opp uses timeseal? */
2267             game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
2268           } else {    /* opp has no timeseal */
2269             game_globals.garray[g].bTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
2270           }
2271         }
2272       } else {
2273         if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) {  /* black uses timeseal? */
2274           game_globals.garray[g].bRealTime += (m->tookTime * 100);
2275           game_globals.garray[g].bRealTime -= (game_globals.garray[g].wIncrement * 100);
2276           game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
2277           if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) { /* opp uses timeseal? */
2278             game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
2279           } else {    /* opp has no timeseal */
2280             game_globals.garray[g].wTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
2281           }
2282         } else {  /* black has no timeseal */
2283           game_globals.garray[g].bTime += m->tookTime;
2284           if (!game_globals.garray[g].bIncrement)
2285             game_globals.garray[g].bTime -= game_globals.garray[g].wIncrement;
2286           else
2287             game_globals.garray[g].bTime -= game_globals.garray[g].bIncrement;
2288           if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) { /* opp uses timeseal? */
2289             game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
2290           } else {    /* opp has no timeseal */
2291             game_globals.garray[g].wTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
2292           }
2293         }
2294       }
2295
2296       if (game_globals.garray[g].numHalfMoves == 0)
2297         game_globals.garray[g].timeOfStart = now;
2298       game_globals.garray[g].lastMoveTime = now;
2299       game_globals.garray[g].lastDecTime = now;
2300     }
2301   }
2302   if (gs->onMove == BLACK)
2303     gs->onMove = WHITE;
2304   else {
2305     gs->onMove = BLACK;
2306     gs->moveNum--;
2307   }
2308
2309   /******* Here begins the patch : ********************************
2310      Takeback of last move is done already, it's time to update enpassant
2311      array.  (patch from Soso, added by Sparky 3/17/95)
2312   ********/
2313
2314   if (game_globals.garray[g].numHalfMoves > 0) {\r
2315     m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[game_globals.garray[g].numHalfMoves - 1] : \r
2316                             &game_globals.garray[g].examMoveList[game_globals.garray[g].numHalfMoves - 1];\r
2317     if (piecetype(gs->board[m1->toFile][m1->toRank]) == PAWN) {\r
2318       if ((m1->toRank - m1->fromRank) == 2) {\r
2319         if ((m1->toFile < gs->files-1) && gs->board[m1->toFile + 1][m1->toRank] == B_PAWN) {\r
2320           gs->ep_possible[1][m1->toFile + 1] = -1;\r
2321         }\r
2322         if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][m1->toRank] == B_PAWN) {\r
2323           gs->ep_possible[1][m1->toFile - 1] = 1;\r
2324         }\r
2325       }\r
2326       if ((m1->toRank - m1->fromRank) == -2) {\r
2327         if ((m1->toFile < gs->files-1) && gs->board[m1->toFile + 1][m1->toRank] == W_PAWN) {\r
2328           gs->ep_possible[0][m1->toFile + 1] = -1;\r
2329         }\r
2330         if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][m1->toRank] == W_PAWN) {\r
2331           gs->ep_possible[0][m1->toFile - 1] = 1;\r
2332         }\r
2333       }\r
2334     }\r
2335   }\r
2336   /************** and here's the end **************/
2337   return MOVE_OK;
2338 }
2339
2340
2341
2342