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