converted two files from dos to unix format
[xboard.git] / moves.c
1 /*
2  * moves.c - Move generation and checking
3  * $Id: moves.c,v 2.1 2003/10/27 19:21:00 mann Exp $
4  *
5  * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
6  * Enhancements Copyright 1992-95 Free Software Foundation, Inc.
7  *
8  * The following terms apply to Digital Equipment Corporation's copyright
9  * interest in XBoard:
10  * ------------------------------------------------------------------------
11  * All Rights Reserved
12  *
13  * Permission to use, copy, modify, and distribute this software and its
14  * documentation for any purpose and without fee is hereby granted,
15  * provided that the above copyright notice appear in all copies and that
16  * both that copyright notice and this permission notice appear in
17  * supporting documentation, and that the name of Digital not be
18  * used in advertising or publicity pertaining to distribution of the
19  * software without specific, written prior permission.
20  *
21  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
22  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
23  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
24  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
25  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
26  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
27  * SOFTWARE.
28  * ------------------------------------------------------------------------
29  *
30  * The following terms apply to the enhanced version of XBoard distributed
31  * by the Free Software Foundation:
32  * ------------------------------------------------------------------------
33  * This program is free software; you can redistribute it and/or modify
34  * it under the terms of the GNU General Public License as published by
35  * the Free Software Foundation; either version 2 of the License, or
36  * (at your option) any later version.
37  *
38  * This program is distributed in the hope that it will be useful,
39  * but WITHOUT ANY WARRANTY; without even the implied warranty of
40  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
41  * GNU General Public License for more details.
42  *
43  * You should have received a copy of the GNU General Public License
44  * along with this program; if not, write to the Free Software
45  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
46  * ------------------------------------------------------------------------
47  */
48
49 #include "config.h"
50
51 #include <stdio.h>
52 #if HAVE_STRING_H
53 # include <string.h>
54 #else /* not HAVE_STRING_H */
55 # include <strings.h>
56 #endif /* not HAVE_STRING_H */
57 #include "common.h"
58 #include "backend.h" 
59 #include "moves.h"
60 #include "parser.h"
61
62 int WhitePiece P((ChessSquare));
63 int BlackPiece P((ChessSquare));
64 int SameColor P((ChessSquare, ChessSquare));
65
66 extern char initialRights[BOARD_SIZE]; /* [HGM] all rights enabled, set in InitPosition */
67
68
69 int WhitePiece(piece)
70      ChessSquare piece;
71 {
72     return (int) piece >= (int) WhitePawn && (int) piece < (int) BlackPawn;
73 }
74
75 int BlackPiece(piece)
76      ChessSquare piece;
77 {
78     return (int) piece >= (int) BlackPawn && (int) piece < (int) EmptySquare;
79 }
80
81 int SameColor(piece1, piece2)
82      ChessSquare piece1, piece2;
83 {
84     return ((int) piece1 >= (int) WhitePawn &&   /* [HGM] can be > King ! */
85             (int) piece1 <  (int) BlackPawn &&
86             (int) piece2 >= (int) WhitePawn &&
87             (int) piece2 <  (int) BlackPawn)
88       ||   ((int) piece1 >= (int) BlackPawn &&
89             (int) piece1 <  (int) EmptySquare &&
90             (int) piece2 >= (int) BlackPawn &&
91             (int) piece2 <  (int) EmptySquare);
92 }
93
94 ChessSquare PromoPiece(moveType)
95      ChessMove moveType;
96 {
97     switch (moveType) {
98       default:
99         return EmptySquare;
100       case WhitePromotionQueen:
101         return WhiteQueen;
102       case BlackPromotionQueen:
103         return BlackQueen;
104       case WhitePromotionRook:
105         return WhiteRook;
106       case BlackPromotionRook:
107         return BlackRook;
108       case WhitePromotionBishop:
109         return WhiteBishop;
110       case BlackPromotionBishop:
111         return BlackBishop;
112       case WhitePromotionKnight:
113         return WhiteKnight;
114       case BlackPromotionKnight:
115         return BlackKnight;
116       case WhitePromotionKing:
117         return WhiteKing;
118       case BlackPromotionKing:
119         return BlackKing;
120       case WhitePromotionChancellor:
121         return WhiteMarshall;
122       case BlackPromotionChancellor:
123         return BlackMarshall;
124       case WhitePromotionArchbishop:
125         return WhiteAngel;
126       case BlackPromotionArchbishop:
127         return BlackAngel;
128       case WhitePromotionCentaur:
129         return WhiteSilver;
130       case BlackPromotionCentaur:
131         return BlackSilver;
132     }
133 }
134
135 char pieceToChar[] = {
136                         'P', 'N', 'B', 'R', 'Q', 'F', 'E', 'A', 'C', 'W', 'M', 
137                         'O', 'H', 'I', 'J', 'G', 'D', 'V', 'L', 's', 'U', 'K',
138                         'p', 'n', 'b', 'r', 'q', 'f', 'e', 'a', 'c', 'w', 'm', 
139                         'o', 'h', 'i', 'j', 'g', 'd', 'v', 'l', 's', 'u', 'k', 
140                         'x' };
141
142 char PieceToChar(p)
143      ChessSquare p;
144 {
145     if((int)p < 0 || (int)p >= (int)EmptySquare) return('x'); /* [HGM] for safety */
146     return pieceToChar[(int) p];
147 }
148
149 int PieceToNumber(p)  /* [HGM] holdings: count piece type, ignoring non-participating piece types */
150      ChessSquare p;
151 {
152     int i=0;
153     ChessSquare start = (int)p >= (int)BlackPawn ? BlackPawn : WhitePawn;
154
155     while(start++ != p) if(pieceToChar[(int)start-1] != '.') i++;
156     return i;
157 }
158
159 ChessSquare CharToPiece(c)
160      int c;
161 {
162      int i;
163      for(i=0; i< (int) EmptySquare; i++)
164           if(pieceToChar[i] == c) return (ChessSquare) i;
165      return EmptySquare;
166 }
167
168 ChessMove PromoCharToMoveType(whiteOnMove, promoChar)
169      int whiteOnMove;
170      int promoChar;
171 {       /* [HGM] made dependent on CharToPiece to alow alternate piece letters */
172         ChessSquare piece = CharToPiece(whiteOnMove ? ToUpper(promoChar) : ToLower(promoChar) );
173
174
175         if(promoChar == NULLCHAR) return NormalMove;
176
177         switch(piece) {
178                 case WhiteQueen:
179                         return WhitePromotionQueen;
180                 case WhiteRook:
181                         return WhitePromotionRook;
182                 case WhiteBishop:
183                         return WhitePromotionBishop;
184                 case WhiteKnight:
185                         return WhitePromotionKnight;
186                 case WhiteKing:
187                         return WhitePromotionKing;
188                 case WhiteAngel:
189                         return WhitePromotionArchbishop;
190                 case WhiteMarshall:
191                         return WhitePromotionChancellor;
192                 case WhiteSilver:
193                         return WhitePromotionCentaur;
194                 case BlackQueen:
195                         return BlackPromotionQueen;
196                 case BlackRook:
197                         return BlackPromotionRook;
198                 case BlackBishop:
199                         return BlackPromotionBishop;
200                 case BlackKnight:
201                         return BlackPromotionKnight;
202                 case BlackKing:
203                         return BlackPromotionKing;
204                 case BlackAngel:
205                         return BlackPromotionArchbishop;
206                 case BlackMarshall:
207                         return BlackPromotionChancellor;
208                 case BlackSilver:
209                         return BlackPromotionCentaur;
210                 default:
211                         // not all promotion implemented yet! Take Queen for those we don't know.
212                         return (whiteOnMove ? WhitePromotionQueen : BlackPromotionQueen);
213         }
214 }
215
216 void CopyBoard(to, from)
217      Board to, from;
218 {
219     int i, j;
220     
221     for (i = 0; i < BOARD_HEIGHT; i++)
222       for (j = 0; j < BOARD_WIDTH; j++)
223         to[i][j] = from[i][j];
224 }
225
226 int CompareBoards(board1, board2)
227      Board board1, board2;
228 {
229     int i, j;
230     
231     for (i = 0; i < BOARD_HEIGHT; i++)
232       for (j = 0; j < BOARD_WIDTH; j++) {
233           if (board1[i][j] != board2[i][j])
234             return FALSE;
235     }
236     return TRUE;
237 }
238
239
240 /* Call callback once for each pseudo-legal move in the given
241    position, except castling moves. A move is pseudo-legal if it is
242    legal, or if it would be legal except that it leaves the king in
243    check.  In the arguments, epfile is EP_NONE if the previous move
244    was not a double pawn push, or the file 0..7 if it was, or
245    EP_UNKNOWN if we don't know and want to allow all e.p. captures.
246    Promotion moves generated are to Queen only.
247 */
248 void GenPseudoLegal(board, flags, epfile, callback, closure)
249      Board board;
250      int flags;
251      int epfile;
252      MoveCallback callback;
253      VOIDSTAR closure;
254 {
255     int rf, ff;
256     int i, j, d, s, fs, rs, rt, ft, m;
257
258     for (rf = 0; rf < BOARD_HEIGHT; rf++) 
259       for (ff = BOARD_LEFT; ff < BOARD_RGHT; ff++) {
260           ChessSquare piece;
261
262           if (flags & F_WHITE_ON_MOVE) {
263               if (!WhitePiece(board[rf][ff])) continue;
264           } else {
265               if (!BlackPiece(board[rf][ff])) continue;
266           }
267           m = 0; piece = board[rf][ff];
268           if(PieceToChar(piece) == '~') 
269                  piece = (ChessSquare) ( DEMOTED piece );
270           if(gameInfo.variant == VariantShogi)
271                  piece = (ChessSquare) ( SHOGI piece );
272
273           switch (piece) {
274             /* case EmptySquare: [HGM] this is nonsense, and conflicts with Shogi cases */
275             default:
276               /* can't happen ([HGM] except for faries...) */
277               break;
278
279              case WhitePawn:
280               if(gameInfo.variant == VariantXiangqi) {
281                   /* [HGM] capture and move straight ahead in Xiangqi */
282                   if (rf < BOARD_HEIGHT-1 &&
283                            !SameColor(board[rf][ff], board[rf + 1][ff]) ) {
284                            callback(board, flags, NormalMove,
285                                     rf, ff, rf + 1, ff, closure);
286                   }
287                   /* and move sideways when across the river */
288                   for (s = -1; s <= 1; s += 2) {
289                       if (rf >= BOARD_HEIGHT>>1 &&
290                           ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
291                           !WhitePiece(board[rf][ff+s]) ) {
292                            callback(board, flags, NormalMove,
293                                     rf, ff, rf, ff+s, closure);
294                       }
295                   }
296                   break;
297               }
298               if (rf < BOARD_HEIGHT-1 && board[rf + 1][ff] == EmptySquare) {
299                   callback(board, flags,
300                            rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,
301                            rf, ff, rf + 1, ff, closure);
302               }
303               if (rf == 1 && board[2][ff] == EmptySquare &&
304                   gameInfo.variant != VariantShatranj && /* [HGM] */
305                   gameInfo.variant != VariantCourier  && /* [HGM] */
306                   board[3][ff] == EmptySquare ) {
307                       callback(board, flags, NormalMove,
308                                rf, ff, 3, ff, closure);
309               }
310               for (s = -1; s <= 1; s += 2) {
311                   if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
312                       ((flags & F_KRIEGSPIEL_CAPTURE) ||
313                        BlackPiece(board[rf + 1][ff + s]))) {
314                       callback(board, flags, 
315                                rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,
316                                rf, ff, rf + 1, ff + s, closure);
317                   }
318                   if (rf == BOARD_HEIGHT-4) {
319                       if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
320                           (epfile == ff + s || epfile == EP_UNKNOWN) &&
321                           board[BOARD_HEIGHT-4][ff + s] == BlackPawn &&
322                           board[BOARD_HEIGHT-3][ff + s] == EmptySquare) {
323                           callback(board, flags, WhiteCapturesEnPassant,
324                                    rf, ff, 5, ff + s, closure);
325                       }
326                   }
327               }             
328               break;
329
330             case BlackPawn:
331               if(gameInfo.variant == VariantXiangqi) {
332                   /* [HGM] capture straight ahead in Xiangqi */
333                   if (rf > 0 && !SameColor(board[rf][ff], board[rf - 1][ff]) ) {
334                            callback(board, flags, NormalMove,
335                                     rf, ff, rf - 1, ff, closure);
336                   }
337                   /* and move sideways when across the river */
338                   for (s = -1; s <= 1; s += 2) {
339                       if (rf < BOARD_HEIGHT>>1 &&
340                           ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
341                           !BlackPiece(board[rf][ff+s]) ) {
342                            callback(board, flags, NormalMove,
343                                     rf, ff, rf, ff+s, closure);
344                       }
345                   }
346                   break;
347               }
348               if (rf > 0 && board[rf - 1][ff] == EmptySquare) {
349                   callback(board, flags, 
350                            rf == 1 ? BlackPromotionQueen : NormalMove,
351                            rf, ff, rf - 1, ff, closure);
352               }
353               if (rf == BOARD_HEIGHT-2 && board[BOARD_HEIGHT-3][ff] == EmptySquare &&
354                   gameInfo.variant != VariantShatranj && /* [HGM] */
355                   gameInfo.variant != VariantCourier  && /* [HGM] */
356                   board[BOARD_HEIGHT-4][ff] == EmptySquare) {
357                   callback(board, flags, NormalMove,
358                            rf, ff, BOARD_HEIGHT-4, ff, closure);
359               }
360               for (s = -1; s <= 1; s += 2) {
361                   if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
362                       ((flags & F_KRIEGSPIEL_CAPTURE) ||
363                        WhitePiece(board[rf - 1][ff + s]))) {
364                       callback(board, flags, 
365                                rf == 1 ? BlackPromotionQueen : NormalMove,
366                                rf, ff, rf - 1, ff + s, closure);
367                   }
368                   if (rf == 3) {
369                       if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
370                           (epfile == ff + s || epfile == EP_UNKNOWN) &&
371                           board[3][ff + s] == WhitePawn &&
372                           board[2][ff + s] == EmptySquare) {
373                           callback(board, flags, BlackCapturesEnPassant,
374                                    rf, ff, 2, ff + s, closure);
375                       }
376                   }
377               }             
378               break;
379
380             case WhiteUnicorn:
381             case BlackUnicorn:
382             case WhiteKnight:
383             case BlackKnight:
384             mounted:
385               for (i = -1; i <= 1; i += 2)
386                 for (j = -1; j <= 1; j += 2)
387                   for (s = 1; s <= 2; s++) {
388                       rt = rf + i*s;
389                       ft = ff + j*(3-s);
390                       if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
391                           && ( gameInfo.variant != VariantXiangqi || board[rf+i*(s-1)][ff+j*(2-s)] == EmptySquare)
392                           && !SameColor(board[rf][ff], board[rt][ft]))
393                       callback(board, flags, NormalMove,
394                                rf, ff, rt, ft, closure);
395                   }
396               break;
397
398             case SHOGI WhiteKnight:
399               for (s = -1; s <= 1; s += 2) {
400                   if (rf < BOARD_HEIGHT-2 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
401                       !SameColor(board[rf][ff], board[rf + 2][ff + s])) {
402                       callback(board, flags, NormalMove,
403                                rf, ff, rf + 2, ff + s, closure);
404                   }
405               }
406               break;
407
408             case SHOGI BlackKnight:
409               for (s = -1; s <= 1; s += 2) {
410                   if (rf > 1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
411                       !SameColor(board[rf][ff], board[rf - 2][ff + s])) {
412                       callback(board, flags, NormalMove,
413                                rf, ff, rf - 2, ff + s, closure);
414                   }
415               }             
416               break;
417
418             case WhiteCannon:
419             case BlackCannon:
420               for (d = 0; d <= 1; d++)
421                 for (s = -1; s <= 1; s += 2) {
422                   m = 0;
423                   for (i = 1;; i++) {
424                       rt = rf + (i * s) * d;
425                       ft = ff + (i * s) * (1 - d);
426                       if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
427                       if (m == 0 && board[rt][ft] == EmptySquare)
428                                  callback(board, flags, NormalMove,
429                                           rf, ff, rt, ft, closure);
430                       if (m == 1 && board[rt][ft] != EmptySquare &&
431                           !SameColor(board[rf][ff], board[rt][ft]) )
432                                  callback(board, flags, NormalMove,
433                                           rf, ff, rt, ft, closure);
434                       if (board[rt][ft] != EmptySquare && m++) break;
435                   }
436                 }
437               break;
438
439             /* Gold General (and all its promoted versions) . First do the */
440             /* diagonal forward steps, then proceed as normal Wazir        */
441             case SHOGI WhiteWazir:
442             case SHOGI (PROMOTED WhitePawn):
443             case SHOGI (PROMOTED WhiteKnight):
444             case SHOGI (PROMOTED WhiteQueen):
445             case SHOGI (PROMOTED WhiteFerz):
446               for (s = -1; s <= 1; s += 2) {
447                   if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
448                       !SameColor(board[rf][ff], board[rf + 1][ff + s])) {
449                       callback(board, flags, NormalMove,
450                                rf, ff, rf + 1, ff + s, closure);
451                   }
452               }
453               goto finishGold;
454
455             case SHOGI BlackWazir:
456             case SHOGI (PROMOTED BlackPawn):
457             case SHOGI (PROMOTED BlackKnight):
458             case SHOGI (PROMOTED BlackQueen):
459             case SHOGI (PROMOTED BlackFerz):
460               for (s = -1; s <= 1; s += 2) {
461                   if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
462                       !SameColor(board[rf][ff], board[rf - 1][ff + s])) {
463                       callback(board, flags, NormalMove,
464                                rf, ff, rf - 1, ff + s, closure);
465                   }
466               }             
467
468             case WhiteWazir:
469             case BlackWazir:
470             finishGold:
471               for (d = 0; d <= 1; d++)
472                 for (s = -1; s <= 1; s += 2) {
473                       rt = rf + s * d;
474                       ft = ff + s * (1 - d);
475                       if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
476                           && !SameColor(board[rf][ff], board[rt][ft]) &&
477                           (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) )
478                                callback(board, flags, NormalMove,
479                                         rf, ff, rt, ft, closure);
480                       }
481               break;
482
483             case WhiteAlfil:
484             case BlackAlfil:
485                 /* [HGM] support Shatranj pieces */
486                 for (rs = -1; rs <= 1; rs += 2) 
487                   for (fs = -1; fs <= 1; fs += 2) {
488                       rt = rf + 2 * rs;
489                       ft = ff + 2 * fs;
490                       if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
491                           && ( gameInfo.variant != VariantXiangqi ||
492                                board[rf+rs][ff+fs] == EmptySquare && (2*rf < BOARD_HEIGHT) == (2*rt < BOARD_HEIGHT) )
493                          
494                           && !SameColor(board[rf][ff], board[rt][ft]))
495                                callback(board, flags, NormalMove,
496                                         rf, ff, rt, ft, closure);
497                   }
498                 break;
499
500             /* Shogi Dragon Horse has to continue with Wazir after Bishop */
501             case SHOGI WhiteCardinal:
502             case SHOGI BlackCardinal:
503               m++;
504
505             /* Capablanca Archbishop continues as Knight                  */
506             case WhiteAngel:
507             case BlackAngel:
508               m++;
509
510             /* Shogi Bishops are ordinary Bishops */
511             case SHOGI WhiteBishop:
512             case SHOGI BlackBishop:
513             case WhiteBishop:
514             case BlackBishop:
515               for (rs = -1; rs <= 1; rs += 2) 
516                 for (fs = -1; fs <= 1; fs += 2) 
517                   for (i = 1;; i++) {
518                       rt = rf + (i * rs);
519                       ft = ff + (i * fs);
520                       if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
521                       if (SameColor(board[rf][ff], board[rt][ft])) break;
522                       callback(board, flags, NormalMove,
523                                rf, ff, rt, ft, closure);
524                       if (board[rt][ft] != EmptySquare) break;
525                   }
526                 if(m==1) goto mounted;
527                 if(m==2) goto finishGold;
528                 /* Bishop falls through */
529               break;
530
531             /* Shogi Lance is unlike anything, and asymmetric at that */
532             case SHOGI WhiteQueen:
533               for(i = 1;; i++) {
534                       rt = rf + i;
535                       ft = ff;
536                       if (rt >= BOARD_HEIGHT) break;
537                       if (SameColor(board[rf][ff], board[rt][ft])) break;
538                       callback(board, flags, NormalMove,
539                                rf, ff, rt, ft, closure);
540                       if (board[rt][ft] != EmptySquare) break;
541               }
542               break;
543
544             case SHOGI BlackQueen:
545               for(i = 1;; i++) {
546                       rt = rf - i;
547                       ft = ff;
548                       if (rt < 0) break;
549                       if (SameColor(board[rf][ff], board[rt][ft])) break;
550                       callback(board, flags, NormalMove,
551                                rf, ff, rt, ft, closure);
552                       if (board[rt][ft] != EmptySquare) break;
553               }
554               break;
555
556             /* Shogi Dragon King has to continue as Ferz after Rook moves */
557             case SHOGI WhiteDragon:
558             case SHOGI BlackDragon:
559               m++;
560
561             /* Capablanca Chancellor sets flag to continue as Knight      */
562             case WhiteMarshall:
563             case BlackMarshall:
564               m++;
565
566             /* Shogi Rooks are ordinary Rooks */
567             case SHOGI WhiteRook:
568             case SHOGI BlackRook:
569             case WhiteRook:
570             case BlackRook:
571               for (d = 0; d <= 1; d++)
572                 for (s = -1; s <= 1; s += 2)
573                   for (i = 1;; i++) {
574                       rt = rf + (i * s) * d;
575                       ft = ff + (i * s) * (1 - d);
576                       if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
577                       if (SameColor(board[rf][ff], board[rt][ft])) break;
578                       callback(board, flags, NormalMove,
579                                rf, ff, rt, ft, closure);
580                       if (board[rt][ft] != EmptySquare) break;
581                   }
582                 if(m==1) goto mounted;
583                 if(m==2) goto finishGold;
584               break;
585
586             case WhiteQueen:
587             case BlackQueen:
588               for (rs = -1; rs <= 1; rs++) 
589                 for (fs = -1; fs <= 1; fs++) {
590                     if (rs == 0 && fs == 0) continue;
591                     for (i = 1;; i++) {
592                         rt = rf + (i * rs);
593                         ft = ff + (i * fs);
594                         if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
595                         if (SameColor(board[rf][ff], board[rt][ft])) break;
596                         callback(board, flags, NormalMove,
597                                  rf, ff, rt, ft, closure);
598                         if (board[rt][ft] != EmptySquare) break;
599                     }
600                 }
601               break;
602
603             /* Shogi Pawn and Silver General: first the Pawn move,    */
604             /* then the General continues like a Ferz                 */
605             case SHOGI WhitePawn:
606             case SHOGI WhiteFerz:
607                   if (rf < BOARD_HEIGHT-1 &&
608                            !SameColor(board[rf][ff], board[rf + 1][ff]) ) 
609                            callback(board, flags, NormalMove,
610                                     rf, ff, rf + 1, ff, closure);
611               if(piece != SHOGI WhitePawn) goto finishSilver;
612               break;
613
614             case SHOGI BlackPawn:
615             case SHOGI BlackFerz:
616                   if (rf > 0 &&
617                            !SameColor(board[rf][ff], board[rf - 1][ff]) ) 
618                            callback(board, flags, NormalMove,
619                                     rf, ff, rf - 1, ff, closure);
620               if(piece == SHOGI BlackPawn) break;
621
622             case WhiteFerz:
623             case BlackFerz:
624             finishSilver:
625                 /* [HGM] support Shatranj pieces */
626                 for (rs = -1; rs <= 1; rs += 2) 
627                   for (fs = -1; fs <= 1; fs += 2) {
628                       rt = rf + rs;
629                       ft = ff + fs;
630                       if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
631                       if (!SameColor(board[rf][ff], board[rt][ft]) &&
632                           (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) )
633                                callback(board, flags, NormalMove,
634                                         rf, ff, rt, ft, closure);
635                   }
636                 break;
637
638             case WhiteSilver:
639             case BlackSilver:
640                 m++; // [HGM] superchess: use for Centaur
641             case WhiteMan:
642             case BlackMan:
643             case SHOGI WhiteKing:
644             case SHOGI BlackKing:
645             case WhiteKing:
646             case BlackKing:
647             walking:
648               for (i = -1; i <= 1; i++)
649                 for (j = -1; j <= 1; j++) {
650                     if (i == 0 && j == 0) continue;
651                     rt = rf + i;
652                     ft = ff + j;
653                     if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
654                     if (SameColor(board[rf][ff], board[rt][ft])) continue;
655                     callback(board, flags, NormalMove,
656                              rf, ff, rt, ft, closure);
657                 }
658                 if(m==1) goto mounted;
659               break;
660
661             case WhiteNightrider:
662             case BlackNightrider:
663               for (i = -1; i <= 1; i += 2)
664                 for (j = -1; j <= 1; j += 2)
665                   for (s = 1; s <= 2; s++) {  int k;
666                     for(k=1;; k++) {
667                       rt = rf + k*i*s;
668                       ft = ff + k*j*(3-s);
669                       if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
670                       if (SameColor(board[rf][ff], board[rt][ft])) break;
671                       callback(board, flags, NormalMove,
672                                rf, ff, rt, ft, closure);
673                       if (board[rt][ft] != EmptySquare) break;
674                     }
675                   }
676               break;
677
678           }
679       }
680 }
681
682
683 typedef struct {
684     MoveCallback cb;
685     VOIDSTAR cl;
686 } GenLegalClosure;
687
688 extern void GenLegalCallback P((Board board, int flags, ChessMove kind,
689                                 int rf, int ff, int rt, int ft,
690                                 VOIDSTAR closure));
691
692 void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure)
693      Board board;
694      int flags;
695      ChessMove kind;
696      int rf, ff, rt, ft;
697      VOIDSTAR closure;
698 {
699     register GenLegalClosure *cl = (GenLegalClosure *) closure;
700
701     if (!(flags & F_IGNORE_CHECK) &&
702         CheckTest(board, flags, rf, ff, rt, ft,
703                   kind == WhiteCapturesEnPassant ||
704                   kind == BlackCapturesEnPassant)) return;
705     if (flags & F_ATOMIC_CAPTURE) {
706       if (board[rt][ft] != EmptySquare ||
707           kind == WhiteCapturesEnPassant || kind == BlackCapturesEnPassant) {
708         int r, f;
709         ChessSquare king = (flags & F_WHITE_ON_MOVE) ? WhiteKing : BlackKing;
710         if (board[rf][ff] == king) return;
711         for (r = rt-1; r <= rt+1; r++) {
712           for (f = ft-1; f <= ft+1; f++) {
713             if (r >= 0 && r < BOARD_HEIGHT && f >= BOARD_LEFT && f < BOARD_RGHT &&
714                 board[r][f] == king) return;
715           }
716         }
717       }
718     }
719     cl->cb(board, flags, kind, rf, ff, rt, ft, cl->cl);
720 }
721
722
723 typedef struct {
724     int rf, ff, rt, ft;
725     ChessMove kind;
726 } LegalityTestClosure;
727
728
729 /* Like GenPseudoLegal, but (1) include castling moves, (2) unless
730    F_IGNORE_CHECK is set in the flags, omit moves that would leave the
731    king in check, and (3) if F_ATOMIC_CAPTURE is set in the flags, omit
732    moves that would destroy your own king.  The CASTLE_OK flags are
733    true if castling is not yet ruled out by a move of the king or
734    rook.  Return TRUE if the player on move is currently in check and
735    F_IGNORE_CHECK is not set.  [HGM] add castlingRights parameter */
736 int GenLegal(board, flags, epfile, castlingRights, callback, closure)
737      Board board;
738      int flags;
739      int epfile;
740      char castlingRights[];
741      MoveCallback callback;
742      VOIDSTAR closure;
743 {
744     GenLegalClosure cl;
745     int ff, ft, k, left, right;
746     int ignoreCheck = (flags & F_IGNORE_CHECK) != 0;
747     ChessSquare wKing = WhiteKing, bKing = BlackKing;
748
749     cl.cb = callback;
750     cl.cl = closure;
751     GenPseudoLegal(board, flags, epfile, GenLegalCallback, (VOIDSTAR) &cl);
752
753     if (!ignoreCheck &&
754         CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE;
755
756     /* Generate castling moves */
757     if(gameInfo.variant == VariantKnightmate) { /* [HGM] Knightmate */
758         wKing = WhiteUnicorn; bKing = BlackUnicorn;
759     }
760
761     for (ff = BOARD_WIDTH>>1; ff >= (BOARD_WIDTH-1)>>1; ff-- /*ics wild 1*/) {
762         if ((flags & F_WHITE_ON_MOVE) &&
763             (flags & F_WHITE_KCASTLE_OK) &&
764             board[0][ff] == wKing &&
765             board[0][ff + 1] == EmptySquare &&
766             board[0][ff + 2] == EmptySquare &&
767             board[0][BOARD_RGHT-3] == EmptySquare &&
768             board[0][BOARD_RGHT-2] == EmptySquare &&
769             board[0][BOARD_RGHT-1] == WhiteRook &&
770             castlingRights[0] >= 0 && /* [HGM] check rights */
771             ( castlingRights[2] == ff || castlingRights[6] == ff ) &&
772             (ignoreCheck ||                             
773              (!CheckTest(board, flags, 0, ff, 0, ff + 1, FALSE) &&
774               !CheckTest(board, flags, 0, ff, 0, BOARD_RGHT-3, FALSE) &&
775               (gameInfo.variant != VariantJanus || !CheckTest(board, flags, 0, ff, 0, BOARD_RGHT-2, FALSE)) &&
776               !CheckTest(board, flags, 0, ff, 0, ff + 2, FALSE)))) {
777
778             callback(board, flags,
779                      ff==BOARD_WIDTH>>1 ? WhiteKingSideCastle : WhiteKingSideCastleWild,
780                      0, ff, 0, ff + ((gameInfo.boardWidth+2)>>2) + (gameInfo.variant == VariantJanus), closure);
781         }
782         if ((flags & F_WHITE_ON_MOVE) &&
783             (flags & F_WHITE_QCASTLE_OK) &&
784             board[0][ff] == wKing &&
785             board[0][ff - 1] == EmptySquare &&
786             board[0][ff - 2] == EmptySquare &&
787             board[0][BOARD_LEFT+2] == EmptySquare &&
788             board[0][BOARD_LEFT+1] == EmptySquare &&
789             board[0][BOARD_LEFT+0] == WhiteRook &&
790             castlingRights[1] >= 0 && /* [HGM] check rights */
791             ( castlingRights[2] == ff || castlingRights[6] == ff ) &&
792             (ignoreCheck ||
793              (!CheckTest(board, flags, 0, ff, 0, ff - 1, FALSE) &&
794               !CheckTest(board, flags, 0, ff, 0, BOARD_LEFT+3, FALSE) &&
795               !CheckTest(board, flags, 0, ff, 0, ff - 2, FALSE)))) {
796
797             callback(board, flags,
798                      ff==BOARD_WIDTH>>1 ? WhiteQueenSideCastle : WhiteQueenSideCastleWild,
799                      0, ff, 0, ff - ((gameInfo.boardWidth+2)>>2), closure);
800         }
801         if (!(flags & F_WHITE_ON_MOVE) &&
802             (flags & F_BLACK_KCASTLE_OK) &&
803             board[BOARD_HEIGHT-1][ff] == bKing &&
804             board[BOARD_HEIGHT-1][ff + 1] == EmptySquare &&
805             board[BOARD_HEIGHT-1][ff + 2] == EmptySquare &&
806             board[BOARD_HEIGHT-1][BOARD_RGHT-3] == EmptySquare &&
807             board[BOARD_HEIGHT-1][BOARD_RGHT-2] == EmptySquare &&
808             board[BOARD_HEIGHT-1][BOARD_RGHT-1] == BlackRook &&
809             castlingRights[3] >= 0 && /* [HGM] check rights */
810             ( castlingRights[5] == ff || castlingRights[7] == ff ) &&
811             (ignoreCheck ||
812              (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 1, FALSE) &&
813               !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_RGHT-3, FALSE) &&
814               (gameInfo.variant != VariantJanus || !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_RGHT-2, FALSE)) &&
815               !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 2, FALSE)))) {
816
817             callback(board, flags,
818                      ff==BOARD_WIDTH>>1 ? BlackKingSideCastle : BlackKingSideCastleWild,
819                      BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + ((gameInfo.boardWidth+2)>>2) + (gameInfo.variant == VariantJanus), closure);
820         }
821         if (!(flags & F_WHITE_ON_MOVE) &&
822             (flags & F_BLACK_QCASTLE_OK) &&
823             board[BOARD_HEIGHT-1][ff] == bKing &&
824             board[BOARD_HEIGHT-1][ff - 1] == EmptySquare &&
825             board[BOARD_HEIGHT-1][ff - 2] == EmptySquare &&
826             board[BOARD_HEIGHT-1][BOARD_LEFT+2] == EmptySquare &&
827             board[BOARD_HEIGHT-1][BOARD_LEFT+1] == EmptySquare &&
828             board[BOARD_HEIGHT-1][BOARD_LEFT+0] == BlackRook &&
829             castlingRights[4] >= 0 && /* [HGM] check rights */
830             ( castlingRights[5] == ff || castlingRights[7] == ff ) &&
831             (ignoreCheck ||
832              (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE) &&
833               !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_LEFT+3, FALSE) &&
834               !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 2, FALSE)))) {
835
836             callback(board, flags,
837                      ff==BOARD_WIDTH>>1 ? BlackQueenSideCastle : BlackQueenSideCastleWild,
838                      BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - ((gameInfo.boardWidth+2)>>2), closure);
839         }
840     }
841
842   if(gameInfo.variant == VariantFischeRandom) {
843
844     /* generate all potential FRC castling moves (KxR), ignoring flags */
845     /* [HGM] test if the Rooks we find have castling rights */
846
847
848     if ((flags & F_WHITE_ON_MOVE) != 0) {
849         ff = castlingRights[2]; /* King file if we have any rights */
850         if(ff > 0 && board[0][ff] == WhiteKing) {
851     if (appData.debugMode) {
852         fprintf(debugFP, "FRC castling, %d %d %d %d %d %d\n",
853                 castlingRights[0],castlingRights[1],ff,castlingRights[3],castlingRights[4],castlingRights[5]);
854     }
855             ft = castlingRights[0]; /* Rook file if we have H-side rights */
856             left  = ff+1;
857             right = BOARD_RGHT-2;
858             if(ff == BOARD_RGHT-2) left = right = ff-1;    /* special case */
859             for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */
860                 if(k != ft && board[0][k] != EmptySquare) ft = -1;
861             for(k=left; k<right && ft >= 0; k++) /* then if not checked */
862                 if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = -1;
863             if(ft >= 0 && board[0][ft] == WhiteRook)
864                 callback(board, flags, WhiteHSideCastleFR, 0, ff, 0, ft, closure);
865
866             ft = castlingRights[1]; /* Rook file if we have A-side rights */
867             left  = BOARD_LEFT+2;
868             right = ff-1;
869             if(ff <= BOARD_LEFT+2) { left = ff+1; right = BOARD_LEFT+3; }
870             for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */
871                 if(k != ft && board[0][k] != EmptySquare) ft = -1;
872             if(ff > BOARD_LEFT+2) 
873             for(k=left+1; k<=right && ft >= 0; k++) /* then if not checked */
874                 if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = -1;
875             if(ft >= 0 && board[0][ft] == WhiteRook)
876                 callback(board, flags, WhiteASideCastleFR, 0, ff, 0, ft, closure);
877         }
878     } else {
879         ff = castlingRights[5]; /* King file if we have any rights */
880         if(ff > 0 && board[BOARD_HEIGHT-1][ff] == BlackKing) {
881             ft = castlingRights[3]; /* Rook file if we have H-side rights */
882             left  = ff+1;
883             right = BOARD_RGHT-2;
884             if(ff == BOARD_RGHT-2) left = right = ff-1;    /* special case */
885             for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */
886                 if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = -1;
887             for(k=left; k<right && ft >= 0; k++) /* then if not checked */
888                 if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = -1;
889             if(ft >= 0 && board[BOARD_HEIGHT-1][ft] == BlackRook)
890                 callback(board, flags, BlackHSideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);
891
892             ft = castlingRights[4]; /* Rook file if we have A-side rights */
893             left  = BOARD_LEFT+2;
894             right = ff-1;
895             if(ff <= BOARD_LEFT+2) { left = ff+1; right = BOARD_LEFT+3; }
896             for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */
897                 if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = -1;
898             if(ff > BOARD_LEFT+2) 
899             for(k=left+1; k<=right && ft >= 0; k++) /* then if not checked */
900                 if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = -1;
901             if(ft >= 0 && board[BOARD_HEIGHT-1][ft] == BlackRook)
902                 callback(board, flags, BlackASideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);
903         }
904     }
905
906   }
907
908     return FALSE;
909 }
910
911
912 typedef struct {
913     int rking, fking;
914     int check;
915 } CheckTestClosure;
916
917
918 extern void CheckTestCallback P((Board board, int flags, ChessMove kind,
919                                  int rf, int ff, int rt, int ft,
920                                  VOIDSTAR closure));
921
922
923 void CheckTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
924      Board board;
925      int flags;
926      ChessMove kind;
927      int rf, ff, rt, ft;
928      VOIDSTAR closure;
929 {
930     register CheckTestClosure *cl = (CheckTestClosure *) closure;
931
932     if (rt == cl->rking && ft == cl->fking) cl->check++;
933 }
934
935
936 /* If the player on move were to move from (rf, ff) to (rt, ft), would
937    he leave himself in check?  Or if rf == -1, is the player on move
938    in check now?  enPassant must be TRUE if the indicated move is an
939    e.p. capture.  The possibility of castling out of a check along the
940    back rank is not accounted for (i.e., we still return nonzero), as
941    this is illegal anyway.  Return value is the number of times the
942    king is in check. */ 
943 int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
944      Board board;
945      int flags;
946      int rf, ff, rt, ft, enPassant;
947 {
948     CheckTestClosure cl;
949     ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing;
950     ChessSquare captured = EmptySquare;
951     /*  Suppress warnings on uninitialized variables    */
952
953     if(gameInfo.variant == VariantXiangqi)
954         king = flags & F_WHITE_ON_MOVE ? WhiteWazir : BlackWazir;
955     if(gameInfo.variant == VariantKnightmate)
956         king = flags & F_WHITE_ON_MOVE ? WhiteUnicorn : BlackUnicorn;
957
958     if (rf >= 0) {
959         if (enPassant) {
960             captured = board[rf][ft];
961             board[rf][ft] = EmptySquare;
962         } else {
963             captured = board[rt][ft];
964         }
965         board[rt][ft] = board[rf][ff];
966         board[rf][ff] = EmptySquare;
967     }
968
969     /* For compatibility with ICS wild 9, we scan the board in the
970        order a1, a2, a3, ... b1, b2, ..., h8 to find the first king,
971        and we test only whether that one is in check. */
972     cl.check = 0;
973     for (cl.fking = BOARD_LEFT+0; cl.fking < BOARD_RGHT; cl.fking++)
974         for (cl.rking = 0; cl.rking < BOARD_HEIGHT; cl.rking++) {
975           if (board[cl.rking][cl.fking] == king) {
976               if(gameInfo.variant == VariantXiangqi) {
977                   /* [HGM] In Xiangqi opposing Kings means check as well */
978                   int i, dir;
979                   dir = (king >= BlackPawn) ? -1 : 1;
980                   for( i=cl.rking+dir; i>=0 && i<BOARD_HEIGHT &&
981                                 board[i][cl.fking] == EmptySquare; i+=dir );
982                   if(i>=0 && i<BOARD_HEIGHT &&
983                       board[i][cl.fking] == (dir>0 ? BlackWazir : WhiteWazir) )
984                           cl.check++;
985               }
986
987               GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, -1,
988                              CheckTestCallback, (VOIDSTAR) &cl);
989               goto undo_move;  /* 2-level break */
990           }
991       }
992
993   undo_move:
994
995     if (rf >= 0) {
996         board[rf][ff] = board[rt][ft];
997         if (enPassant) {
998             board[rf][ft] = captured;
999             board[rt][ft] = EmptySquare;
1000         } else {
1001             board[rt][ft] = captured;
1002         }
1003     }
1004
1005     return cl.check;
1006 }
1007
1008
1009 extern void LegalityTestCallback P((Board board, int flags, ChessMove kind,
1010                                     int rf, int ff, int rt, int ft,
1011                                     VOIDSTAR closure));
1012
1013 void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
1014      Board board;
1015      int flags;
1016      ChessMove kind;
1017      int rf, ff, rt, ft;
1018      VOIDSTAR closure;
1019 {
1020     register LegalityTestClosure *cl = (LegalityTestClosure *) closure;
1021
1022 //    if (appData.debugMode) {
1023 //        fprintf(debugFP, "Legality test: %c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE);
1024 //    }
1025     if (rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft)
1026       cl->kind = kind;
1027 }
1028
1029 ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, promoChar)
1030      Board board;
1031      int flags, epfile;
1032      int rf, ff, rt, ft, promoChar;
1033      char castlingRights[];
1034 {
1035     LegalityTestClosure cl; ChessSquare piece = board[rf][ff];
1036     
1037     if (appData.debugMode) {
1038         int i;
1039         for(i=0; i<6; i++) fprintf(debugFP, "%d ", castlingRights[i]);
1040         fprintf(debugFP, "Legality test? %c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE);
1041     }
1042     /* [HGM] Lance, Cobra and Falcon are wildcard pieces; consider all their moves legal */
1043     /* (perhaps we should disallow moves that obviously leave us in check?)              */
1044     if(piece == WhiteFalcon || piece == BlackFalcon ||
1045        piece == WhiteCobra  || piece == BlackCobra  ||
1046        piece == WhiteLance  || piece == BlackLance)
1047         return NormalMove;
1048
1049     cl.rf = rf;
1050     cl.ff = ff;
1051     cl.rt = rt;
1052     cl.ft = ft;
1053     cl.kind = IllegalMove;
1054     GenLegal(board, flags, epfile, castlingRights, LegalityTestCallback, (VOIDSTAR) &cl);
1055
1056     if(gameInfo.variant == VariantShogi) {
1057         /* [HGM] Shogi promotions. '=' means defer */
1058         if(rf != DROP_RANK && cl.kind == NormalMove) {
1059             ChessSquare piece = board[rf][ff];
1060
1061             if(promoChar == PieceToChar(BlackQueen)) promoChar = NULLCHAR; /* [HGM] Kludge */
1062             if(promoChar != NULLCHAR && promoChar != 'x' &&
1063                promoChar != '+' && promoChar != '=' &&
1064                ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(promoChar) )
1065                     cl.kind = IllegalMove;
1066             else if(flags & F_WHITE_ON_MOVE) {
1067                 if( (int) piece < (int) WhiteWazir &&
1068                      (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) {
1069                     if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||
1070                          piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */
1071                              cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight;
1072                     else /* promotion optional, default is promote */
1073                              cl.kind = promoChar == '=' ? NormalMove  : WhitePromotionQueen;
1074                    
1075                 } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?
1076                                             NormalMove : IllegalMove;
1077             } else {
1078                 if( (int) piece < (int) BlackWazir && (rf < 3 || rt < 3) ) {
1079                     if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||
1080                          piece == BlackKnight && rt < 2 ) /* promotion obligatory */
1081                              cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight;
1082                     else /* promotion optional, default is promote */
1083                              cl.kind = promoChar == '=' ? NormalMove  : BlackPromotionQueen;
1084
1085                 } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?
1086                                             NormalMove : IllegalMove;
1087             }
1088         }
1089     } else
1090     if (promoChar != NULLCHAR && promoChar != 'x') {
1091         if(promoChar == '=') cl.kind = IllegalMove; else // [HGM] shogi: no deferred promotion outside Shogi
1092         if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {
1093             cl.kind = 
1094               PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0, promoChar);
1095         } else {
1096             cl.kind = IllegalMove;
1097         }
1098     }
1099     /* [HGM] For promotions, 'ToQueen' = optional, 'ToKnight' = mandatory */
1100     return cl.kind;
1101 }
1102
1103 typedef struct {
1104     int count;
1105 } MateTestClosure;
1106
1107 extern void MateTestCallback P((Board board, int flags, ChessMove kind,
1108                                 int rf, int ff, int rt, int ft,
1109                                 VOIDSTAR closure));
1110
1111 void MateTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
1112      Board board;
1113      int flags;
1114      ChessMove kind;
1115      int rf, ff, rt, ft;
1116      VOIDSTAR closure;
1117 {
1118     register MateTestClosure *cl = (MateTestClosure *) closure;
1119
1120     cl->count++;
1121 }
1122
1123 /* Return MT_NONE, MT_CHECK, MT_CHECKMATE, or MT_STALEMATE */
1124 int MateTest(board, flags, epfile, castlingRights)
1125      Board board;
1126      int flags, epfile;
1127      char castlingRights[];
1128 {
1129     MateTestClosure cl;
1130     int inCheck;
1131
1132     cl.count = 0;
1133     inCheck = GenLegal(board, flags, epfile, castlingRights, MateTestCallback, (VOIDSTAR) &cl);
1134     if (cl.count > 0) {
1135         return inCheck ? MT_CHECK : MT_NONE;
1136     } else {
1137         return inCheck || gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj ?
1138                          MT_CHECKMATE : MT_STALEMATE;
1139     }
1140 }
1141
1142      
1143 extern void DisambiguateCallback P((Board board, int flags, ChessMove kind,
1144                                     int rf, int ff, int rt, int ft,
1145                                     VOIDSTAR closure));
1146
1147 void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure)
1148      Board board;
1149      int flags;
1150      ChessMove kind;
1151      int rf, ff, rt, ft;
1152      VOIDSTAR closure;
1153 {
1154     register DisambiguateClosure *cl = (DisambiguateClosure *) closure;
1155
1156     if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]
1157          || PieceToChar(board[rf][ff]) == '~'
1158               && cl->pieceIn == (ChessSquare)(DEMOTED board[rf][ff])
1159                                                                       ) &&
1160         (cl->rfIn == -1 || cl->rfIn == rf) &&
1161         (cl->ffIn == -1 || cl->ffIn == ff) &&
1162         (cl->rtIn == -1 || cl->rtIn == rt) &&
1163         (cl->ftIn == -1 || cl->ftIn == ft)) {
1164
1165         cl->count++;
1166         cl->piece = board[rf][ff];
1167         cl->rf = rf;
1168         cl->ff = ff;
1169         cl->rt = rt;
1170         cl->ft = ft;
1171         cl->kind = kind;
1172     }
1173 }
1174
1175 void Disambiguate(board, flags, epfile, closure)
1176      Board board;
1177      int flags, epfile;
1178      DisambiguateClosure *closure;
1179 {
1180     int illegal = 0; char c = closure->promoCharIn;
1181     closure->count = 0;
1182     closure->rf = closure->ff = closure->rt = closure->ft = 0;
1183     closure->kind = ImpossibleMove;
1184     if (appData.debugMode) {
1185         fprintf(debugFP, "Disambiguate in:  %d(%d,%d)-(%d,%d) = %d (%c)\n",
1186                              closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,
1187                              closure->promoCharIn, closure->promoCharIn >= ' ' ? closure->promoCharIn : '-');
1188     }
1189     GenLegal(board, flags, epfile, initialRights, DisambiguateCallback, (VOIDSTAR) closure);
1190     if (closure->count == 0) {
1191         /* See if it's an illegal move due to check */
1192         illegal = 1;
1193         GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights, DisambiguateCallback,
1194                  (VOIDSTAR) closure);   
1195         if (closure->count == 0) {
1196             /* No, it's not even that */
1197     if (appData.debugMode) { int i, j;
1198         for(i=BOARD_HEIGHT-1; i>=0; i--) {
1199                 for(j=0; j<BOARD_WIDTH; j++)
1200                         fprintf(debugFP, "%3d", (int) board[i][j]);
1201                 fprintf(debugFP, "\n");
1202         }
1203     }
1204             return;
1205         }
1206     }
1207
1208     if(gameInfo.variant == VariantShogi) {
1209         /* [HGM] Shogi promotions. '=' means defer */
1210         if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) {
1211             ChessSquare piece = closure->piece;
1212 #if 0
1213     if (appData.debugMode) {
1214         fprintf(debugFP, "Disambiguate A:   %d(%d,%d)-(%d,%d) = %d (%c)\n",
1215                           closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,
1216                           closure->promoCharIn,closure->promoCharIn);
1217     }
1218 #endif
1219             if(c != NULLCHAR && c != 'x' && c != '+' && c != '=' &&
1220                ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(c) ) 
1221                     closure->kind = IllegalMove;
1222             else if(flags & F_WHITE_ON_MOVE) {
1223 #if 0
1224     if (appData.debugMode) {
1225         fprintf(debugFP, "Disambiguate B:   %d(%d,%d)-(%d,%d) = %d (%c)\n",
1226                           closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,
1227                           closure->promoCharIn,closure->promoCharIn);
1228     }
1229 #endif
1230                 if( (int) piece < (int) WhiteWazir &&
1231                      (closure->rf > BOARD_HEIGHT-4 || closure->rt > BOARD_HEIGHT-4) ) {
1232                     if( (piece == WhitePawn || piece == WhiteQueen) && closure->rt > BOARD_HEIGHT-2 ||
1233                          piece == WhiteKnight && closure->rt > BOARD_HEIGHT-3) /* promotion mandatory */
1234                              closure->kind = c == '=' ? IllegalMove : WhitePromotionKnight;
1235                     else /* promotion optional, default is promote */
1236                              closure->kind = c == '=' ? NormalMove  : WhitePromotionQueen;
1237                    
1238                 } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ?
1239                                             NormalMove : IllegalMove;
1240             } else {
1241                 if( (int) piece < (int) BlackWazir && (closure->rf < 3 || closure->rt < 3) ) {
1242                     if( (piece == BlackPawn || piece == BlackQueen) && closure->rt < 1 ||
1243                          piece == BlackKnight && closure->rt < 2 ) /* promotion obligatory */
1244                              closure->kind = c == '=' ? IllegalMove : BlackPromotionKnight;
1245                     else /* promotion optional, default is promote */
1246                              closure->kind = c == '=' ? NormalMove  : BlackPromotionQueen;
1247
1248                 } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ?
1249                                             NormalMove : IllegalMove;
1250             }
1251         }
1252     } else
1253     if (closure->promoCharIn != NULLCHAR && closure->promoCharIn != 'x') {
1254         if (closure->kind == WhitePromotionQueen
1255             || closure->kind == BlackPromotionQueen) {
1256             closure->kind = 
1257               PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0,
1258                                   closure->promoCharIn);
1259         } else {
1260             closure->kind = IllegalMove;
1261         }
1262     }
1263 #if 0
1264     if (appData.debugMode) {
1265         fprintf(debugFP, "Disambiguate C:   %d(%d,%d)-(%d,%d) = %d (%c)\n",
1266                           closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,
1267                           closure->promoCharIn,closure->promoCharIn);
1268     }
1269 #endif
1270     /* [HGM] returns 'q' for optional promotion, 'n' for mandatory */
1271     if(closure->promoCharIn != '=')
1272         closure->promoChar = ToLower(closure->promoCharIn);
1273     else closure->promoChar = '=';
1274     if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;
1275     if (closure->count > 1) {
1276         closure->kind = AmbiguousMove;
1277     }
1278     if (illegal) {
1279         /* Note: If more than one illegal move matches, but no legal
1280            moves, we return IllegalMove, not AmbiguousMove.  Caller
1281            can look at closure->count to detect this.
1282         */
1283         closure->kind = IllegalMove;
1284     }
1285     if(closure->kind == IllegalMove)
1286     /* [HGM] might be a variant we don't understand, pass on promotion info */
1287         closure->promoChar = ToLower(closure->promoCharIn);
1288     if (appData.debugMode) {
1289         fprintf(debugFP, "Disambiguate out: %d(%d,%d)-(%d,%d) = %d (%c)\n",
1290         closure->piece,closure->ff,closure->rf,closure->ft,closure->rt,closure->promoChar,
1291         closure->promoChar >= ' ' ? closure->promoChar:'-');
1292     }
1293 }
1294
1295
1296 typedef struct {
1297     /* Input */
1298     ChessSquare piece;
1299     int rf, ff, rt, ft;
1300     /* Output */
1301     ChessMove kind;
1302     int rank;
1303     int file;
1304     int either;
1305 } CoordsToAlgebraicClosure;
1306
1307 extern void CoordsToAlgebraicCallback P((Board board, int flags,
1308                                          ChessMove kind, int rf, int ff,
1309                                          int rt, int ft, VOIDSTAR closure));
1310
1311 void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure)
1312      Board board;
1313      int flags;
1314      ChessMove kind;
1315      int rf, ff, rt, ft;
1316      VOIDSTAR closure;
1317 {
1318     register CoordsToAlgebraicClosure *cl =
1319       (CoordsToAlgebraicClosure *) closure;
1320
1321     if (rt == cl->rt && ft == cl->ft &&
1322         (board[rf][ff] == cl->piece
1323          || PieceToChar(board[rf][ff]) == '~' &&
1324             (ChessSquare) (DEMOTED board[rf][ff]) == cl->piece)
1325                                      ) {
1326         if (rf == cl->rf) {
1327             if (ff == cl->ff) {
1328                 cl->kind = kind; /* this is the move we want */
1329             } else {
1330                 cl->file++; /* need file to rule out this move */
1331             }
1332         } else {
1333             if (ff == cl->ff) {
1334                 cl->rank++; /* need rank to rule out this move */
1335             } else {
1336                 cl->either++; /* rank or file will rule out this move */
1337             }
1338         }           
1339     }
1340 }
1341
1342 /* Convert coordinates to normal algebraic notation.
1343    promoChar must be NULLCHAR or 'x' if not a promotion.
1344 */
1345 ChessMove CoordsToAlgebraic(board, flags, epfile,
1346                             rf, ff, rt, ft, promoChar, out)
1347      Board board;
1348      int flags, epfile;
1349      int rf, ff, rt, ft;
1350      int promoChar;
1351      char out[MOVE_LEN];
1352 {
1353     ChessSquare piece;
1354     ChessMove kind;
1355     char *outp = out, c;
1356     CoordsToAlgebraicClosure cl;
1357     
1358     if (rf == DROP_RANK) {
1359         /* Bughouse piece drop */
1360         *outp++ = ToUpper(PieceToChar((ChessSquare) ff));
1361         *outp++ = '@';
1362         *outp++ = ft + AAA;
1363         if(rt+ONE <= '9')
1364            *outp++ = rt + ONE;
1365         else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
1366         *outp = NULLCHAR;
1367         return (flags & F_WHITE_ON_MOVE) ? WhiteDrop : BlackDrop;
1368     }
1369
1370     if (promoChar == 'x') promoChar = NULLCHAR;
1371     piece = board[rf][ff];
1372     if(PieceToChar(piece)=='~') piece = (ChessSquare)(DEMOTED piece);
1373
1374   if (appData.debugMode)
1375           fprintf(debugFP, "CoordsToAlgebraic, piece=%d (%d,%d)-(%d,%d) %c\n", (int)piece,ff,rf,ft,rt,promoChar >= ' ' ? promoChar : '-');
1376     switch (piece) {
1377       case WhitePawn:
1378       case BlackPawn:
1379         kind = LegalityTest(board, flags, epfile, initialRights, rf, ff, rt, ft, promoChar);
1380         if (kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {
1381             /* Keep short notation if move is illegal only because it
1382                leaves the player in check, but still return IllegalMove */
1383             kind = LegalityTest(board, flags|F_IGNORE_CHECK, epfile, initialRights,
1384                                rf, ff, rt, ft, promoChar);
1385             if (kind == IllegalMove) break;
1386             kind = IllegalMove;
1387         }
1388         /* Pawn move */
1389         *outp++ = ff + AAA;
1390         if (ff == ft && board[rt][ft] == EmptySquare) { /* [HGM] Xiangqi has straight noncapts! */
1391             /* Non-capture; use style "e5" */
1392             if(rt+ONE <= '9')
1393                *outp++ = rt + ONE;
1394             else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
1395         } else {
1396             /* Capture; use style "exd5" */
1397             if(gameInfo.variant != VariantXiangqi || board[rt][ft] != EmptySquare )
1398             *outp++ = 'x';  /* [HGM] Xiangqi has sideway noncaptures across river! */
1399             *outp++ = ft + AAA;
1400             if(rt+ONE <= '9')
1401                *outp++ = rt + ONE;
1402             else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
1403         }
1404         /* Use promotion suffix style "=Q" */
1405         *outp = NULLCHAR;
1406   if (appData.debugMode)
1407           fprintf(debugFP, "movetype=%d, promochar=%d=%c\n", (int)kind, promoChar, promoChar >= ' ' ? promoChar : '-');
1408         if (promoChar != NULLCHAR) {
1409             if(gameInfo.variant == VariantShogi) {
1410                 /* [HGM] ... but not in Shogi! */
1411                 *outp++ = promoChar == '=' ? '=' : '+';
1412             } else {
1413                 *outp++ = '=';
1414                 *outp++ = ToUpper(promoChar);
1415             }
1416             *outp = NULLCHAR;
1417         }
1418         return kind;
1419
1420         
1421       case WhiteKing:
1422       case BlackKing:
1423         /* Fabien moved code: FRC castling first (if KxR), wild castling second */
1424         /* Code added by Tord:  FRC castling. */
1425         if((piece == WhiteKing && board[rt][ft] == WhiteRook) ||
1426            (piece == BlackKing && board[rt][ft] == BlackRook)) {
1427           if(ft > ff) strcpy(out, "O-O"); else strcpy(out, "O-O-O");
1428             return LegalityTest(board, flags, epfile, initialRights,
1429                                 rf, ff, rt, ft, promoChar);
1430         }
1431         /* End of code added by Tord */
1432         /* Test for castling or ICS wild castling */
1433         /* Use style "O-O" (oh-oh) for PGN compatibility */
1434         else if (rf == rt &&
1435             rf == ((piece == WhiteKing) ? 0 : BOARD_HEIGHT-1) &&
1436             ((ff == BOARD_WIDTH>>1 && (ft == BOARD_LEFT+2 || ft == BOARD_RGHT-2)) ||
1437              (ff == (BOARD_WIDTH-1)>>1 && (ft == BOARD_LEFT+1 || ft == BOARD_RGHT-3)))) {
1438             if(ft==BOARD_LEFT+1 || ft==BOARD_RGHT-2)
1439                 strcpy(out, "O-O");
1440             else
1441                 strcpy(out, "O-O-O");
1442
1443             /* This notation is always unambiguous, unless there are
1444                kings on both the d and e files, with "wild castling"
1445                possible for the king on the d file and normal castling
1446                possible for the other.  ICS rules for wild 9
1447                effectively make castling illegal for either king in
1448                this situation.  So I am not going to worry about it;
1449                I'll just generate an ambiguous O-O in this case.
1450             */
1451             return LegalityTest(board, flags, epfile, initialRights,
1452                                 rf, ff, rt, ft, promoChar);
1453         }
1454
1455         /* else fall through */
1456       default:
1457         /* Piece move */
1458         cl.rf = rf;
1459         cl.ff = ff;
1460         cl.rt = rt;
1461         cl.ft = ft;
1462         cl.piece = piece;
1463         cl.kind = IllegalMove;
1464         cl.rank = cl.file = cl.either = 0;
1465         GenLegal(board, flags, epfile, initialRights,
1466                  CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
1467
1468         if (cl.kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {
1469             /* Generate pretty moves for moving into check, but
1470                still return IllegalMove.
1471             */
1472             GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights,
1473                      CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
1474             if (cl.kind == IllegalMove) break;
1475             cl.kind = IllegalMove;
1476         }
1477
1478         /* Style is "Nf3" or "Nxf7" if this is unambiguous,
1479            else "Ngf3" or "Ngxf7",
1480            else "N1f3" or "N5xf7",
1481            else "Ng1f3" or "Ng5xf7".
1482         */
1483         c = PieceToChar(piece) ;
1484         if( c == '~' || c == '+') {
1485            /* [HGM] print nonexistent piece as its demoted version */
1486            piece = (ChessSquare) (DEMOTED piece);
1487         }
1488         if(c=='+') *outp++ = c;
1489         *outp++ = ToUpper(PieceToChar(piece));
1490
1491         if (cl.file || (cl.either && !cl.rank)) {
1492             *outp++ = ff + AAA;
1493         }
1494         if (cl.rank) {
1495             if(rf+ONE <= '9')
1496                 *outp++ = rf + ONE;
1497             else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }
1498         }
1499
1500         if(board[rt][ft] != EmptySquare)
1501           *outp++ = 'x';
1502
1503         *outp++ = ft + AAA;
1504         if(rt+ONE <= '9')
1505            *outp++ = rt + ONE;
1506         else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
1507         *outp = NULLCHAR;
1508         if (gameInfo.variant == VariantShogi) {
1509             /* [HGM] in Shogi non-pawns can promote */
1510             if(flags & F_WHITE_ON_MOVE) {
1511                 if( (int) cl.piece < (int) WhiteWazir &&
1512                      (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) {
1513                     if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||
1514                          piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */
1515                              cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight;
1516                     else cl.kind =  WhitePromotionQueen; /* promotion optional */
1517                    
1518                 } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?
1519                                             NormalMove : IllegalMove;
1520             } else {
1521                 if( (int) cl.piece < (int) BlackWazir && (rf < 3 || rt < 3) ) {
1522                     if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||
1523                          piece == BlackKnight && rt < 2 ) /* promotion obligatory */
1524                              cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight;
1525                     else cl.kind =  BlackPromotionQueen; /* promotion optional */
1526                 } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?
1527                                             NormalMove : IllegalMove;
1528             }
1529             if(cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {
1530                 /* for optional promotions append '+' or '=' */
1531                 if(promoChar == '=') {
1532                     *outp++ = '=';
1533                     cl.kind = NormalMove;
1534                 } else *outp++ = '+';
1535                 *outp = NULLCHAR;
1536             } else if(cl.kind == IllegalMove) {
1537                 /* Illegal move specifies any given promotion */
1538                 if(promoChar != NULLCHAR && promoChar != 'x') {
1539                     *outp++ = '=';
1540                     *outp++ = ToUpper(promoChar);
1541                     *outp = NULLCHAR;
1542                 }
1543             }
1544         }
1545         return cl.kind;
1546         
1547       /* [HGM] Always long notation for fairies we don't know */
1548       case WhiteFalcon:
1549       case BlackFalcon:
1550       case WhiteLance:
1551       case BlackLance:
1552       case WhiteGrasshopper:
1553       case BlackGrasshopper:
1554       case EmptySquare:
1555         /* Moving a nonexistent piece */
1556         break;
1557     }
1558     
1559     /* Not a legal move, even ignoring check.
1560        If there was a piece on the from square, 
1561        use style "Ng1g3" or "Ng1xe8";
1562        if there was a pawn or nothing (!),
1563        use style "g1g3" or "g1xe8".  Use "x"
1564        if a piece was on the to square, even
1565        a piece of the same color.
1566     */
1567     outp = out;
1568     if (piece != EmptySquare && piece != WhitePawn && piece != BlackPawn) {
1569         *outp++ = ToUpper(PieceToChar(piece));
1570     }
1571     *outp++ = ff + AAA;
1572     if(rf+ONE <= '9')
1573        *outp++ = rf + ONE;
1574     else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }
1575     if (board[rt][ft] != EmptySquare) *outp++ = 'x';
1576     *outp++ = ft + AAA;
1577     if(rt+ONE <= '9')
1578        *outp++ = rt + ONE;
1579     else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
1580     /* Use promotion suffix style "=Q" */
1581     if (promoChar != NULLCHAR && promoChar != 'x') {
1582         *outp++ = '=';
1583         *outp++ = ToUpper(promoChar);
1584     }
1585     *outp = NULLCHAR;
1586
1587     return IllegalMove;
1588 }
1589
1590