changes from H.G. Muller; version 4.3.8
[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               if(gameInfo.variant == VariantXiangqi) {\r
936                   /* [HGM] In Xiangqi opposing Kings means check as well */\r
937                   int i, dir;\r
938                   dir = (king >= BlackPawn) ? -1 : 1;\r
939                   for( i=cl.rking+dir; i>=0 && i<BOARD_HEIGHT &&\r
940                                 board[i][cl.fking] == EmptySquare; i+=dir );\r
941                   if(i>=0 && i<BOARD_HEIGHT &&\r
942                       board[i][cl.fking] == (dir>0 ? BlackWazir : WhiteWazir) )\r
943                           cl.check++;\r
944               }\r
945 \r
946               GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, -1,\r
947                              CheckTestCallback, (VOIDSTAR) &cl);\r
948               goto undo_move;  /* 2-level break */\r
949           }\r
950       }\r
951 \r
952   undo_move:\r
953 \r
954     if (rf >= 0) {\r
955         board[rf][ff] = board[rt][ft];\r
956         if (enPassant) {\r
957             board[rf][ft] = captured;\r
958             board[rt][ft] = EmptySquare;\r
959         } else {\r
960             board[rt][ft] = captured;\r
961         }\r
962     }\r
963 \r
964     return cl.check;\r
965 }\r
966 \r
967 \r
968 extern void LegalityTestCallback P((Board board, int flags, ChessMove kind,\r
969                                     int rf, int ff, int rt, int ft,\r
970                                     VOIDSTAR closure));\r
971 \r
972 void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
973      Board board;\r
974      int flags;\r
975      ChessMove kind;\r
976      int rf, ff, rt, ft;\r
977      VOIDSTAR closure;\r
978 {\r
979     register LegalityTestClosure *cl = (LegalityTestClosure *) closure;\r
980 \r
981     if (appData.debugMode) {\r
982         fprintf(debugFP, "Legality test: %c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE);\r
983     }\r
984     if (rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft)\r
985       cl->kind = kind;\r
986 }\r
987 \r
988 ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, promoChar)\r
989      Board board;\r
990      int flags, epfile;\r
991      int rf, ff, rt, ft, promoChar;\r
992      char castlingRights[];\r
993 {\r
994     LegalityTestClosure cl;\r
995     \r
996     cl.rf = rf;\r
997     cl.ff = ff;\r
998     cl.rt = rt;\r
999     cl.ft = ft;\r
1000     cl.kind = IllegalMove;\r
1001     GenLegal(board, flags, epfile, castlingRights, LegalityTestCallback, (VOIDSTAR) &cl);\r
1002 \r
1003     if(gameInfo.variant == VariantShogi) {\r
1004         /* [HGM] Shogi promotions. '=' means defer */\r
1005         if(rf != DROP_RANK && cl.kind == NormalMove) {\r
1006             ChessSquare piece = board[rf][ff];\r
1007 \r
1008             if(promoChar == PieceToChar(BlackQueen)) promoChar = NULLCHAR; /* [HGM] Kludge */\r
1009             if(promoChar != NULLCHAR && promoChar != 'x' &&\r
1010                promoChar != '+' && promoChar != '=' &&\r
1011                ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(promoChar) )\r
1012                     cl.kind = IllegalMove;\r
1013             else if(flags & F_WHITE_ON_MOVE) {\r
1014                 if( (int) piece < (int) WhiteWazir &&\r
1015                      (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) {\r
1016                     if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||\r
1017                          piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */\r
1018                              cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight;\r
1019                     else /* promotion optional, default is promote */\r
1020                              cl.kind = promoChar == '=' ? NormalMove  : WhitePromotionQueen;\r
1021                    \r
1022                 } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
1023                                             NormalMove : IllegalMove;\r
1024             } else {\r
1025                 if( (int) piece < (int) BlackWazir && (rf < 3 || rt < 3) ) {\r
1026                     if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||\r
1027                          piece == BlackKnight && rt < 2 ) /* promotion obligatory */\r
1028                              cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight;\r
1029                     else /* promotion optional, default is promote */\r
1030                              cl.kind = promoChar == '=' ? NormalMove  : BlackPromotionQueen;\r
1031 \r
1032                 } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
1033                                             NormalMove : IllegalMove;\r
1034             }\r
1035         }\r
1036     } else\r
1037     if (promoChar != NULLCHAR && promoChar != 'x') {\r
1038         if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {\r
1039             cl.kind = \r
1040               PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0, promoChar);\r
1041         } else {\r
1042             cl.kind = IllegalMove;\r
1043         }\r
1044     }\r
1045     /* [HGM] For promotions, 'ToQueen' = optional, 'ToKnight' = mandatory */\r
1046     return cl.kind;\r
1047 }\r
1048 \r
1049 typedef struct {\r
1050     int count;\r
1051 } MateTestClosure;\r
1052 \r
1053 extern void MateTestCallback P((Board board, int flags, ChessMove kind,\r
1054                                 int rf, int ff, int rt, int ft,\r
1055                                 VOIDSTAR closure));\r
1056 \r
1057 void MateTestCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
1058      Board board;\r
1059      int flags;\r
1060      ChessMove kind;\r
1061      int rf, ff, rt, ft;\r
1062      VOIDSTAR closure;\r
1063 {\r
1064     register MateTestClosure *cl = (MateTestClosure *) closure;\r
1065 \r
1066     cl->count++;\r
1067 }\r
1068 \r
1069 /* Return MT_NONE, MT_CHECK, MT_CHECKMATE, or MT_STALEMATE */\r
1070 int MateTest(board, flags, epfile, castlingRights)\r
1071      Board board;\r
1072      int flags, epfile;\r
1073      char castlingRights[];\r
1074 {\r
1075     MateTestClosure cl;\r
1076     int inCheck;\r
1077 \r
1078     cl.count = 0;\r
1079     inCheck = GenLegal(board, flags, epfile, castlingRights, MateTestCallback, (VOIDSTAR) &cl);\r
1080     if (cl.count > 0) {\r
1081         return inCheck ? MT_CHECK : MT_NONE;\r
1082     } else {\r
1083         return inCheck || gameInfo.variant == VariantXiangqi ?\r
1084                          MT_CHECKMATE : MT_STALEMATE;\r
1085     }\r
1086 }\r
1087 \r
1088      \r
1089 extern void DisambiguateCallback P((Board board, int flags, ChessMove kind,\r
1090                                     int rf, int ff, int rt, int ft,\r
1091                                     VOIDSTAR closure));\r
1092 \r
1093 void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
1094      Board board;\r
1095      int flags;\r
1096      ChessMove kind;\r
1097      int rf, ff, rt, ft;\r
1098      VOIDSTAR closure;\r
1099 {\r
1100     register DisambiguateClosure *cl = (DisambiguateClosure *) closure;\r
1101 \r
1102     if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]) &&\r
1103         (cl->rfIn == -1 || cl->rfIn == rf) &&\r
1104         (cl->ffIn == -1 || cl->ffIn == ff) &&\r
1105         (cl->rtIn == -1 || cl->rtIn == rt) &&\r
1106         (cl->ftIn == -1 || cl->ftIn == ft)) {\r
1107 \r
1108         cl->count++;\r
1109         cl->piece = board[rf][ff];\r
1110         cl->rf = rf;\r
1111         cl->ff = ff;\r
1112         cl->rt = rt;\r
1113         cl->ft = ft;\r
1114         cl->kind = kind;\r
1115     }\r
1116 }\r
1117 \r
1118 void Disambiguate(board, flags, epfile, closure)\r
1119      Board board;\r
1120      int flags, epfile;\r
1121      DisambiguateClosure *closure;\r
1122 {\r
1123     int illegal = 0; char c = closure->promoCharIn;\r
1124     closure->count = 0;\r
1125     closure->rf = closure->ff = closure->rt = closure->ft = 0;\r
1126     closure->kind = ImpossibleMove;\r
1127     GenLegal(board, flags, epfile, initialRights, DisambiguateCallback, (VOIDSTAR) closure);\r
1128     if (closure->count == 0) {\r
1129         /* See if it's an illegal move due to check */\r
1130         illegal = 1;\r
1131         GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights, DisambiguateCallback,\r
1132                  (VOIDSTAR) closure);   \r
1133         if (closure->count == 0) {\r
1134             /* No, it's not even that */\r
1135             return;\r
1136         }\r
1137     }\r
1138 \r
1139     if (appData.debugMode) {\r
1140         fprintf(debugFP, "Disambiguate in:  %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
1141         closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,closure->promoCharIn,closure->promoCharIn);\r
1142     }\r
1143     if(gameInfo.variant == VariantShogi) {\r
1144         /* [HGM] Shogi promotions. '=' means defer */\r
1145         if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) {\r
1146             ChessSquare piece = closure->piece;\r
1147 \r
1148     if (appData.debugMode) {\r
1149         fprintf(debugFP, "Disambiguate A:   %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
1150         closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,closure->promoCharIn,closure->promoCharIn);\r
1151     }\r
1152             if(c != NULLCHAR && c != 'x' && c != '+' && c != '=' &&\r
1153                ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(c) ) \r
1154                     closure->kind = IllegalMove;\r
1155             else if(flags & F_WHITE_ON_MOVE) {\r
1156     if (appData.debugMode) {\r
1157         fprintf(debugFP, "Disambiguate B:   %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
1158         closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,closure->promoCharIn,closure->promoCharIn);\r
1159     }\r
1160                 if( (int) piece < (int) WhiteWazir &&\r
1161                      (closure->rf > BOARD_HEIGHT-4 || closure->rt > BOARD_HEIGHT-4) ) {\r
1162                     if( (piece == WhitePawn || piece == WhiteQueen) && closure->rt > BOARD_HEIGHT-2 ||\r
1163                          piece == WhiteKnight && closure->rt > BOARD_HEIGHT-3) /* promotion mandatory */\r
1164                              closure->kind = c == '=' ? IllegalMove : WhitePromotionKnight;\r
1165                     else /* promotion optional, default is promote */\r
1166                              closure->kind = c == '=' ? NormalMove  : WhitePromotionQueen;\r
1167                    \r
1168                 } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ?\r
1169                                             NormalMove : IllegalMove;\r
1170             } else {\r
1171                 if( (int) piece < (int) BlackWazir && (closure->rf < 3 || closure->rt < 3) ) {\r
1172                     if( (piece == BlackPawn || piece == BlackQueen) && closure->rt < 1 ||\r
1173                          piece == BlackKnight && closure->rt < 2 ) /* promotion obligatory */\r
1174                              closure->kind = c == '=' ? IllegalMove : BlackPromotionKnight;\r
1175                     else /* promotion optional, default is promote */\r
1176                              closure->kind = c == '=' ? NormalMove  : BlackPromotionQueen;\r
1177 \r
1178                 } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ?\r
1179                                             NormalMove : IllegalMove;\r
1180             }\r
1181         }\r
1182     } else\r
1183     if (closure->promoCharIn != NULLCHAR && closure->promoCharIn != 'x') {\r
1184         if (closure->kind == WhitePromotionQueen\r
1185             || closure->kind == BlackPromotionQueen) {\r
1186             closure->kind = \r
1187               PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0,\r
1188                                   closure->promoCharIn);\r
1189         } else {\r
1190             closure->kind = IllegalMove;\r
1191         }\r
1192     }\r
1193     if (appData.debugMode) {\r
1194         fprintf(debugFP, "Disambiguate C:   %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
1195         closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,closure->promoCharIn,closure->promoCharIn);\r
1196     }\r
1197     /* [HGM] returns 'q' for optional promotion, 'n' for mandatory */\r
1198     if(closure->promoCharIn != '=')\r
1199         closure->promoChar = ToLower(PieceToChar(PromoPiece(closure->kind)));\r
1200     else closure->promoChar = '=';\r
1201     if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;\r
1202     if (closure->count > 1) {\r
1203         closure->kind = AmbiguousMove;\r
1204     }\r
1205     if (illegal) {\r
1206         /* Note: If more than one illegal move matches, but no legal\r
1207            moves, we return IllegalMove, not AmbiguousMove.  Caller\r
1208            can look at closure->count to detect this.\r
1209         */\r
1210         closure->kind = IllegalMove;\r
1211     }\r
1212     if(closure->kind == IllegalMove)\r
1213     /* [HGM] might be a variant we don't understand, pass on promotion info */\r
1214         closure->promoChar = closure->promoCharIn;\r
1215     if (appData.debugMode) {\r
1216         fprintf(debugFP, "Disambiguate out: %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
1217         closure->piece,closure->ff,closure->rf,closure->ft,closure->rt,closure->promoChar,closure->promoChar);\r
1218     }\r
1219 }\r
1220 \r
1221 \r
1222 typedef struct {\r
1223     /* Input */\r
1224     ChessSquare piece;\r
1225     int rf, ff, rt, ft;\r
1226     /* Output */\r
1227     ChessMove kind;\r
1228     int rank;\r
1229     int file;\r
1230     int either;\r
1231 } CoordsToAlgebraicClosure;\r
1232 \r
1233 extern void CoordsToAlgebraicCallback P((Board board, int flags,\r
1234                                          ChessMove kind, int rf, int ff,\r
1235                                          int rt, int ft, VOIDSTAR closure));\r
1236 \r
1237 void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
1238      Board board;\r
1239      int flags;\r
1240      ChessMove kind;\r
1241      int rf, ff, rt, ft;\r
1242      VOIDSTAR closure;\r
1243 {\r
1244     register CoordsToAlgebraicClosure *cl =\r
1245       (CoordsToAlgebraicClosure *) closure;\r
1246 \r
1247     if (rt == cl->rt && ft == cl->ft &&\r
1248         board[rf][ff] == cl->piece) {\r
1249         if (rf == cl->rf) {\r
1250             if (ff == cl->ff) {\r
1251                 cl->kind = kind; /* this is the move we want */\r
1252             } else {\r
1253                 cl->file++; /* need file to rule out this move */\r
1254             }\r
1255         } else {\r
1256             if (ff == cl->ff) {\r
1257                 cl->rank++; /* need rank to rule out this move */\r
1258             } else {\r
1259                 cl->either++; /* rank or file will rule out this move */\r
1260             }\r
1261         }           \r
1262     }\r
1263 }\r
1264 \r
1265 /* Convert coordinates to normal algebraic notation.\r
1266    promoChar must be NULLCHAR or 'x' if not a promotion.\r
1267 */\r
1268 ChessMove CoordsToAlgebraic(board, flags, epfile,\r
1269                             rf, ff, rt, ft, promoChar, out)\r
1270      Board board;\r
1271      int flags, epfile;\r
1272      int rf, ff, rt, ft;\r
1273      int promoChar;\r
1274      char out[MOVE_LEN];\r
1275 {\r
1276     ChessSquare piece;\r
1277     ChessMove kind;\r
1278     char *outp = out;\r
1279     CoordsToAlgebraicClosure cl;\r
1280     \r
1281     if (rf == DROP_RANK) {\r
1282         /* Bughouse piece drop */\r
1283         *outp++ = ToUpper(PieceToChar((ChessSquare) ff));\r
1284         *outp++ = '@';\r
1285         *outp++ = ft + AAA;\r
1286         if(rt+ONE <= '9')\r
1287            *outp++ = rt + ONE;\r
1288         else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
1289         *outp = NULLCHAR;\r
1290         AlphaRank(out, 5);\r
1291         return (flags & F_WHITE_ON_MOVE) ? WhiteDrop : BlackDrop;\r
1292     }\r
1293 \r
1294     if (promoChar == 'x') promoChar = NULLCHAR;\r
1295     piece = board[rf][ff];\r
1296 \r
1297   if (appData.debugMode)\r
1298           fprintf(debugFP, "CoordsToAlgebraic, piece=%d\n", (int)piece);\r
1299     switch (piece) {\r
1300       case WhitePawn:\r
1301       case BlackPawn:\r
1302   if (appData.debugMode)\r
1303           fprintf(debugFP, "CoordsToAlgebraic, Pawn\n");\r
1304         kind = LegalityTest(board, flags, epfile, initialRights, rf, ff, rt, ft, promoChar);\r
1305         if (kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {\r
1306             /* Keep short notation if move is illegal only because it\r
1307                leaves the player in check, but still return IllegalMove */\r
1308             kind = LegalityTest(board, flags|F_IGNORE_CHECK, epfile, initialRights,\r
1309                                rf, ff, rt, ft, promoChar);\r
1310             if (kind == IllegalMove) break;\r
1311             kind = IllegalMove;\r
1312         }\r
1313         /* Pawn move */\r
1314         *outp++ = ff + AAA;\r
1315         if (ff == ft && board[rt][ft] == EmptySquare) { /* [HGM] Xiangqi has straight noncapts! */\r
1316             /* Non-capture; use style "e5" */\r
1317             if(rt+ONE <= '9')\r
1318                *outp++ = rt + ONE;\r
1319             else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
1320         } else {\r
1321             /* Capture; use style "exd5" */\r
1322             if(gameInfo.variant != VariantXiangqi || board[rt][ft] != EmptySquare )\r
1323             *outp++ = 'x';  /* [HGM] Xiangqi has sideway noncaptures across river! */\r
1324             *outp++ = ft + AAA;\r
1325             if(rt+ONE <= '9')\r
1326                *outp++ = rt + ONE;\r
1327             else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
1328         }\r
1329         /* Use promotion suffix style "=Q" */\r
1330         *outp = NULLCHAR;\r
1331         if (promoChar != NULLCHAR) {\r
1332             if(gameInfo.variant == VariantShogi) {\r
1333                 /* [HGM] ... but not in Shogi! */\r
1334                 *outp++ = promoChar == '=' ? '=' : '+';\r
1335             } else {\r
1336                 *outp++ = '=';\r
1337                 *outp++ = ToUpper(promoChar);\r
1338             }\r
1339             *outp = NULLCHAR;\r
1340         }\r
1341         AlphaRank(out, 10);\r
1342         return kind;\r
1343 \r
1344         \r
1345       case WhiteKing:\r
1346       case BlackKing:\r
1347         /* Fabien moved code: FRC castling first (if KxR), wild castling second */\r
1348         /* Code added by Tord:  FRC castling. */\r
1349         if((piece == WhiteKing && board[rt][ft] == WhiteRook) ||\r
1350            (piece == BlackKing && board[rt][ft] == BlackRook)) {\r
1351           if(ft > ff) strcpy(out, "O-O"); else strcpy(out, "O-O-O");\r
1352             return LegalityTest(board, flags, epfile, initialRights,\r
1353                                 rf, ff, rt, ft, promoChar);\r
1354         }\r
1355         /* End of code added by Tord */\r
1356         /* Test for castling or ICS wild castling */\r
1357         /* Use style "O-O" (oh-oh) for PGN compatibility */\r
1358         else if (rf == rt &&\r
1359             rf == ((piece == WhiteKing) ? 0 : BOARD_HEIGHT-1) &&\r
1360             ((ff == BOARD_WIDTH>>1 && (ft == BOARD_LEFT+2 || ft == BOARD_RGHT-2)) ||\r
1361              (ff == (BOARD_WIDTH-1)>>1 && (ft == BOARD_LEFT+1 || ft == BOARD_RGHT-3)))) {\r
1362             if(ft==BOARD_LEFT+1 || ft==BOARD_RGHT-2)\r
1363                 strcpy(out, "O-O");\r
1364             else\r
1365                 strcpy(out, "O-O-O");\r
1366 \r
1367             /* This notation is always unambiguous, unless there are\r
1368                kings on both the d and e files, with "wild castling"\r
1369                possible for the king on the d file and normal castling\r
1370                possible for the other.  ICS rules for wild 9\r
1371                effectively make castling illegal for either king in\r
1372                this situation.  So I am not going to worry about it;\r
1373                I'll just generate an ambiguous O-O in this case.\r
1374             */\r
1375             return LegalityTest(board, flags, epfile, initialRights,\r
1376                                 rf, ff, rt, ft, promoChar);\r
1377         }\r
1378 \r
1379         /* else fall through */\r
1380       default:\r
1381         /* Piece move */\r
1382         cl.rf = rf;\r
1383         cl.ff = ff;\r
1384         cl.rt = rt;\r
1385         cl.ft = ft;\r
1386         cl.piece = piece;\r
1387         cl.kind = IllegalMove;\r
1388         cl.rank = cl.file = cl.either = 0;\r
1389         GenLegal(board, flags, epfile, initialRights,\r
1390                  CoordsToAlgebraicCallback, (VOIDSTAR) &cl);\r
1391 \r
1392         if (cl.kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {\r
1393             /* Generate pretty moves for moving into check, but\r
1394                still return IllegalMove.\r
1395             */\r
1396             GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights,\r
1397                      CoordsToAlgebraicCallback, (VOIDSTAR) &cl);\r
1398             if (cl.kind == IllegalMove) break;\r
1399             cl.kind = IllegalMove;\r
1400         }\r
1401 \r
1402         /* Style is "Nf3" or "Nxf7" if this is unambiguous,\r
1403            else "Ngf3" or "Ngxf7",\r
1404            else "N1f3" or "N5xf7",\r
1405            else "Ng1f3" or "Ng5xf7".\r
1406         */\r
1407         if(PieceToChar(piece) == '.') {\r
1408            /* [HGM] print nonexistent piece as its demoted version */\r
1409            piece = (ChessSquare) (DEMOTED piece);\r
1410            if( gameInfo.variant == VariantShogi )\r
1411                 *outp++ = '+';\r
1412         }\r
1413         *outp++ = ToUpper(PieceToChar(piece));\r
1414         if (cl.file || (cl.either && !cl.rank)) {\r
1415             *outp++ = ff + AAA;\r
1416         }\r
1417         if (cl.rank) {\r
1418             if(rf+ONE <= '9')\r
1419                 *outp++ = rf + ONE;\r
1420             else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }\r
1421         }\r
1422 \r
1423         if(board[rt][ft] != EmptySquare)\r
1424           *outp++ = 'x';\r
1425 \r
1426         *outp++ = ft + AAA;\r
1427         if(rt+ONE <= '9')\r
1428            *outp++ = rt + ONE;\r
1429         else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
1430         *outp = NULLCHAR;\r
1431         if (gameInfo.variant == VariantShogi) {\r
1432             /* [HGM] in Shogi non-pawns can promote */\r
1433             if(flags & F_WHITE_ON_MOVE) {\r
1434                 if( (int) cl.piece < (int) WhiteWazir &&\r
1435                      (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) {\r
1436                     if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||\r
1437                          piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */\r
1438                              cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight;\r
1439                     else cl.kind =  WhitePromotionQueen; /* promotion optional */\r
1440                    \r
1441                 } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
1442                                             NormalMove : IllegalMove;\r
1443             } else {\r
1444                 if( (int) cl.piece < (int) BlackWazir && (rf < 3 || rt < 3) ) {\r
1445                     if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||\r
1446                          piece == BlackKnight && rt < 2 ) /* promotion obligatory */\r
1447                              cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight;\r
1448                     else cl.kind =  BlackPromotionQueen; /* promotion optional */\r
1449                 } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
1450                                             NormalMove : IllegalMove;\r
1451             }\r
1452             if(cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {\r
1453                 /* for optional promotions append '+' or '=' */\r
1454                 if(promoChar == '=') {\r
1455                     *outp++ = '=';\r
1456                     cl.kind = NormalMove;\r
1457                 } else *outp++ = '+';\r
1458                 *outp = NULLCHAR;\r
1459             } else if(cl.kind == IllegalMove) {\r
1460                 /* Illegal move specifies any given promotion */\r
1461                 if(promoChar != NULLCHAR && promoChar != 'x') {\r
1462                     *outp++ = '=';\r
1463                     *outp++ = ToUpper(promoChar);\r
1464                     *outp = NULLCHAR;\r
1465                 }\r
1466             }\r
1467         }\r
1468         AlphaRank(out, 10);\r
1469         return cl.kind;\r
1470         \r
1471       /* [HGM] Always long notation for fairies we don't know */\r
1472       case WhiteNightrider:\r
1473       case BlackNightrider:\r
1474       case WhiteGrasshopper:\r
1475       case BlackGrasshopper:\r
1476       case EmptySquare:\r
1477         /* Moving a nonexistent piece */\r
1478         break;\r
1479     }\r
1480     \r
1481     /* Not a legal move, even ignoring check.\r
1482        If there was a piece on the from square, \r
1483        use style "Ng1g3" or "Ng1xe8";\r
1484        if there was a pawn or nothing (!),\r
1485        use style "g1g3" or "g1xe8".  Use "x"\r
1486        if a piece was on the to square, even\r
1487        a piece of the same color.\r
1488     */\r
1489     outp = out;\r
1490     if (piece != EmptySquare && piece != WhitePawn && piece != BlackPawn) {\r
1491         *outp++ = ToUpper(PieceToChar(piece));\r
1492     }\r
1493     *outp++ = ff + AAA;\r
1494     if(rf+ONE <= '9')\r
1495        *outp++ = rf + ONE;\r
1496     else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }\r
1497     if (board[rt][ft] != EmptySquare) *outp++ = 'x';\r
1498     *outp++ = ft + AAA;\r
1499     if(rt+ONE <= '9')\r
1500        *outp++ = rt + ONE;\r
1501     else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
1502     /* Use promotion suffix style "=Q" */\r
1503     if (promoChar != NULLCHAR && promoChar != 'x') {\r
1504         *outp++ = '=';\r
1505         *outp++ = ToUpper(promoChar);\r
1506     }\r
1507     *outp = NULLCHAR;\r
1508 \r
1509     AlphaRank(out, 0);\r
1510     return IllegalMove;\r
1511 }\r
1512 \r
1513 \r