953298c68a66748e98f7974aef7547e06479f9a5
[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) return 0; // [HGM] XQ 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) { /* Capture ? */
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) {\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))\r
632         add_pos(onf - 1, onr + 1, posf, posr, numpos);
633       if(gs->palace && onr >= gs->ranks/2 && (gs->board[onf-1][onr] || iscolor(gs->board[onf-1][onr], BLACK)))
634         add_pos(onf - 1, onr, posf, posr, numpos); // XQ promoted pawn
635     }\r
636     if (onf < gs->files-1) {
637       if (gs->board[onf + 1][onr + 1] != NOPIECE &&\r
638           iscolor(gs->board[onf + 1][onr + 1], BLACK))\r
639         add_pos(onf + 1, onr + 1, posf, posr, numpos);
640       if(gs->palace && onr >= gs->ranks/2 && (gs->board[onf+1][onr] || iscolor(gs->board[onf+1][onr], BLACK)))
641         add_pos(onf + 1, onr, posf, posr, numpos); // XQ promoted pawn
642     }\r
643     if (gs->ep_possible[0][onf] == -1)\r
644       add_pos(onf - 1, onr + 1, posf, posr, numpos);\r
645     if (gs->ep_possible[0][onf] == 1)\r
646       add_pos(onf + 1, onr + 1, posf, posr, numpos);
647   } else {\r
648     if (gs->board[onf][onr - 1] == NOPIECE || gs->palace) {\r
649       add_pos(onf, onr - 1, posf, posr, numpos);\r
650       if ((onr >= gs->ranks - gs->pawnDblStep - 1) && (gs->board[onf][onr - 2] == NOPIECE))\r
651         add_pos(onf, onr - 2, posf, posr, numpos);\r
652     }\r
653     if (onf > 0) {
654       if (gs->board[onf - 1][onr - 1] != NOPIECE &&\r
655           iscolor(gs->board[onf - 1][onr - 1], WHITE))\r
656         add_pos(onf - 1, onr - 1, posf, posr, numpos);
657       if(gs->palace && onr < gs->ranks/2 && !iscolor(gs->board[onf-1][onr], BLACK))
658         add_pos(onf - 1, onr, posf, posr, numpos); // XQ promoted pawn
659     }\r
660     if (onf < gs->files-1) {
661       if (gs->board[onf + 1][onr - 1] != NOPIECE &&\r
662           iscolor(gs->board[onf + 1][onr - 1], WHITE))\r
663         add_pos(onf + 1, onr - 1, posf, posr, numpos);
664       if(gs->palace && onr < gs->ranks/2 && !iscolor(gs->board[onf+1][onr], BLACK))
665         add_pos(onf + 1, onr, posf, posr, numpos); // XQ promoted pawn
666     }\r
667     if (gs->ep_possible[1][onf] == -1)\r
668       add_pos(onf - 1, onr - 1, posf, posr, numpos);\r
669     if (gs->ep_possible[1][onf] == 1)\r
670       add_pos(onf + 1, onr - 1, posf, posr, numpos);\r
671   }\r
672 }
673
674 static void possible_knight_moves(struct game_state_t * gs,
675                                     int onf, int onr,
676                                     int *posf, int *posr, int *numpos)
677 {
678   static int knightJumps[8][2] = {{-1, 2}, {1, 2}, {2, -1}, {2, 1},\r
679   {-1, -2}, {1, -2}, {-2, 1}, {-2, -1}};\r
680   int f, r;\r
681   int j;\r
682 \r
683   for (j = 0; j < 8; j++) {\r
684     f = knightJumps[j][0] + onf;\r
685     r = knightJumps[j][1] + onr;\r
686     if ((f < 0) || (f >= gs->files))\r
687       continue;\r
688     if ((r < 0) || (r >= gs->ranks))\r
689       continue;\r
690     if ((gs->board[f][r] == NOPIECE) ||\r
691         (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
692       add_pos(f, r, posf, posr, numpos);\r
693   }\r
694 }
695
696 static void possible_horse_moves(struct game_state_t * gs,
697                                     int onf, int onr,
698                                     int *posf, int *posr, int *numpos)
699 {
700   static int knightJumps[8][4] = {{-1, 2, 0, 1}, {1, 2, 0, 1}, {2, -1, 1, 0}, {2, 1, 1, 0},\r
701   {-1, -2, 0, -1}, {1, -2, 0, -1}, {-2, 1, -1, 0}, {-2, -1, -1, 0}};\r
702   int f, r;\r
703   int j;\r
704 \r
705   for (j = 0; j < 8; j++) {\r
706     f = knightJumps[j][0] + onf;\r
707     r = knightJumps[j][1] + onr;\r
708     if ((f < 0) || (f >= gs->files))\r
709       continue;\r
710     if ((r < 0) || (r >= gs->ranks))\r
711       continue;\r
712     if ((gs->board[knightJumps[j][2] + onf][knightJumps[j][3] + onr] == NOPIECE) && 
713         ((gs->board[f][r] == NOPIECE) || (iscolor(gs->board[f][r], CToggle(gs->onMove)))))\r
714       add_pos(f, r, posf, posr, numpos);\r
715   }\r
716 }
717
718 static void possible_bishop_moves(struct game_state_t * gs,
719                                     int onf, int onr,
720                                     int *posf, int *posr, int *numpos)
721 {
722   int f, r;\r
723 \r
724   /* Up Left */\r
725   f = onf;\r
726   r = onr;\r
727   for (;;) {\r
728     f--;\r
729     r++;\r
730     if ((f < 0) || (f >= gs->files))\r
731       break;\r
732     if ((r < 0) || (r >= gs->ranks))\r
733       break;\r
734     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
735       break;\r
736     add_pos(f, r, posf, posr, numpos);\r
737     if (gs->board[f][r] != NOPIECE)\r
738       break;\r
739   }\r
740   /* Up Right */\r
741   f = onf;\r
742   r = onr;\r
743   for (;;) {\r
744     f++;\r
745     r++;\r
746     if ((f < 0) || (f >= gs->files))\r
747       break;\r
748     if ((r < 0) || (r >= gs->ranks))\r
749       break;\r
750     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
751       break;\r
752     add_pos(f, r, posf, posr, numpos);\r
753     if (gs->board[f][r] != NOPIECE)\r
754       break;\r
755   }\r
756   /* Down Left */\r
757   f = onf;\r
758   r = onr;\r
759   for (;;) {\r
760     f--;\r
761     r--;\r
762     if ((f < 0) || (f >= gs->files))\r
763       break;\r
764     if ((r < 0) || (r >= gs->ranks))\r
765       break;\r
766     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
767       break;\r
768     add_pos(f, r, posf, posr, numpos);\r
769     if (gs->board[f][r] != NOPIECE)\r
770       break;\r
771   }\r
772   /* Down Right */\r
773   f = onf;\r
774   r = onr;\r
775   for (;;) {\r
776     f++;\r
777     r--;\r
778     if ((f < 0) || (f >= gs->files))\r
779       break;\r
780     if ((r < 0) || (r >= gs->ranks))\r
781       break;\r
782     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
783       break;\r
784     add_pos(f, r, posf, posr, numpos);\r
785     if (gs->board[f][r] != NOPIECE)\r
786       break;\r
787   }\r
788 }
789
790 static void possible_rook_moves(struct game_state_t * gs,
791                                   int onf, int onr,
792                                   int *posf, int *posr, int *numpos)
793 {
794   int f, r;\r
795 \r
796   /* Left */\r
797   f = onf;\r
798   r = onr;\r
799   for (;;) {\r
800     f--;\r
801     if ((f < 0) || (f >= gs->files))\r
802       break;\r
803     if ((r < 0) || (r >= gs->ranks))\r
804       break;\r
805     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
806       break;\r
807     add_pos(f, r, posf, posr, numpos);\r
808     if (gs->board[f][r] != NOPIECE)\r
809       break;\r
810   }\r
811   /* Right */\r
812   f = onf;\r
813   r = onr;\r
814   for (;;) {\r
815     f++;\r
816     if ((f < 0) || (f >= gs->files))\r
817       break;\r
818     if ((r < 0) || (r >= gs->ranks))\r
819       break;\r
820     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
821       break;\r
822     add_pos(f, r, posf, posr, numpos);\r
823     if (gs->board[f][r] != NOPIECE)\r
824       break;\r
825   }\r
826   /* Up */\r
827   f = onf;\r
828   r = onr;\r
829   for (;;) {\r
830     r++;\r
831     if ((f < 0) || (f >= gs->files))\r
832       break;\r
833     if ((r < 0) || (r >= gs->ranks))\r
834       break;\r
835     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
836       break;\r
837     add_pos(f, r, posf, posr, numpos);\r
838     if (gs->board[f][r] != NOPIECE)\r
839       break;\r
840   }\r
841   /* Down */\r
842   f = onf;\r
843   r = onr;\r
844   for (;;) {\r
845     r--;\r
846     if ((f < 0) || (f >= gs->files))\r
847       break;\r
848     if ((r < 0) || (r >= gs->ranks))\r
849       break;\r
850     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
851       break;\r
852     add_pos(f, r, posf, posr, numpos);\r
853     if (gs->board[f][r] != NOPIECE)\r
854       break;\r
855   }\r
856 }
857
858 static void possible_cannon_moves(struct game_state_t * gs,
859                                   int onf, int onr,
860                                   int *posf, int *posr, int *numpos)
861 {
862   int f, r, i;\r
863 \r
864   /* Left */\r
865   f = onf;\r
866   r = onr;\r
867   for (i=0;;) {\r
868     f--;\r
869     if ((f < 0) || (f >= gs->files))\r
870       break;\r
871     if ((r < 0) || (r >= gs->ranks))\r
872       break;\r
873     if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
874     if(i == 0)
875         add_pos(f, r, posf, posr, numpos); // no hop: non-capt
876     else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) 
877         add_pos(f, r, posf, posr, numpos); // hop: capt\r
878     if (gs->board[f][r] != NOPIECE)\r
879       break;\r
880   }\r
881   /* Right */\r
882   f = onf;\r
883   r = onr;\r
884   for (i=0;;) {\r
885     f++;\r
886     if ((f < 0) || (f >= gs->files))\r
887       break;\r
888     if ((r < 0) || (r >= gs->ranks))\r
889       break;\r
890     if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
891     if(i == 0)
892         add_pos(f, r, posf, posr, numpos); // no hop: non-capt
893     else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) 
894         add_pos(f, r, posf, posr, numpos); // hop: capt\r
895     if (gs->board[f][r] != NOPIECE)\r
896       break;\r
897   }\r
898   /* Up */\r
899   f = onf;\r
900   r = onr;\r
901   for (i=0;;) {\r
902     r++;\r
903     if ((f < 0) || (f >= gs->files))\r
904       break;\r
905     if ((r < 0) || (r >= gs->ranks))\r
906       break;\r
907     if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
908     if(i == 0)
909         add_pos(f, r, posf, posr, numpos); // no hop: non-capt
910     else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) 
911         add_pos(f, r, posf, posr, numpos); // hop: capt\r
912     if (gs->board[f][r] != NOPIECE)\r
913       break;\r
914   }\r
915   /* Down */\r
916   f = onf;\r
917   r = onr;\r
918   for (i=0;;) {\r
919     r--;\r
920     if ((f < 0) || (f >= gs->files))\r
921       break;\r
922     if ((r < 0) || (r >= gs->ranks))\r
923       break;\r
924     if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
925     if(i == 0)
926         add_pos(f, r, posf, posr, numpos); // no hop: non-capt
927     else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) 
928         add_pos(f, r, posf, posr, numpos); // hop: capt\r
929     if (gs->board[f][r] != NOPIECE)\r
930       break;\r
931   }\r
932 }
933
934 static void possible_lance_moves(struct game_state_t * gs,
935                                   int onf, int onr,
936                                   int *posf, int *posr, int *numpos)
937 {
938   int f, r;\r
939 \r
940   /* Up */\r
941   f = onf;\r
942   r = onr;\r
943   for (;gs->onMove == WHITE;) {\r
944     r++;\r
945     if ((f < 0) || (f >= gs->files))\r
946       break;\r
947     if ((r < 0) || (r >= gs->ranks))\r
948       break;\r
949     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
950       break;\r
951     add_pos(f, r, posf, posr, numpos);\r
952     if (gs->board[f][r] != NOPIECE)\r
953       break;\r
954   }\r
955   /* Down */\r
956   f = onf;\r
957   r = onr;\r
958   for (;gs->onMove == BLACK;) {\r
959     r--;\r
960     if ((f < 0) || (f >= gs->files))\r
961       break;\r
962     if ((r < 0) || (r >= gs->ranks))\r
963       break;\r
964     if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
965       break;\r
966     add_pos(f, r, posf, posr, numpos);\r
967     if (gs->board[f][r] != NOPIECE)\r
968       break;\r
969   }\r
970 }
971
972 static void possible_cardinal_moves(struct game_state_t * gs,\r
973                                    int onf, int onr,\r
974                                    int *posf, int *posr, int *numpos)\r
975 {\r
976   possible_knight_moves(gs, onf, onr, posf, posr, numpos);\r
977   possible_bishop_moves(gs, onf, onr, posf, posr, numpos);\r
978 }\r
979 \r
980 static void possible_marshall_moves(struct game_state_t * gs,\r
981                                    int onf, int onr,\r
982                                    int *posf, int *posr, int *numpos)\r
983 {\r
984   possible_rook_moves(gs, onf, onr, posf, posr, numpos);\r
985   possible_knight_moves(gs, onf, onr, posf, posr, numpos);\r
986 }\r
987 \r
988 static void possible_queen_moves(struct game_state_t * gs,
989                                    int onf, int onr,
990                                    int *posf, int *posr, int *numpos)
991 {
992   possible_rook_moves(gs, onf, onr, posf, posr, numpos);
993   possible_bishop_moves(gs, onf, onr, posf, posr, numpos);
994 }
995
996 static void possible_alfil_moves(struct game_state_t * gs,\r
997                                   int onf, int onr,\r
998                                   int *posf, int *posr, int *numpos)\r
999 {\r
1000   static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};\r
1001   int f, r;\r
1002   int j;\r
1003 \r
1004   for (j = 0; j < 4; j++) {\r
1005     f = 2*kingJumps[j][0] + onf;\r
1006     r = 2*kingJumps[j][1] + onr;\r
1007     if ((f < 0) || (f >= gs->files))\r
1008       continue;\r
1009     if ((r < 0) || (r >= gs->ranks))\r
1010       continue;\r
1011     if ((gs->board[f][r] == NOPIECE) ||\r
1012         (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
1013       add_pos(f, r, posf, posr, numpos);\r
1014   }\r
1015 }\r
1016 \r
1017 static void possible_ferz_moves(struct game_state_t * gs,\r
1018                                   int onf, int onr,\r
1019                                   int *posf, int *posr, int *numpos)\r
1020 {\r
1021   static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};\r
1022   int f, r;\r
1023   int j;\r
1024 \r
1025   for (j = 0; j < 4; j++) {\r
1026     f = kingJumps[j][0] + onf;\r
1027     r = kingJumps[j][1] + onr;\r
1028     if ((f < 0) || (f >= gs->files))\r
1029       continue;\r
1030     if ((r < 0) || (r >= gs->ranks))\r
1031       continue;
1032     if ((gs->board[f][r] == NOPIECE) ||\r
1033         (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
1034       add_pos(f, r, posf, posr, numpos);\r
1035   }\r
1036 }\r
1037 \r
1038 static void possible_mandarin_moves(struct game_state_t * gs,\r
1039                                   int onf, int onr,\r
1040                                   int *posf, int *posr, int *numpos)\r
1041 {\r
1042   static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};\r
1043   int f, r;\r
1044   int j;\r
1045 \r
1046   for (j = 0; j < 4; j++) {\r
1047     f = kingJumps[j][0] + onf;\r
1048     r = kingJumps[j][1] + onr;\r
1049     if ((f < 0) || (f >= gs->files))\r
1050       continue;\r
1051     if ((r < 0) || (r >= gs->ranks))\r
1052       continue;
1053     if(gs->palace && (r >= gs->palace && r < gs->ranks - gs->palace ||
1054        f < (gs->files - gs->palace)/2 || f >= (gs->files + gs->palace)/2))
1055       continue;\r
1056     if ((gs->board[f][r] == NOPIECE) ||\r
1057         (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
1058       add_pos(f, r, posf, posr, numpos);\r
1059   }\r
1060 }\r
1061 \r
1062 static void possible_wazir_moves(struct game_state_t * gs,\r
1063                                   int onf, int onr,\r
1064                                   int *posf, int *posr, int *numpos)\r
1065 {\r
1066   static int kingJumps[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};\r
1067   int f, r;\r
1068   int j;\r
1069 \r
1070   for (j = 0; j < 4; j++) {\r
1071     f = kingJumps[j][0] + onf;\r
1072     r = kingJumps[j][1] + onr;\r
1073     if ((f < 0) || (f >= gs->files))\r
1074       continue;\r
1075     if ((r < 0) || (r >= gs->ranks))\r
1076       continue;\r
1077     if(gs->palace && (r >= gs->palace && r < gs->ranks - gs->palace ||
1078        f < (gs->files - gs->palace)/2 || f >= (gs->files + gs->palace)/2))
1079       continue;\r
1080     if ((gs->board[f][r] == NOPIECE) ||\r
1081         (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
1082       add_pos(f, r, posf, posr, numpos);\r
1083   }\r
1084 }\r
1085 \r
1086 static void possible_dababba_moves(struct game_state_t * gs,\r
1087                                   int onf, int onr,\r
1088                                   int *posf, int *posr, int *numpos)\r
1089 {\r
1090   static int kingJumps[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};\r
1091   int f, r;\r
1092   int j;\r
1093 \r
1094   for (j = 0; j < 4; j++) {\r
1095     f = 2*kingJumps[j][0] + onf;\r
1096     r = 2*kingJumps[j][1] + onr;\r
1097     if ((f < 0) || (f >= gs->files))\r
1098       continue;\r
1099     if ((r < 0) || (r >= gs->ranks))\r
1100       continue;\r
1101     if ((gs->board[f][r] == NOPIECE) ||\r
1102         (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
1103       add_pos(f, r, posf, posr, numpos);\r
1104   }\r
1105 }\r
1106 \r
1107 static void possible_man_moves(struct game_state_t * gs,\r
1108                                    int onf, int onr,
1109                                    int *posf, int *posr, int *numpos)
1110 {
1111   possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1112   possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1113 }
1114
1115 static void possible_dragonking_moves(struct game_state_t * gs,\r
1116                                    int onf, int onr,
1117                                    int *posf, int *posr, int *numpos)
1118 {
1119   possible_rook_moves(gs, onf, onr, posf, posr, numpos);
1120   possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1121 }
1122
1123 static void possible_dragonhorse_moves(struct game_state_t * gs,\r
1124                                    int onf, int onr,
1125                                    int *posf, int *posr, int *numpos)
1126 {
1127   possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1128   possible_bishop_moves(gs, onf, onr, posf, posr, numpos);
1129 }
1130
1131 static void possible_centaur_moves(struct game_state_t * gs,\r
1132                                    int onf, int onr,
1133                                    int *posf, int *posr, int *numpos)
1134 {
1135   possible_man_moves(gs, onf, onr, posf, posr, numpos);
1136   possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1137 }
1138
1139 static void possible_woody_moves(struct game_state_t * gs,\r
1140                                    int onf, int onr,
1141                                    int *posf, int *posr, int *numpos)
1142 {
1143   possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1144   possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
1145 }
1146
1147 static void possible_squirrel_moves(struct game_state_t * gs,\r
1148                                    int onf, int onr,
1149                                    int *posf, int *posr, int *numpos)
1150 {
1151   possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
1152   possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
1153   possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1154 }
1155
1156 static void possible_mastodon_moves(struct game_state_t * gs,\r
1157                                    int onf, int onr,
1158                                    int *posf, int *posr, int *numpos)
1159 {
1160   possible_man_moves(gs, onf, onr, posf, posr, numpos);
1161   possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
1162   possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
1163 }
1164
1165 static void possible_amazon_moves(struct game_state_t * gs,\r
1166                                    int onf, int onr,
1167                                    int *posf, int *posr, int *numpos)
1168 {
1169   possible_queen_moves(gs, onf, onr, posf, posr, numpos);
1170   possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1171 }
1172
1173 static void possible_modernelephant_moves(struct game_state_t * gs,\r
1174                                    int onf, int onr,
1175                                    int *posf, int *posr, int *numpos)
1176 {
1177   possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1178   possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
1179 }
1180
1181 static void possible_priestess_moves(struct game_state_t * gs,\r
1182                                    int onf, int onr,
1183                                    int *posf, int *posr, int *numpos)
1184 {
1185   possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1186   possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
1187   possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1188 }
1189
1190 static void possible_minister_moves(struct game_state_t * gs,\r
1191                                    int onf, int onr,
1192                                    int *posf, int *posr, int *numpos)
1193 {
1194   possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1195   possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
1196   possible_knight_moves(gs, onf, onr, posf, posr, numpos);
1197 }
1198
1199 static void possible_gold_moves(struct game_state_t * gs,\r
1200                                    int onf, int onr,
1201                                    int *posf, int *posr, int *numpos)
1202 {
1203   possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1204   if(gs->onMove == WHITE) {
1205     if(onr < gs->ranks-1)
1206       if(onf > 0 && !iscolor(gs->board[onf-1][onr+1], WHITE))
1207         add_pos(onf-1, onr+1, posf, posr, numpos);\r
1208       if(onf < gs->files-1 && !iscolor(gs->board[onf+1][onr+1], WHITE))
1209         add_pos(onf+1, onr+1, posf, posr, numpos);\r
1210   } else {
1211     if(onr > 0)
1212       if(onf > 0 && !iscolor(gs->board[onf-1][onr-1], BLACK))
1213         add_pos(onf-1, onr-1, posf, posr, numpos);\r
1214       if(onf < gs->files-1 && !iscolor(gs->board[onf+1][onr-1], BLACK))
1215         add_pos(onf+1, onr-1, posf, posr, numpos);\r
1216   }
1217 }
1218
1219 static void possible_silver_moves(struct game_state_t * gs,\r
1220                                    int onf, int onr,
1221                                    int *posf, int *posr, int *numpos)
1222 {
1223   possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
1224   if(gs->onMove == WHITE) {
1225     if(onr < gs->ranks-1 && !iscolor(gs->board[onf][onr+1], WHITE))
1226       add_pos(onf, onr+1, posf, posr, numpos);\r
1227   } else {
1228     if(onr > 0 && !iscolor(gs->board[onf][onr-1], BLACK))
1229       add_pos(onf, onr-1, posf, posr, numpos);\r
1230   }
1231 }
1232
1233 static void possible_honorablehorse_moves(struct game_state_t * gs,\r
1234                                   int onf, int onr,\r
1235                                   int *posf, int *posr, int *numpos)\r
1236 {\r
1237   int f, r = onr + (gs->onMove == WHITE ? 2 : -2);\r
1238
1239   if(r < 0 || r >= gs->ranks) return;\r
1240   if(onf > 0) {
1241     if ((gs->board[onf-1][r] == NOPIECE) ||\r
1242         (iscolor(gs->board[onf-1][r], CToggle(gs->onMove))))\r
1243       add_pos(onf - 1, r, posf, posr, numpos);\r
1244   }\r
1245   if(onf < gs->files - 1) {
1246     if ((gs->board[onf+1][r] == NOPIECE) ||\r
1247         (iscolor(gs->board[onf+1][r], CToggle(gs->onMove))))\r
1248       add_pos(onf + 1, r, posf, posr, numpos);\r
1249   }\r
1250 }\r
1251 \r
1252 static void possible_king_moves(struct game_state_t * gs,
1253                                   int onf, int onr,
1254                                   int *posf, int *posr, int *numpos)
1255 {
1256   if(gs->royalKnight)\r
1257     possible_knight_moves(gs, onf, onr, posf, posr, numpos);\r
1258   else if(gs->palace)
1259     possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
1260   else\r
1261     possible_man_moves(gs, onf, onr, posf, posr, numpos);\r
1262 }
1263
1264 static void possible_elephant_moves(struct game_state_t * gs,
1265                                    int onf, int onr,
1266                                    int *posf, int *posr, int *numpos)
1267 {\r
1268   static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};\r
1269   int f, r;\r
1270   int j;\r
1271 \r
1272   for (j = 0; j < 4; j++) {\r
1273     f = 2*kingJumps[j][0] + onf;\r
1274     r = 2*kingJumps[j][1] + onr;\r
1275     if ((f < 0) || (f >= gs->files))\r
1276       continue;\r
1277     if ((r < 0) || (r >= gs->ranks))\r
1278       continue;\r
1279     if ((gs->board[(f+onf)/2][(r+onr)/2] == NOPIECE) && ((gs->board[f][r] == NOPIECE) ||\r
1280         (iscolor(gs->board[f][r], CToggle(gs->onMove)))))\r
1281       add_pos(f, r, posf, posr, numpos);\r
1282   }\r
1283 }\r
1284
1285 /* Doesn't check for check */
1286 int legal_move(struct game_state_t * gs,
1287                int fFile, int fRank,
1288                int tFile, int tRank)
1289 {
1290   int move_piece;
1291   int legal;
1292
1293   if (fFile == ALG_DROP) {
1294     move_piece = fRank;
1295     if(!gs->drops) return 0; // [HGM] variants: no drops in this variant
1296     if (move_piece == KING)
1297       return 0;
1298     if (gs->holding[gs->onMove==WHITE ? 0 : 1][move_piece-1] == 0)
1299       return 0;
1300     if (gs->board[tFile][tRank] != NOPIECE)
1301       return 0;
1302     if (move_piece == PAWN && (tRank == 0 || tRank == gs->ranks-1))
1303       return 0;
1304     return 1;
1305   } else if(fFile == ALG_CASTLE) {
1306         // [HGM] castle: this code can handle any type of free castling
1307         // it does not check if Rook and King from squares correspond to the rights, as the
1308         // user never enters such squares, but they are copied from the rights on entering o-o-o
1309         int backRank, kRook, qRook, fKing, leftEmpty, rightEmpty, leftCheck, rightCheck, f;
1310         if(!gs->castlingStyle) return 0;   // no castling in this variant
1311         if(gs->onMove == WHITE) {
1312                 if(gs->wkmoved < 0) return 0; // King moved
1313                 fKing = gs->wkmoved;
1314                 backRank = 0;
1315                 kRook = gs->wkrmoved;
1316                 qRook = gs->wqrmoved;
1317         } else {
1318                 if(gs->bkmoved < 0) return 0; // King moved
1319                 fKing = gs->bkmoved;
1320                 backRank = gs->ranks-1;
1321                 kRook = gs->bkrmoved;
1322                 qRook = gs->bqrmoved;
1323         }
1324         if((tRank > tFile ? qRook : kRook) < 0) return 0; // Rook moved
1325         // here we verified rights do exist, so from squares (fRank and fKing) must be valid
1326         if(gs->board[fRank][backRank] != (ROOK | gs->onMove) ) return 0; // only with own Rook
1327         if(gs->board[fKing][backRank] != (KING | gs->onMove) ) return 0; // only with own King
1328
1329         // by now we know that K and R are in correct position, and still have rights
1330         if(tRank > tFile) { // R ends right of K: q-side
1331                 leftEmpty  = fRank < tFile ? fRank+1 : tFile+1;
1332                 rightEmpty = tRank < fKing ? fKing-1 : tRank-1;
1333         } else { // k-side
1334                 leftEmpty  = tRank < fKing ? tRank+1 : fKing+1;
1335                 rightEmpty = fRank < tFile ? fRank-1 : tFile-1;
1336         }
1337         for(f=leftEmpty; f<=rightEmpty; f++) // check if other pieces block castling
1338                 if(f != fRank && f != fKing && gs->board[f][backRank] != NOPIECE) return 0;
1339
1340         leftCheck  = fKing < tFile ? fKing : tFile+1;
1341         rightCheck = fKing < tFile ? tFile-1 : fKing;
1342         for(f=leftCheck; f<=rightCheck; f++) // check if King passes attacked square or was in check
1343                 if(is_square_attacked(gs, f, backRank)) return 0;
1344
1345         return 1; // passed all tests
1346   } else {
1347     move_piece = piecetype(gs->board[fFile][fRank]);
1348   }
1349   if (gs->board[fFile][fRank] == NOPIECE)
1350     return 0;
1351   if (!iscolor(gs->board[fFile][fRank], gs->onMove))    /* Wrong color */
1352     return 0;
1353   if ((gs->board[tFile][tRank] != NOPIECE) &&
1354       iscolor(gs->board[tFile][tRank], gs->onMove))     /* Can't capture own */
1355     return 0;
1356   if ((fFile == tFile) && (fRank == tRank))     /* Same square */
1357     return 0;
1358   switch (move_piece) {
1359   case PAWN:
1360     legal = legal_pawn_move(gs, fFile, fRank, tFile, tRank);
1361     break;
1362   case KNIGHT:
1363     legal = legal_knight_move(gs, fFile, fRank, tFile, tRank);
1364     break;
1365   case BISHOP:
1366     legal = legal_bishop_move(gs, fFile, fRank, tFile, tRank);
1367     break;
1368   case ROOK:
1369     legal = legal_rook_move(gs, fFile, fRank, tFile, tRank);
1370     break;
1371   case CARDINAL:\r
1372   case PRINCESS:\r
1373     legal = legal_cardinal_move(gs, fFile, fRank, tFile, tRank);\r
1374     break;\r
1375   case MARSHALL:\r
1376   case EMPRESS:\r
1377     legal = legal_marshall_move(gs, fFile, fRank, tFile, tRank);\r
1378     break;\r
1379   case MAN:\r
1380   case MAN2:\r
1381     legal = legal_man_move(gs, fFile, fRank, tFile, tRank);\r
1382     break;\r
1383   case QUEEN:
1384     legal = legal_queen_move(gs, fFile, fRank, tFile, tRank);
1385     break;
1386   case ELEPHANT:
1387     legal = legal_elephant_move(gs, fFile, fRank, tFile, tRank);
1388     break;
1389   case AMAZON:
1390     legal = legal_amazon_move(gs, fFile, fRank, tFile, tRank);
1391     break;
1392   case WOODY:
1393     legal = legal_woody_move(gs, fFile, fRank, tFile, tRank);
1394     break;
1395   case SQUIRREL:
1396     legal = legal_squirrel_move(gs, fFile, fRank, tFile, tRank);
1397     break;
1398   case MASTODON:
1399     legal = legal_mastodon_move(gs, fFile, fRank, tFile, tRank);
1400     break;
1401   case CENTAUR:
1402     legal = legal_centaur_move(gs, fFile, fRank, tFile, tRank);
1403     break;
1404   case HORSE:
1405     legal = legal_horse_move(gs, fFile, fRank, tFile, tRank);
1406     break;
1407   case FERZ:
1408   case FERZ2:
1409     legal = legal_ferz_move(gs, fFile, fRank, tFile, tRank);
1410     break;
1411   case MANDARIN:
1412     legal = legal_mandarin_move(gs, fFile, fRank, tFile, tRank);
1413     break;
1414   case WAZIR:
1415     legal = legal_wazir_move(gs, fFile, fRank, tFile, tRank);
1416     break;
1417   case ALFIL:
1418   case ALFIL2:
1419     legal = legal_alfil_move(gs, fFile, fRank, tFile, tRank);
1420     break;
1421   case MODERNELEPHANT:
1422     legal = legal_modernelephant_move(gs, fFile, fRank, tFile, tRank);
1423     break;
1424   case PRIESTESS:
1425     legal = legal_priestess_move(gs, fFile, fRank, tFile, tRank);
1426     break;
1427   case MINISTER:
1428     legal = legal_minister_move(gs, fFile, fRank, tFile, tRank);
1429     break;
1430   case SILVER:
1431     legal = legal_silver_move(gs, fFile, fRank, tFile, tRank);
1432     break;
1433   case GOLD:
1434     legal = legal_gold_move(gs, fFile, fRank, tFile, tRank);
1435     break;
1436   case LANCE:
1437     legal = legal_lance_move(gs, fFile, fRank, tFile, tRank);
1438     break;
1439   case CANNON:
1440     legal = legal_cannon_move(gs, fFile, fRank, tFile, tRank);
1441     break;
1442   case DRAGONHORSE:
1443     legal = legal_dragonhorse_move(gs, fFile, fRank, tFile, tRank);
1444     break;
1445   case DRAGONKING:
1446     legal = legal_dragonking_move(gs, fFile, fRank, tFile, tRank);
1447     break;
1448   case HONORABLEHORSE:
1449     legal = legal_honorablehorse_move(gs, fFile, fRank, tFile, tRank);
1450     break;
1451   case KING:
1452     legal = legal_king_move(gs, fFile, fRank, tFile, tRank);
1453     break;
1454   default:
1455     return 0;
1456     break;
1457   }
1458   return legal;
1459 }
1460
1461 #define DROP_CHAR '@'
1462
1463 /* This fills in the rest of the mt structure once it is determined that
1464  * the move is legal. Returns MOVE_ILLEGAL if move leaves you in check */
1465 static int move_calculate(struct game_state_t * gs, struct move_t * mt, int promote)
1466 {
1467   struct game_state_t fakeMove;\r
1468 \r
1469   mt->pieceCaptured = gs->board[mt->toFile][mt->toRank];\r
1470   mt->enPassant = 0;            /* Don't know yet, let execute move take care\r
1471                                    of it */\r
1472   if (mt->fromFile == ALG_DROP) {\r
1473     mt->piecePromotionTo = NOPIECE;\r
1474     sprintf(mt->moveString, "%s/%c%c-%c%d",\r
1475             wpstring[mt->fromRank],\r
1476                 DROP_CHAR, DROP_CHAR,\r
1477             mt->toFile + 'a', mt->toRank + 1 - (gs->ranks>9));\r
1478   } else if(mt->fromFile == ALG_CASTLE) { 
1479         // [HGM] castle: generalized castling, fr and tr give from and to file of Rook.
1480             sprintf(mt->moveString, mt->toRank > mt->toFile ? "o-o-o" : "o-o");
1481   } else {
1482   if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) && 
1483         !gs->palace && // [HGM] XQ: no promotions in xiangqi\r
1484       ((mt->toRank == 0) || (mt->toRank == gs->ranks-1))) {
1485     if(!gs->pawnDblStep && promote == PRINCESS) promote = MAN2;
1486     if(!gs->pawnDblStep && promote != FERZ2 && promote != MAN2) promote = FERZ; // [HGM] kludge to recognize shatranj
1487     mt->piecePromotionTo = promote |\r
1488       (colorval(gs->board[mt->fromFile][mt->fromRank]));\r
1489   } else {\r
1490     mt->piecePromotionTo = NOPIECE;\r
1491   }\r
1492   if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) &&\r
1493    ((mt->fromRank - mt->toRank == 2) || (mt->toRank - mt->fromRank == 2))) {\r
1494     mt->doublePawn = mt->fromFile;\r
1495   } else {\r
1496     mt->doublePawn = -1;\r
1497   }
1498 #if 0
1499   if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) &&\r
1500       (mt->fromFile == gs->files/2) && (mt->toFile == 2) &&
1501        mt->fromRank == mt->toRank) {\r
1502     sprintf(mt->moveString, "o-o-o");\r
1503   } else if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) &&\r
1504              (mt->fromFile == gs->files/2) && (mt->toFile == gs->files-2) &&
1505                 mt->fromRank == mt->toRank) {\r
1506     sprintf(mt->moveString, "o-o");
1507   } else {
1508 #else
1509   {
1510 #endif\r
1511     sprintf(mt->moveString, "%s/%c%d-%c%d",\r
1512             wpstring[piecetype(gs->board[mt->fromFile][mt->fromRank])],\r
1513             mt->fromFile + 'a', mt->fromRank + 1 - (gs->ranks>9),\r
1514             mt->toFile + 'a', mt->toRank + 1 - (gs->ranks>9));\r
1515   }\r
1516   }\r
1517   /* Replace this with an algabraic de-parser */\r
1518 \r
1519   sprintf(mt->algString, alg_unparse(gs, mt));\r
1520   fakeMove = *gs;\r
1521   /* Calculates enPassant also */\r
1522   execute_move(&fakeMove, mt, 0);\r
1523 \r
1524   /* Does making this move leave ME in check? */\r
1525   if (in_check(&fakeMove))\r
1526     return MOVE_ILLEGAL;\r
1527   /* IanO: bughouse variants: drop cannot be check/checkmate */\r
1528 \r
1529   return MOVE_OK;\r
1530 }
1531
1532 int legal_andcheck_move(struct game_state_t * gs,
1533                         int fFile, int fRank,
1534                         int tFile, int tRank)
1535 {
1536   struct move_t mt;
1537   if (!legal_move(gs, fFile, fRank, tFile, tRank))
1538     return 0;
1539   mt.color = gs->onMove;
1540   mt.fromFile = fFile;
1541   mt.fromRank = fRank;
1542   mt.toFile = tFile;
1543   mt.toRank = tRank;
1544   /* This should take into account a pawn promoting to another piece */
1545   if (move_calculate(gs, &mt, QUEEN) == MOVE_OK)
1546     return 1;
1547   else
1548     return 0;
1549 }
1550
1551 /* in_check: checks if the side that is NOT about to move is in check 
1552  */
1553 int in_check(struct game_state_t * gs)
1554 {
1555   int f, r;\r
1556   int kf = -1, kr = -1;\r
1557 \r
1558   /* Find the king */\r
1559   if (gs->onMove == WHITE) {\r
1560     for (f = 0; f < gs->files && kf < 0; f++)\r
1561       for (r = 0; r < gs->ranks && kf < 0; r++)\r
1562         if (gs->board[f][r] == B_KING) {\r
1563           kf = f;\r
1564           kr = r;\r
1565         }\r
1566   } else {\r
1567     for (f = 0; f < gs->files && kf < 0; f++)\r
1568       for (r = 0; r < gs->ranks && kf < 0; r++)\r
1569         if (gs->board[f][r] == W_KING) {\r
1570           kf = f;\r
1571           kr = r;\r
1572         }\r
1573   }\r
1574   if (kf < 0) {\r
1575     d_printf( "CHESSD: Error game with no king!\n");\r
1576     return 0;\r
1577   }\r
1578   for (InitPieceLoop(gs->board, &f, &r, gs->onMove);\r
1579        NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {\r
1580     if (legal_move(gs, f, r, kf, kr)) { /* In Check? */\r
1581       return 1;\r
1582     }\r
1583   }\r
1584   return 0;\r
1585 }
1586
1587 int has_legal_move(struct game_state_t * gs)
1588 {
1589   int i;
1590   int f, r;
1591   int kf = 0, kr = 0;
1592   int possiblef[500], possibler[500];
1593   int numpossible = 0;
1594
1595   for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
1596        NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {
1597     switch (piecetype(gs->board[f][r])) {
1598     case PAWN:
1599       possible_pawn_moves(gs, f, r, possiblef, possibler, &numpossible);
1600       break;
1601     case KNIGHT:
1602       possible_knight_moves(gs, f, r, possiblef, possibler, &numpossible);
1603       break;
1604     case BISHOP:
1605       possible_bishop_moves(gs, f, r, possiblef, possibler, &numpossible);
1606       break;
1607     case ROOK:
1608       possible_rook_moves(gs, f, r, possiblef, possibler, &numpossible);
1609       break;
1610     case CARDINAL:\r
1611     case PRINCESS:\r
1612       possible_cardinal_moves(gs, f, r, possiblef, possibler, &numpossible);\r
1613       break;\r
1614     case MARSHALL:\r
1615     case EMPRESS:\r
1616       possible_marshall_moves(gs, f, r, possiblef, possibler, &numpossible);\r
1617       break;\r
1618     case MAN:\r
1619     case MAN2:\r
1620       possible_man_moves(gs, f, r, possiblef, possibler, &numpossible);\r
1621       break;\r
1622     case QUEEN:
1623       possible_queen_moves(gs, f, r, possiblef, possibler, &numpossible);
1624       break;
1625     case ELEPHANT:
1626       possible_elephant_moves(gs, f, r, possiblef, possibler, &numpossible);
1627       break;
1628     case AMAZON:
1629       possible_amazon_moves(gs, f, r, possiblef, possibler, &numpossible);
1630       break;
1631     case WOODY:
1632       possible_woody_moves(gs, f, r, possiblef, possibler, &numpossible);
1633       break;
1634     case SQUIRREL:
1635       possible_squirrel_moves(gs, f, r, possiblef, possibler, &numpossible);
1636       break;
1637     case MASTODON:
1638       possible_mastodon_moves(gs, f, r, possiblef, possibler, &numpossible);
1639       break;
1640     case CENTAUR:
1641       possible_centaur_moves(gs, f, r, possiblef, possibler, &numpossible);
1642       break;
1643     case HORSE:
1644       possible_horse_moves(gs, f, r, possiblef, possibler, &numpossible);
1645       break;
1646     case FERZ:
1647     case FERZ2:
1648       possible_ferz_moves(gs, f, r, possiblef, possibler, &numpossible);
1649       break;
1650     case MANDARIN:
1651       possible_mandarin_moves(gs, f, r, possiblef, possibler, &numpossible);
1652       break;
1653     case WAZIR:
1654       possible_wazir_moves(gs, f, r, possiblef, possibler, &numpossible);
1655       break;
1656     case ALFIL:
1657     case ALFIL2:
1658       possible_alfil_moves(gs, f, r, possiblef, possibler, &numpossible);
1659       break;
1660     case MODERNELEPHANT:
1661       possible_modernelephant_moves(gs, f, r, possiblef, possibler, &numpossible);
1662       break;
1663     case PRIESTESS:
1664       possible_priestess_moves(gs, f, r, possiblef, possibler, &numpossible);
1665       break;
1666     case MINISTER:
1667       possible_minister_moves(gs, f, r, possiblef, possibler, &numpossible);
1668       break;
1669     case SILVER:
1670       possible_silver_moves(gs, f, r, possiblef, possibler, &numpossible);
1671       break;
1672     case GOLD:
1673       possible_gold_moves(gs, f, r, possiblef, possibler, &numpossible);
1674       break;
1675     case CANNON:
1676       possible_cannon_moves(gs, f, r, possiblef, possibler, &numpossible);
1677       break;
1678     case LANCE:
1679       possible_lance_moves(gs, f, r, possiblef, possibler, &numpossible);
1680       break;
1681     case DRAGONHORSE:
1682       possible_dragonhorse_moves(gs, f, r, possiblef, possibler, &numpossible);
1683       break;
1684     case DRAGONKING:
1685       possible_dragonking_moves(gs, f, r, possiblef, possibler, &numpossible);
1686       break;
1687     case HONORABLEHORSE:
1688       possible_honorablehorse_moves(gs, f, r, possiblef, possibler, &numpossible);
1689       break;
1690     case KING:
1691       kf = f;
1692       kr = r;
1693       possible_king_moves(gs, f, r, possiblef, possibler, &numpossible);
1694       break;
1695     }
1696     if (numpossible >= 500) {
1697       d_printf( "CHESSD: Possible move overrun\n");
1698     }
1699     for (i = 0; i < numpossible; i++)
1700       if (legal_andcheck_move(gs, f, r, possiblef[i], possibler[i])) {
1701         return 1;
1702       }
1703   }
1704
1705   /* IanO:  if we got here, then kf and kr must be set */\r
1706   if (gs->gameNum >=0 && game_globals.garray[gs->gameNum].link >= 0
1707         || gs->holdings) { // [HGM] zh: also in 2-player games with drops\r
1708     /* bughouse: potential drops as check interpositions */\r
1709     gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]++;\r
1710     for (f=kf-1; f<=kf+1; f++) for (r=kr-1; r<=kr+1; r++) {\r
1711       if (f>=0 && f<gs->files && r>=0 && r<gs->ranks && gs->board[f][r] == NOPIECE) {\r
1712         /* try a drop next to the king */\r
1713         if (legal_andcheck_move(gs, ALG_DROP, QUEEN, f, r)) {\r
1714           gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--;
1715           // OK, so we have an interposing drop. But do we have something to drop?
1716           if(game_globals.garray[gs->gameNum].link < 0) {
1717                 // we have no partner, so we must have something to drop now
1718                 for(i=QUEEN; i>=PAWN; i--)
1719                         if(gs->holding[gs->onMove==WHITE ? 0 : 1][i-1]) break;
1720                 if(i > PAWN) return 1; // we have a non-Pawn to drop
1721                 // We have a Pawn, but check if it legal to drop it
1722                 if(i == PAWN && r != 0 && r != gs->ranks-1) return 1; // [HGM] todo: for Shogi there are extra conditions on Pawn drops!
1723           }\r
1724           return 1;\r
1725         }\r
1726       }\r
1727     }\r
1728     gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--;\r
1729   }\r
1730
1731   return 0;
1732 }
1733
1734 /* This will end up being a very complicated function */
1735 int parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt, int promote)
1736 {
1737   int type = is_move(mstr);\r
1738   int result;\r
1739 \r
1740   mt->piecePromotionTo = NOPIECE;\r
1741   mt->color = gs->onMove;\r
1742   switch (type) {\r
1743   case MS_NOTMOVE:\r
1744     return MOVE_ILLEGAL;\r
1745     break;\r
1746   case MS_COMP:\r
1747     mt->fromFile = mstr[0] - 'a';\r
1748     mt->fromRank = mstr[1] - '1' + (gs->ranks>9);\r
1749     mt->toFile = mstr[2] - 'a';\r
1750     mt->toRank = mstr[3] - '1' + (gs->ranks>9);\r
1751     break;\r
1752   case MS_COMPDASH:\r
1753     mt->fromFile = mstr[0] - 'a';\r
1754     mt->fromRank = mstr[1] - '1' + (gs->ranks>9);\r
1755     mt->toFile = mstr[3] - 'a';\r
1756     mt->toRank = mstr[4] - '1' + (gs->ranks>9);\r
1757     break;\r
1758   case MS_KCASTLE:\r
1759 #if 0
1760     mt->fromFile = gs->files/2;\r
1761     mt->toFile = gs->files-2;\r
1762     if (gs->onMove == WHITE) {\r
1763       mt->fromRank = 0;\r
1764       mt->toRank = 0;\r
1765     } else {\r
1766       mt->fromRank = gs->ranks-1;\r
1767       mt->toRank = gs->ranks-1;\r
1768     }\r
1769     break;
1770 #endif
1771     // [HGM] castle: for now always assume Fischer-type castling (of which normal castling is a special case).
1772     mt->fromFile = ALG_CASTLE;\r
1773     mt->toFile = gs->files-2;\r
1774     mt->fromRank = gs->onMove == WHITE ? gs->wkrmoved : gs->bkrmoved;\r
1775     mt->toRank = mt->toFile-1; // R next to K\r
1776     break;    \r
1777   case MS_QCASTLE:
1778 #if 0\r
1779     mt->fromFile = gs->files/2;\r
1780     mt->toFile = 2;\r
1781     if (gs->onMove == WHITE) {\r
1782       mt->fromRank = 0;\r
1783       mt->toRank = 0;\r
1784     } else {\r
1785       mt->fromRank = gs->ranks-1;\r
1786       mt->toRank = gs->ranks-1;\r
1787     }\r
1788     break;
1789 #endif\r
1790     mt->fromFile = ALG_CASTLE;\r
1791     mt->toFile = 2;\r
1792     mt->fromRank = gs->onMove == WHITE ? gs->wqrmoved : gs->bqrmoved;\r
1793     mt->toRank = mt->toFile+1;
1794     break;\r
1795   case MS_ALG:\r
1796     /* Fills in the mt structure */\r
1797     if ((result = alg_parse_move(mstr, gs, mt)) != MOVE_OK)\r
1798       return result;\r
1799     break;\r
1800   default:\r
1801     return MOVE_ILLEGAL;\r
1802     break;\r
1803   }
1804   if((mt->fromRank >= gs->ranks || mt->fromRank < 0 || mt->fromFile >= gs->files) &&
1805      mt->fromFile != ALG_DROP && mt->fromFile != ALG_CASTLE\r
1806      || mt->toRank < 0 || mt->toRank >= gs->ranks || mt->toFile >= gs->files)\r
1807     return MOVE_ILLEGAL; // [HGM] make sure move stays on board
1808 \r
1809   if (!(result = legal_move(gs, mt->fromFile, mt->fromRank, mt->toFile, mt->toRank)))
1810     return MOVE_ILLEGAL;\r
1811
1812   if(result == 2) { // [HGM] castle: orthodox castling was given as King move; convert it to new format
1813         if(mt->fromFile - mt->toFile > 1) { // Q-side
1814                 mt->fromRank = 0; 
1815                 mt->toRank   = mt->toFile+1;
1816         } else if(mt->toFile - mt->fromFile > 1) { // K-side
1817                 mt->fromRank = gs->files-1;
1818                 mt->toRank   = mt->toFile-1;
1819         }
1820         mt->fromFile = ALG_CASTLE;
1821     }\r
1822 \r
1823   if (mt->piecePromotionTo != NOPIECE) {\r
1824           promote = piecetype(mt->piecePromotionTo);\r
1825   }\r
1826 \r
1827   return move_calculate(gs, mt, promote);\r
1828 }
1829
1830 /* Returns MOVE_OK, MOVE_NOMATERIAL, MOVE_CHECKMATE, or MOVE_STALEMATE */
1831 /* check_game_status prevents recursion */
1832 int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_status)
1833 {
1834   int movedPiece;
1835   int tookPiece;
1836   int i, j, foobar, wCnt, bCnt, king, rook;
1837
1838   if (mt->fromFile == ALG_DROP) {
1839     movedPiece = mt->fromRank;
1840     tookPiece = NOPIECE;
1841     gs->holding[gs->onMove==WHITE ? 0 : 1][movedPiece-1]--;
1842     gs->board[mt->toFile][mt->toRank] = movedPiece | gs->onMove;
1843     if (gs->gameNum >= 0)
1844       gs->lastIrreversable = game_globals.garray[gs->gameNum].numHalfMoves;
1845   } else if(mt->fromFile == ALG_CASTLE) {
1846     int backRank, fKing;
1847     // [HGM] castle: perform castling
1848     if(gs->onMove == WHITE) {
1849         backRank = 0;
1850         fKing = gs->wkmoved;
1851         gs->wkmoved = -gs->wkmoved-2;
1852     } else {
1853         backRank = gs->ranks-1;
1854         fKing = gs->bkmoved;
1855         gs->bkmoved = -gs->bkmoved-2;
1856     }
1857     // move Rook & King, in a way that is resistant to ending where they started (for FRC!)
1858     rook = gs->board[mt->fromRank][backRank];    // first remember\r
1859     king = gs->board[fKing][backRank];\r
1860     gs->board[mt->fromRank][backRank] = NOPIECE; // then erase\r    gs->board[fKing][backRank] = NOPIECE;\r    gs->board[mt->toRank][backRank] = rook;      // then put back
1861     gs->board[mt->toFile][backRank] = king;
1862   } else {
1863   movedPiece = gs->board[mt->fromFile][mt->fromRank];
1864   tookPiece = gs->board[mt->toFile][mt->toRank];
1865   if (mt->piecePromotionTo == NOPIECE) {
1866     gs->board[mt->toFile][mt->toRank] = gs->board[mt->fromFile][mt->fromRank];
1867   } else {
1868     gs->board[mt->toFile][mt->toRank] = mt->piecePromotionTo | gs->onMove;
1869     if(gs->promoType == 2) gs->holding[gs->onMove][mt->piecePromotionTo-1]--;
1870   }
1871   gs->board[mt->fromFile][mt->fromRank] = NOPIECE;
1872   /* Check if irreversable */
1873   if ((piecetype(movedPiece) == PAWN) && (mt->fromRank != mt->toRank) // [HGM] XQ: sideway Pawn move reversible!
1874                         || (tookPiece != NOPIECE)) {
1875     if (gs->gameNum >= 0)
1876       gs->lastIrreversable = game_globals.garray[gs->gameNum].numHalfMoves;
1877   }
1878   /* Check if this move is en-passant */
1879   if ((piecetype(movedPiece) == PAWN) && (mt->fromFile != mt->toFile) &&
1880       (tookPiece == NOPIECE) && !gs->palace) { // [HGM] XQ: no e.p. in sideway xiangqi moves
1881     if (gs->onMove == WHITE) {
1882       mt->pieceCaptured = B_PAWN;
1883     } else {
1884       mt->pieceCaptured = W_PAWN;
1885     }
1886     if (mt->fromFile > mt->toFile) {
1887       mt->enPassant = -1;
1888     } else {
1889       mt->enPassant = 1;
1890     }
1891     gs->board[mt->toFile][mt->fromRank] = NOPIECE;
1892   }
1893   /* Check en-passant flags for next moves */\r
1894   for (i = 0; i < gs->files; i++) {\r
1895     gs->ep_possible[0][i] = 0;\r
1896     gs->ep_possible[1][i] = 0;\r
1897   }\r
1898 /* Added by Sparky 3/16/95
1899
1900    From soso@Viktoria.drp.fmph.uniba.sk Thu Mar 16 13:08:51 1995
1901    Subject: Re: To DAV: enpassant prob. again
1902    To: chess@caissa.onenet.net (ICS)
1903    Date: Thu, 16 Mar 1995 20:06:20 +0100 (MET)
1904
1905    Yeah !
1906    There was bug in other part of code:
1907
1908    movecheck.c , line about 800:
1909
1910      if (gs->onMove == WHITE) {
1911         if ((mt->toFile+1 < 7 ) ....  should be : (mt->toFile < 7 ) }
1912 */
1913
1914   if ((piecetype(movedPiece) == PAWN) &&\r
1915    ((mt->fromRank == mt->toRank + 2) || (mt->fromRank + 2 == mt->toRank))) {\r
1916     /* Should turn on enpassent flag if possible */\r
1917     if (gs->onMove == WHITE) {\r
1918       if ((mt->toFile < gs->files-1) && gs->board[mt->toFile + 1][mt->toRank] == B_PAWN) {\r
1919         gs->ep_possible[1][mt->toFile + 1] = -1;\r
1920       }\r
1921       if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][mt->toRank] == B_PAWN) {\r
1922         gs->ep_possible[1][mt->toFile - 1] = 1;\r
1923       }\r
1924     } else {\r
1925       if ((mt->toFile < gs->files-1) && gs->board[mt->toFile + 1][mt->toRank] == W_PAWN) {\r
1926         gs->ep_possible[0][mt->toFile + 1] = -1;\r
1927       }\r
1928       if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][mt->toRank] == W_PAWN) {\r
1929         gs->ep_possible[0][mt->toFile - 1] = 1;\r
1930       }\r
1931     }\r
1932   }\r
1933   if ((piecetype(movedPiece) == ROOK) && (mt->fromRank == 0) && (gs->onMove == WHITE)) {\r
1934     if (mt->fromFile == gs->wqrmoved) // [HGM] castle: flip w.r.t. -1 to remember original\r
1935       gs->wqrmoved = -gs->wqrmoved-2;\r
1936     if (mt->fromFile == gs->wkrmoved)\r
1937       gs->wkrmoved = -gs->wkrmoved-2;\r
1938   }\r
1939   if ((piecetype(movedPiece) == ROOK) && (mt->fromRank == gs->ranks-1) && (gs->onMove == BLACK)) {\r
1940     if (mt->fromFile == gs->bqrmoved)\r
1941       gs->bqrmoved = -gs->bqrmoved-2;\r
1942     if (mt->fromFile == gs->bkrmoved)\r
1943       gs->bkrmoved = -gs->bkrmoved-2;\r
1944   }\r
1945   if (piecetype(movedPiece) == KING) {\r
1946     if ((gs->onMove == WHITE) && (mt->fromFile == gs->wkmoved))\r
1947       gs->wkmoved = -gs->wkmoved-2;\r
1948     if ((gs->onMove == BLACK) && (mt->fromFile == gs->bkmoved))\r
1949       gs->bkmoved = -gs->bkmoved-2;\r
1950   }
1951 #if 0\r
1952   if ((piecetype(movedPiece) == KING) &&\r
1953       ((mt->fromFile == gs->files/2) && (mt->toFile == gs->files-2)) &&
1954         mt->fromRank == mt->toRank) {   /* Check for KS castling */\r
1955     gs->board[gs->files-3][mt->toRank] = gs->board[gs->files-1][mt->toRank];\r
1956     gs->board[gs->files-1][mt->toRank] = NOPIECE;\r
1957   }\r
1958   if ((piecetype(movedPiece) == KING) &&\r
1959       ((mt->fromFile == gs->files/2) && (mt->toFile == 2)) &&
1960         mt->fromRank == mt->toRank) {   /* Check for QS castling */\r
1961     gs->board[3][mt->toRank] = gs->board[0][mt->toRank];\r
1962     gs->board[0][mt->toRank] = NOPIECE;\r
1963   }
1964 #endif\r
1965   }\r
1966   if (gs->onMove == BLACK)\r
1967     gs->moveNum++;\r
1968 \r
1969   if (check_game_status) {\r
1970     /* Does this move result in check? */\r
1971     if (in_check(gs)) {\r
1972       /* Check for checkmate */\r
1973       gs->onMove = CToggle(gs->onMove);\r
1974       if (!has_legal_move(gs))\r
1975         return MOVE_CHECKMATE;\r
1976     } else {\r
1977       /* Check for stalemate */\r
1978       gs->onMove = CToggle(gs->onMove);\r
1979       if (!has_legal_move(gs))\r
1980         return gs->stalemate ? MOVE_STALEMATE : MOVE_CHECKMATE; // [HGM] in XQ and shatranj stalemate loses\r
1981     }\r
1982 /* loon: check for insufficient mating material, first try */\r
1983       foobar = wCnt = bCnt = 0;\r
1984       for (i=0; i<gs->files; i++) {\r
1985         for (j=0; j<gs->ranks; j++) {
1986           int p = gs->board[i][j];\r
1987           switch(piecetype(p)) {\r
1988             case KNIGHT:\r
1989             case BISHOP:\r
1990               foobar++;\r
1991               break;\r
1992             case KING:\r
1993             case NOPIECE:\r
1994               break;\r
1995             default:\r
1996               foobar = 2;\r
1997               break;\r
1998           }
1999           if(p != NOPIECE && iscolor(p, WHITE)) wCnt++;
2000           if(iscolor(p, BLACK)) bCnt++;\r
2001         }\r
2002       }
2003       if(gs->bareKingLoses) { // [HGM] with bare-King-loses rule only KK is insuff. material
2004         if(gs->onMove == BLACK && wCnt == 1 && bCnt > 1) return MOVE_BARE;
2005         if(gs->onMove == WHITE && bCnt == 1 && wCnt > 1) return MOVE_BARE;
2006         if(bCnt == 1 && wCnt == 1) return MOVE_NOMATERIAL;
2007       } else if (foobar < 2)\r
2008         return MOVE_NOMATERIAL;\r
2009   } else {\r
2010     gs->onMove = CToggle(gs->onMove);\r
2011   }\r
2012   return MOVE_OK;\r
2013 }
2014
2015 int backup_move(int g, int mode)
2016 {
2017   struct game_state_t *gs;
2018   struct move_t *m, *m1;
2019   int now, i;
2020
2021   if (game_globals.garray[g].link >= 0) /*IanO: not implemented for bughouse yet */
2022     return MOVE_ILLEGAL;
2023   if (game_globals.garray[g].numHalfMoves < 1)
2024     return MOVE_ILLEGAL;
2025   gs = &game_globals.garray[g].game_state;
2026   m = (mode==REL_GAME) ? &game_globals.garray[g].moveList[game_globals.garray[g].numHalfMoves - 1] : 
2027                          &game_globals.garray[g].examMoveList[game_globals.garray[g].numHalfMoves - 1];
2028   if (m->toFile < 0) {
2029     return MOVE_ILLEGAL;
2030   }
2031   if(m->fromFile == ALG_CASTLE) {
2032     // [HGM] castling in new format. Derive K and R moves
2033     int rank, kingFromFile;
2034     if(m->color == WHITE) {
2035       rank = 0;
2036       kingFromFile = -gs->wkmoved-2;
2037       if(kingFromFile<0) kingFromFile = -kingFromFile-2; // safety catch; should never happen?
2038       gs->wkmoved = kingFromFile;
2039       if(m->toRank > m->toFile) gs->wqrmoved = m->fromRank;
2040       else gs->wkrmoved = m->fromRank;
2041     } else {
2042       rank = gs->ranks-1;
2043       kingFromFile = -gs->bkmoved-2;
2044       if(kingFromFile<0) kingFromFile = -kingFromFile-2; // safety catch; should never happen?
2045       gs->bkmoved = kingFromFile;
2046       if(m->toRank > m->toFile) gs->bqrmoved = m->fromRank;
2047       else gs->bkrmoved = m->fromRank;
2048     }
2049     // remove first, as one might come back to a square the other left
2050     gs->board[m->toFile  ][rank] = NOPIECE; // King toSqr
2051     gs->board[m->toRank  ][rank] = NOPIECE; // Rook toSqr
2052     gs->board[m->fromRank][rank] = ROOK | m->color; // Rook fromSqr
2053     gs->board[kingFromFile][rank] = KING | m->color; // King fromSquare
2054     goto cleanupMove;
2055   }
2056   gs->board[m->fromFile][m->fromRank] = gs->board[m->toFile][m->toRank];
2057   if (m->piecePromotionTo != NOPIECE) {
2058     gs->board[m->fromFile][m->fromRank] = PAWN |
2059       colorval(gs->board[m->fromFile][m->fromRank]);
2060   }
2061   /******************
2062      When takeback a _first_ move of rook, the ??rmoved variable
2063      must be cleared . To check, if the move is first, we should
2064      scan moveList.
2065   *******************/
2066   if (piecetype(gs->board[m->fromFile][m->fromRank]) == ROOK) {
2067     if (m->color == WHITE) {
2068       if ((m->fromFile == -gs->wqrmoved-2) && (m->fromRank == 0)) {
2069         for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
2070           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
2071           if ((m1->fromFile == -gs->wqrmoved-2) && (m1->fromRank == 0))
2072             break;
2073         }
2074         if (i == game_globals.garray[g].numHalfMoves - 1)
2075           gs->wqrmoved = m->fromFile;
2076       }
2077       if ((m->fromFile == -gs->wkrmoved-2) && (m->fromRank == 0)) {\r
2078         for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
2079           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
2080           if ((m1->fromFile == -gs->wkrmoved-2) && (m1->fromRank == 0))\r
2081             break;\r
2082         }\r
2083         if (i == game_globals.garray[g].numHalfMoves - 1)\r
2084           gs->wkrmoved = m->fromFile;\r
2085       }\r
2086     } else {\r
2087       if ((m->fromFile == -gs->bqrmoved-2) && (m->fromRank == gs->ranks-1)) {\r
2088         for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
2089           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
2090           if ((m1->fromFile == -gs->bkrmoved-2) && (m1->fromRank == gs->ranks-1))\r
2091             break;\r
2092         }\r
2093         if (i == game_globals.garray[g].numHalfMoves - 1)\r
2094           gs->bqrmoved = m->fromFile;\r
2095       }\r
2096       if ((m->fromFile == -gs->bkrmoved-2) && (m->fromRank == gs->ranks-1)) {\r
2097         for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
2098           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
2099           if ((m1->fromFile == -gs->wkrmoved-2) && (m1->fromRank == gs->ranks-1))\r
2100             break;\r
2101         }\r
2102         if (i == game_globals.garray[g].numHalfMoves - 1)\r
2103           gs->bkrmoved = m->fromFile;\r
2104       }\r
2105     }\r
2106   }\r
2107   if (piecetype(gs->board[m->fromFile][m->fromRank]) == KING) {
2108     gs->board[m->toFile][m->toRank] = m->pieceCaptured;
2109 #if 0
2110     /* [HGM] castlings are already intercepted due to new format; this code wrecks knightmate! */
2111     if (m->toFile - m->fromFile == 2) {
2112       gs->board[7][m->fromRank] = ROOK |
2113         colorval(gs->board[m->fromFile][m->fromRank]);
2114       gs->board[5][m->fromRank] = NOPIECE;
2115
2116       /********
2117          If takeback a castling, the appropriates ??moved variables
2118          must be cleared
2119       ********/
2120       if (m->color == WHITE) {
2121         gs->wkmoved = 0;
2122         gs->wkrmoved = 0;
2123       } else {
2124         gs->bkmoved = 0;
2125         gs->bkrmoved = 0;
2126       }
2127       goto cleanupMove;
2128     }
2129     if (m->fromFile - m->toFile == 2) {
2130       gs->board[0][m->fromRank] = ROOK |
2131         colorval(gs->board[m->fromFile][m->fromRank]);
2132       gs->board[3][m->fromRank] = NOPIECE;
2133
2134       /**********
2135          If takeback a castling, the appropriate ??moved variables
2136          must be cleared
2137       ***********/
2138       if (m->color == WHITE) {
2139         gs->wkmoved = 0;
2140         gs->wqrmoved = 0;
2141       } else {
2142         gs->bkmoved = 0;
2143         gs->bqrmoved = 0;
2144       }
2145       goto cleanupMove;
2146     }
2147 #endif
2148     /******************
2149        When takeback a _first_ move of king (not the castling),
2150        the ?kmoved variable must be cleared . To check, if the move is first,
2151        we should scan moveList.
2152     *******************/
2153
2154     if (m->color == WHITE) {\r
2155 \r
2156       if ((m->fromFile == -gs->wkmoved-2) && (m->fromRank == 0)) {\r
2157         for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
2158           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
2159           if ((m1->fromFile == gs->wkmoved-2) && (m1->fromRank == 0))\r
2160             break;\r
2161         }\r
2162         if (i == game_globals.garray[g].numHalfMoves - 1)\r
2163           gs->wkmoved = m->fromFile;\r
2164       }\r
2165     } else {\r
2166       if ((m->fromFile == -gs->bkmoved-2) && (m->fromRank == gs->ranks-1)) {\r
2167         for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
2168           m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
2169           if ((m1->fromFile == -gs->bkmoved-2) && (m1->fromRank == gs->ranks-1))\r
2170             break;\r
2171         }\r
2172         if (i == game_globals.garray[g].numHalfMoves - 1)\r
2173           gs->bkmoved = m->fromFile;\r
2174       }\r
2175     }\r
2176   }\r
2177   if (m->enPassant) {           /* Do enPassant */
2178     gs->board[m->toFile][m->fromRank] = PAWN |
2179       (colorval(gs->board[m->fromFile][m->fromRank]) == WHITE ? BLACK : WHITE);
2180     gs->board[m->toFile][m->toRank] = NOPIECE;
2181     /* Should set the enpassant array, but I don't care right now */
2182     goto cleanupMove;
2183   }
2184   gs->board[m->toFile][m->toRank] = m->pieceCaptured;
2185 cleanupMove:
2186   if (game_globals.garray[g].status != GAME_EXAMINE) {
2187     game_update_time(g);
2188   }
2189   game_globals.garray[g].numHalfMoves--;
2190   if (game_globals.garray[g].status != GAME_EXAMINE) {
2191     if (game_globals.garray[g].wInitTime) {     /* Don't update times in untimed games */
2192       now = tenth_secs();
2193
2194       if (m->color == WHITE) {
2195         if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) {  /* white uses timeseal? */      
2196           game_globals.garray[g].wRealTime += (m->tookTime * 100); 
2197           game_globals.garray[g].wRealTime -= (game_globals.garray[g].wIncrement * 100);
2198           game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
2199           if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) { /* opp uses timeseal? */
2200             game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
2201           } else {    /* opp has no timeseal */
2202             game_globals.garray[g].bTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
2203           }
2204         } else {  /* white has no timeseal */
2205           game_globals.garray[g].wTime += m->tookTime;
2206           game_globals.garray[g].wTime -= game_globals.garray[g].wIncrement;
2207           if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) { /* opp uses timeseal? */
2208             game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
2209           } else {    /* opp has no timeseal */
2210             game_globals.garray[g].bTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
2211           }
2212         }
2213       } else {
2214         if (net_globals.con[player_globals.parray[game_globals.garray[g].black].socket]->timeseal) {  /* black uses timeseal? */
2215           game_globals.garray[g].bRealTime += (m->tookTime * 100);
2216           game_globals.garray[g].bRealTime -= (game_globals.garray[g].wIncrement * 100);
2217           game_globals.garray[g].bTime = game_globals.garray[g].bRealTime / 100;
2218           if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) { /* opp uses timeseal? */
2219             game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
2220           } else {    /* opp has no timeseal */
2221             game_globals.garray[g].wTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
2222           }
2223         } else {  /* black has no timeseal */
2224           game_globals.garray[g].bTime += m->tookTime;
2225           if (!game_globals.garray[g].bIncrement)
2226             game_globals.garray[g].bTime -= game_globals.garray[g].wIncrement;
2227           else
2228             game_globals.garray[g].bTime -= game_globals.garray[g].bIncrement;
2229           if (net_globals.con[player_globals.parray[game_globals.garray[g].white].socket]->timeseal) { /* opp uses timeseal? */
2230             game_globals.garray[g].wTime = game_globals.garray[g].wRealTime / 100;
2231           } else {    /* opp has no timeseal */
2232             game_globals.garray[g].wTime += (game_globals.garray[g].lastDecTime - game_globals.garray[g].lastMoveTime);
2233           }
2234         }
2235       }
2236
2237       if (game_globals.garray[g].numHalfMoves == 0)
2238         game_globals.garray[g].timeOfStart = now;
2239       game_globals.garray[g].lastMoveTime = now;
2240       game_globals.garray[g].lastDecTime = now;
2241     }
2242   }
2243   if (gs->onMove == BLACK)
2244     gs->onMove = WHITE;
2245   else {
2246     gs->onMove = BLACK;
2247     gs->moveNum--;
2248   }
2249
2250   /******* Here begins the patch : ********************************
2251      Takeback of last move is done already, it's time to update enpassant
2252      array.  (patch from Soso, added by Sparky 3/17/95)
2253   ********/
2254
2255   if (game_globals.garray[g].numHalfMoves > 0) {\r
2256     m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[game_globals.garray[g].numHalfMoves - 1] : \r
2257                             &game_globals.garray[g].examMoveList[game_globals.garray[g].numHalfMoves - 1];\r
2258     if (piecetype(gs->board[m1->toFile][m1->toRank]) == PAWN) {\r
2259       if ((m1->toRank - m1->fromRank) == 2) {\r
2260         if ((m1->toFile < gs->files-1) && gs->board[m1->toFile + 1][m1->toRank] == B_PAWN) {\r
2261           gs->ep_possible[1][m1->toFile + 1] = -1;\r
2262         }\r
2263         if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][m1->toRank] == B_PAWN) {\r
2264           gs->ep_possible[1][m1->toFile - 1] = 1;\r
2265         }\r
2266       }\r
2267       if ((m1->toRank - m1->fromRank) == -2) {\r
2268         if ((m1->toFile < gs->files-1) && gs->board[m1->toFile + 1][m1->toRank] == W_PAWN) {\r
2269           gs->ep_possible[0][m1->toFile + 1] = -1;\r
2270         }\r
2271         if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][m1->toRank] == W_PAWN) {\r
2272           gs->ep_possible[0][m1->toFile - 1] = 1;\r
2273         }\r
2274       }\r
2275     }\r
2276   }\r
2277   /************** and here's the end **************/
2278   return MOVE_OK;
2279 }
2280
2281
2282
2283