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