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