changes from H.G. Muller; version 4.3.2
[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 WhiteFairyRook;\r
123       case BlackPromotionChancellor:\r
124         return BlackFairyRook;\r
125       case WhitePromotionArchbishop:\r
126         return WhiteFairyBishop;\r
127       case BlackPromotionArchbishop:\r
128         return BlackFairyBishop;\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', \r
200 #ifdef FAIRY\r
201     'A', 'C', 'F', 'H', 'E', 'W', 'D', 'O', 'G', 'M',\r
202 #endif\r
203     'Q', 'K', 'p', 'n', 'b', 'r', \r
204 #ifdef FAIRY            \r
205     'a', 'c', 'f', 'h', 'e', 'w', 'd', 'o', 'g', 'm',\r
206 #endif\r
207     'q', 'k', 'x'\r
208   };\r
209 \r
210 char PieceToChar(p)\r
211      ChessSquare p;\r
212 {\r
213     return pieceToChar[(int) p];\r
214 }\r
215 \r
216 ChessSquare CharToPiece(c)\r
217      int c;\r
218 {    switch (c) {\r
219       default:\r
220       case 'x': return EmptySquare;\r
221       case 'P': return WhitePawn;\r
222       case 'R': return WhiteRook;\r
223       case 'N': return WhiteKnight;\r
224       case 'B': return WhiteBishop;\r
225       case 'Q': return WhiteQueen;\r
226       case 'K': return WhiteKing;\r
227       case 'p': return BlackPawn;\r
228       case 'r': return BlackRook;\r
229       case 'n': return BlackKnight;\r
230       case 'b': return BlackBishop;\r
231       case 'q': return BlackQueen;\r
232       case 'k': return BlackKing;\r
233 #ifdef FAIRY\r
234       case 'A': return WhiteCardinal;\r
235       case 'C': return WhiteMarshall;\r
236       case 'F': return WhiteFairyPawn;\r
237       case 'H': return WhiteFairyKnight;\r
238       case 'E': return WhiteFairyBishop;\r
239       case 'W': return WhiteFairyRook;\r
240       case 'D': return WhiteFairyCardinal;\r
241       case 'O': return WhiteFairyMarshall;\r
242       case 'G': return WhiteFairyQueen;\r
243       case 'M': return WhiteFairyKing;\r
244                 \r
245       case 'a': return BlackCardinal;\r
246       case 'c': return BlackMarshall;\r
247       case 'f': return BlackFairyPawn;\r
248       case 'h': return BlackFairyKnight;\r
249       case 'e': return BlackFairyBishop;\r
250       case 'w': return BlackFairyRook;\r
251       case 'd': return BlackFairyCardinal;\r
252       case 'o': return BlackFairyMarshall;\r
253       case 'g': return BlackFairyQueen;\r
254       case 'm': return BlackFairyKing;\r
255                 \r
256 #endif\r
257     }\r
258 }\r
259 \r
260 void CopyBoard(to, from)\r
261      Board to, from;\r
262 {\r
263     int i, j;\r
264     \r
265     for (i = 0; i < BOARD_HEIGHT; i++)\r
266       for (j = 0; j < BOARD_WIDTH; j++)\r
267         to[i][j] = from[i][j];\r
268 }\r
269 \r
270 int CompareBoards(board1, board2)\r
271      Board board1, board2;\r
272 {\r
273     int i, j;\r
274     \r
275     for (i = 0; i < BOARD_HEIGHT; i++)\r
276       for (j = 0; j < BOARD_WIDTH; j++) {\r
277           if (board1[i][j] != board2[i][j])\r
278             return FALSE;\r
279     }\r
280     return TRUE;\r
281 }\r
282 \r
283 \r
284 /* Call callback once for each pseudo-legal move in the given\r
285    position, except castling moves. A move is pseudo-legal if it is\r
286    legal, or if it would be legal except that it leaves the king in\r
287    check.  In the arguments, epfile is EP_NONE if the previous move\r
288    was not a double pawn push, or the file 0..7 if it was, or\r
289    EP_UNKNOWN if we don't know and want to allow all e.p. captures.\r
290    Promotion moves generated are to Queen only.\r
291 */\r
292 void GenPseudoLegal(board, flags, epfile, callback, closure)\r
293      Board board;\r
294      int flags;\r
295      int epfile;\r
296      MoveCallback callback;\r
297      VOIDSTAR closure;\r
298 {\r
299     int rf, ff;\r
300     int i, j, d, s, fs, rs, rt, ft, m;\r
301 \r
302     for (rf = 0; rf < BOARD_HEIGHT; rf++) \r
303       for (ff = 0; ff < BOARD_WIDTH; ff++) {\r
304           if (flags & F_WHITE_ON_MOVE) {\r
305               if (!WhitePiece(board[rf][ff])) continue;\r
306           } else {\r
307               if (!BlackPiece(board[rf][ff])) continue;\r
308           }\r
309           m = 0;\r
310           switch (board[rf][ff]) {\r
311             case EmptySquare:\r
312             default:\r
313               /* can't happen ([HGM] except for faries...) */\r
314               break;\r
315 \r
316             case WhitePawn:\r
317 #ifdef FAIRY\r
318               if(gameInfo.variant == VariantXiangqi) {\r
319                   /* [HGM] capture and move straight ahead in Xiangqi */\r
320                   if (rf < BOARD_HEIGHT-1 &&\r
321                            !SameColor(board[rf][ff], board[rf + 1][ff]) ) {\r
322                            callback(board, flags, NormalMove,\r
323                                     rf, ff, rf + 1, ff, closure);\r
324                   }\r
325                   /* and move sideways when across the river */\r
326                   for (s = -1; s <= 1; s += 2) {\r
327                       if (rf >= BOARD_HEIGHT>>1 &&\r
328                           ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
329                           !WhitePiece(board[rf][ff+s]) ) {\r
330                            callback(board, flags, NormalMove,\r
331                                     rf, ff, rf, ff+s, closure);\r
332                       }\r
333                   }\r
334                   break;\r
335               }\r
336 #endif\r
337               if (rf < BOARD_HEIGHT-1 && board[rf + 1][ff] == EmptySquare) {\r
338                   callback(board, flags,\r
339                            rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,\r
340                            rf, ff, rf + 1, ff, closure);\r
341               }\r
342               if (rf == 1 && board[2][ff] == EmptySquare &&\r
343                   gameInfo.variant != VariantShatranj && /* [HGM] */\r
344                   board[3][ff] == EmptySquare ) {\r
345                       callback(board, flags, NormalMove,\r
346                                rf, ff, 3, ff, closure);\r
347               }\r
348               for (s = -1; s <= 1; s += 2) {\r
349                   if (rf < BOARD_HEIGHT-1 && ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
350                       ((flags & F_KRIEGSPIEL_CAPTURE) ||\r
351                        BlackPiece(board[rf + 1][ff + s]))) {\r
352                       callback(board, flags, \r
353                                rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,\r
354                                rf, ff, rf + 1, ff + s, closure);\r
355                   }\r
356                   if (rf == BOARD_HEIGHT-4) {\r
357                       if (ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
358                           (epfile == ff + s || epfile == EP_UNKNOWN) &&\r
359                           board[BOARD_HEIGHT-4][ff + s] == BlackPawn &&\r
360                           board[BOARD_HEIGHT-3][ff + s] == EmptySquare) {\r
361                           callback(board, flags, WhiteCapturesEnPassant,\r
362                                    rf, ff, 5, ff + s, closure);\r
363                       }\r
364                   }\r
365               }             \r
366               break;\r
367 \r
368             case BlackPawn:\r
369 #ifdef FAIRY\r
370               if(gameInfo.variant == VariantXiangqi) {\r
371                   /* [HGM] capture straight ahead in Xiangqi */\r
372                   if (rf > 0 && !SameColor(board[rf][ff], board[rf - 1][ff]) ) {\r
373                            callback(board, flags, NormalMove,\r
374                                     rf, ff, rf - 1, ff, closure);\r
375                   }\r
376                   /* and move sideways when across the river */\r
377                   for (s = -1; s <= 1; s += 2) {\r
378                       if (rf < BOARD_HEIGHT>>1 &&\r
379                           ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
380                           !BlackPiece(board[rf][ff+s]) ) {\r
381                            callback(board, flags, NormalMove,\r
382                                     rf, ff, rf, ff+s, closure);\r
383                       }\r
384                   }\r
385                   break;\r
386               }\r
387 #endif\r
388               if (rf > 0 && board[rf - 1][ff] == EmptySquare) {\r
389                   callback(board, flags, \r
390                            rf == 1 ? BlackPromotionQueen : NormalMove,\r
391                            rf, ff, rf - 1, ff, closure);\r
392               }\r
393               if (rf == BOARD_HEIGHT-2 && board[BOARD_HEIGHT-3][ff] == EmptySquare &&\r
394                   gameInfo.variant != VariantShatranj && /* [HGM] */\r
395                   board[BOARD_HEIGHT-4][ff] == EmptySquare) {\r
396                   callback(board, flags, NormalMove,\r
397                            rf, ff, BOARD_HEIGHT-4, ff, closure);\r
398               }\r
399               for (s = -1; s <= 1; s += 2) {\r
400                   if (rf > 0 && ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
401                       ((flags & F_KRIEGSPIEL_CAPTURE) ||\r
402                        WhitePiece(board[rf - 1][ff + s]))) {\r
403                       callback(board, flags, \r
404                                rf == 1 ? BlackPromotionQueen : NormalMove,\r
405                                rf, ff, rf - 1, ff + s, closure);\r
406                   }\r
407                   if (rf == 3) {\r
408                       if (ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
409                           (epfile == ff + s || epfile == EP_UNKNOWN) &&\r
410                           board[3][ff + s] == WhitePawn &&\r
411                           board[2][ff + s] == EmptySquare) {\r
412                           callback(board, flags, BlackCapturesEnPassant,\r
413                                    rf, ff, 2, ff + s, closure);\r
414                       }\r
415                   }\r
416               }             \r
417               break;\r
418 \r
419             case WhiteKnight:\r
420             case BlackKnight:\r
421             mounted:\r
422               for (i = -1; i <= 1; i += 2)\r
423                 for (j = -1; j <= 1; j += 2)\r
424                   for (s = 1; s <= 2; s++) {\r
425                       rt = rf + i*s;\r
426                       ft = ff + j*(3-s);\r
427                       if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) continue;\r
428                       if (SameColor(board[rf][ff], board[rt][ft])) continue;\r
429                       callback(board, flags, NormalMove,\r
430                                rf, ff, rt, ft, closure);\r
431                   }\r
432               break;\r
433 #ifdef FAIRY\r
434             case WhiteFairyMarshall:\r
435             case BlackFairyMarshall:\r
436               for (d = 0; d <= 1; d++)\r
437                 for (s = -1; s <= 1; s += 2) {\r
438                   m = 0;\r
439                   for (i = 1;; i++) {\r
440                       rt = rf + (i * s) * d;\r
441                       ft = ff + (i * s) * (1 - d);\r
442                       if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
443                       if (m == 0 && board[rt][ft] == EmptySquare)\r
444                                  callback(board, flags, NormalMove,\r
445                                           rf, ff, rt, ft, closure);\r
446                       if (m == 1 && board[rt][ft] != EmptySquare &&\r
447                           !SameColor(board[rf][ff], board[rt][ft]) )\r
448                                  callback(board, flags, NormalMove,\r
449                                           rf, ff, rt, ft, closure);\r
450                       if (board[rt][ft] != EmptySquare && m++) break;\r
451                   }\r
452                 }\r
453               break;\r
454 \r
455             case WhiteFairyRook:\r
456             case BlackFairyRook:\r
457               for (d = 0; d <= 1; d++)\r
458                 for (s = -1; s <= 1; s += 2)\r
459                       rt = rf + s * d;\r
460                       ft = ff + s * (1 - d);\r
461                       if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH)\r
462                           && !SameColor(board[rf][ff], board[rt][ft]))\r
463                                callback(board, flags, NormalMove,\r
464                                         rf, ff, rt, ft, closure);\r
465               break;\r
466 \r
467             case WhiteFairyBishop:\r
468             case BlackFairyBishop:\r
469                 /* [HGM] support Shatranj pieces */\r
470                 for (rs = -1; rs <= 1; rs += 2) \r
471                   for (fs = -1; fs <= 1; fs += 2) {\r
472                       rt = rf + 2 * rs;\r
473                       ft = ff + 2 * fs;\r
474                       if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH)\r
475                           && !SameColor(board[rf][ff], board[rt][ft]))\r
476                                callback(board, flags, NormalMove,\r
477                                         rf, ff, rt, ft, closure);\r
478                   }\r
479                 break;\r
480 \r
481             case WhiteCardinal:\r
482             case BlackCardinal:\r
483               m++;\r
484 #endif\r
485             case WhiteBishop:\r
486             case BlackBishop:\r
487               for (rs = -1; rs <= 1; rs += 2) \r
488                 for (fs = -1; fs <= 1; fs += 2) \r
489                   for (i = 1;; i++) {\r
490                       rt = rf + (i * rs);\r
491                       ft = ff + (i * fs);\r
492                       if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
493                       if (SameColor(board[rf][ff], board[rt][ft])) break;\r
494                       callback(board, flags, NormalMove,\r
495                                rf, ff, rt, ft, closure);\r
496                       if (board[rt][ft] != EmptySquare) break;\r
497                   }\r
498                 if(m) goto mounted;\r
499               break;\r
500 \r
501 #ifdef FAIRY\r
502             case WhiteMarshall:\r
503             case BlackMarshall:\r
504               m++;\r
505 #endif\r
506             case WhiteRook:\r
507             case BlackRook:\r
508               for (d = 0; d <= 1; d++)\r
509                 for (s = -1; s <= 1; s += 2)\r
510                   for (i = 1;; i++) {\r
511                       rt = rf + (i * s) * d;\r
512                       ft = ff + (i * s) * (1 - d);\r
513                       if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
514                       if (SameColor(board[rf][ff], board[rt][ft])) break;\r
515                       callback(board, flags, NormalMove,\r
516                                rf, ff, rt, ft, closure);\r
517                       if (board[rt][ft] != EmptySquare) break;\r
518                   }\r
519                 if(m) goto mounted;\r
520               break;\r
521 \r
522             case WhiteQueen:\r
523             case BlackQueen:\r
524               for (rs = -1; rs <= 1; rs++) \r
525                 for (fs = -1; fs <= 1; fs++) {\r
526                     if (rs == 0 && fs == 0) continue;\r
527                     for (i = 1;; i++) {\r
528                         rt = rf + (i * rs);\r
529                         ft = ff + (i * fs);\r
530                         if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
531                         if (SameColor(board[rf][ff], board[rt][ft])) break;\r
532                         callback(board, flags, NormalMove,\r
533                                  rf, ff, rt, ft, closure);\r
534                         if (board[rt][ft] != EmptySquare) break;\r
535                     }\r
536                 }\r
537               break;\r
538 \r
539 #ifdef FAIRY\r
540             case WhiteFairyPawn:\r
541             case BlackFairyPawn:\r
542                 /* [HGM] support Shatranj pieces */\r
543                 for (rs = -1; rs <= 1; rs += 2) \r
544                   for (fs = -1; fs <= 1; fs += 2) {\r
545                       rt = rf + rs;\r
546                       ft = ff + fs;\r
547                       if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
548                       if (!SameColor(board[rf][ff], board[rt][ft]))\r
549                                callback(board, flags, NormalMove,\r
550                                         rf, ff, rt, ft, closure);\r
551                   }\r
552                 break;\r
553 \r
554             case WhiteFairyKing:\r
555             case BlackFairyKing:\r
556 #endif\r
557             case WhiteKing:\r
558             case BlackKing:\r
559               for (i = -1; i <= 1; i++)\r
560                 for (j = -1; j <= 1; j++) {\r
561                     if (i == 0 && j == 0) continue;\r
562                     rt = rf + i;\r
563                     ft = ff + j;\r
564                     if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) continue;\r
565                     if (SameColor(board[rf][ff], board[rt][ft])) continue;\r
566                     callback(board, flags, NormalMove,\r
567                              rf, ff, rt, ft, closure);\r
568                 }\r
569               break;\r
570           }\r
571       }\r
572 }\r
573 \r
574 \r
575 typedef struct {\r
576     MoveCallback cb;\r
577     VOIDSTAR cl;\r
578 } GenLegalClosure;\r
579 \r
580 extern void GenLegalCallback P((Board board, int flags, ChessMove kind,\r
581                                 int rf, int ff, int rt, int ft,\r
582                                 VOIDSTAR closure));\r
583 \r
584 void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
585      Board board;\r
586      int flags;\r
587      ChessMove kind;\r
588      int rf, ff, rt, ft;\r
589      VOIDSTAR closure;\r
590 {\r
591     register GenLegalClosure *cl = (GenLegalClosure *) closure;\r
592 \r
593     if (!(flags & F_IGNORE_CHECK) &&\r
594         CheckTest(board, flags, rf, ff, rt, ft,\r
595                   kind == WhiteCapturesEnPassant ||\r
596                   kind == BlackCapturesEnPassant)) return;\r
597     if (flags & F_ATOMIC_CAPTURE) {\r
598       if (board[rt][ft] != EmptySquare ||\r
599           kind == WhiteCapturesEnPassant || kind == BlackCapturesEnPassant) {\r
600         int r, f;\r
601         ChessSquare king = (flags & F_WHITE_ON_MOVE) ? WhiteKing : BlackKing;\r
602         if (board[rf][ff] == king) return;\r
603         for (r = rt-1; r <= rt+1; r++) {\r
604           for (f = ft-1; f <= ft+1; f++) {\r
605             if (r >= 0 && r < BOARD_HEIGHT && f >= 0 && f < BOARD_WIDTH &&\r
606                 board[r][f] == king) return;\r
607           }\r
608         }\r
609       }\r
610     }\r
611     cl->cb(board, flags, kind, rf, ff, rt, ft, cl->cl);\r
612 }\r
613 \r
614 \r
615 typedef struct {\r
616     int rf, ff, rt, ft;\r
617     ChessMove kind;\r
618 } LegalityTestClosure;\r
619 \r
620 \r
621 /* Like GenPseudoLegal, but (1) include castling moves, (2) unless\r
622    F_IGNORE_CHECK is set in the flags, omit moves that would leave the\r
623    king in check, and (3) if F_ATOMIC_CAPTURE is set in the flags, omit\r
624    moves that would destroy your own king.  The CASTLE_OK flags are\r
625    true if castling is not yet ruled out by a move of the king or\r
626    rook.  Return TRUE if the player on move is currently in check and\r
627    F_IGNORE_CHECK is not set.  [HGM] add castlingRights parameter */\r
628 int GenLegal(board, flags, epfile, castlingRights, callback, closure)\r
629      Board board;\r
630      int flags;\r
631      int epfile;\r
632      char castlingRights[];\r
633      MoveCallback callback;\r
634      VOIDSTAR closure;\r
635 {\r
636     GenLegalClosure cl;\r
637     int ff, ft;\r
638     int ignoreCheck = (flags & F_IGNORE_CHECK) != 0;\r
639 \r
640     cl.cb = callback;\r
641     cl.cl = closure;\r
642     GenPseudoLegal(board, flags, epfile, GenLegalCallback, (VOIDSTAR) &cl);\r
643 \r
644     if (!ignoreCheck &&\r
645         CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE;\r
646 \r
647     /* Generate castling moves */\r
648     for (ff = BOARD_WIDTH>>1; ff >= (BOARD_WIDTH-1)>>1; ff-- /*ics wild 1*/) {\r
649         if ((flags & F_WHITE_ON_MOVE) &&\r
650             (flags & F_WHITE_KCASTLE_OK) &&\r
651             board[0][ff] == WhiteKing &&\r
652             board[0][ff + 1] == EmptySquare &&\r
653             board[0][ff + 2] == EmptySquare &&\r
654             board[0][BOARD_WIDTH-3] == EmptySquare &&\r
655             board[0][BOARD_WIDTH-2] == EmptySquare &&\r
656             board[0][BOARD_WIDTH-1] == WhiteRook &&\r
657             castlingRights[0] >= 0 && /* [HGM] check rights */\r
658             ( castlingRights[2] == ff || castlingRights[6] == ff ) &&\r
659             (ignoreCheck ||                             \r
660              (!CheckTest(board, flags, 0, ff, 0, ff + 1, FALSE) &&\r
661               !CheckTest(board, flags, 0, ff, 0, BOARD_WIDTH-3, FALSE) &&\r
662               !CheckTest(board, flags, 0, ff, 0, ff + 2, FALSE)))) {\r
663 \r
664             callback(board, flags,\r
665                      ff==4 ? WhiteKingSideCastle : WhiteKingSideCastleWild,\r
666                      0, ff, 0, ff + ((BOARD_WIDTH+2)>>2), closure);\r
667         }\r
668         if ((flags & F_WHITE_ON_MOVE) &&\r
669             (flags & F_WHITE_QCASTLE_OK) &&\r
670             board[0][ff] == WhiteKing &&\r
671             board[0][ff - 1] == EmptySquare &&\r
672             board[0][ff - 2] == EmptySquare &&\r
673             board[0][2] == EmptySquare &&\r
674             board[0][1] == EmptySquare &&\r
675             board[0][0] == WhiteRook &&\r
676             castlingRights[1] >= 0 && /* [HGM] check rights */\r
677             ( castlingRights[2] == ff || castlingRights[6] == ff ) &&\r
678             (ignoreCheck ||\r
679              (!CheckTest(board, flags, 0, ff, 0, ff - 1, FALSE) &&\r
680               !CheckTest(board, flags, 0, ff, 0, 3,      FALSE) &&\r
681               !CheckTest(board, flags, 0, ff, 0, ff - 2, FALSE)))) {\r
682 \r
683             callback(board, flags,\r
684                      ff==BOARD_WIDTH>>1 ? WhiteQueenSideCastle : WhiteQueenSideCastleWild,\r
685                      0, ff, 0, ff - ((BOARD_WIDTH+2)>>2), closure);\r
686         }\r
687         if (!(flags & F_WHITE_ON_MOVE) &&\r
688             (flags & F_BLACK_KCASTLE_OK) &&\r
689             board[BOARD_HEIGHT-1][ff] == BlackKing &&\r
690             board[BOARD_HEIGHT-1][ff + 1] == EmptySquare &&\r
691             board[BOARD_HEIGHT-1][ff + 2] == EmptySquare &&\r
692             board[BOARD_HEIGHT-1][BOARD_WIDTH-3] == EmptySquare &&\r
693             board[BOARD_HEIGHT-1][BOARD_WIDTH-2] == EmptySquare &&\r
694             board[BOARD_HEIGHT-1][BOARD_WIDTH-1] == BlackRook &&\r
695             castlingRights[3] >= 0 && /* [HGM] check rights */\r
696             ( castlingRights[5] == ff || castlingRights[7] == ff ) &&\r
697             (ignoreCheck ||\r
698              (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 1, FALSE) &&\r
699               !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_WIDTH-3, FALSE) &&\r
700               !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 2, FALSE)))) {\r
701 \r
702             callback(board, flags,\r
703                      ff==BOARD_WIDTH>>1 ? BlackKingSideCastle : BlackKingSideCastleWild,\r
704                      BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + ((BOARD_WIDTH+2)>>2), closure);\r
705         }\r
706         if (!(flags & F_WHITE_ON_MOVE) &&\r
707             (flags & F_BLACK_QCASTLE_OK) &&\r
708             board[BOARD_HEIGHT-1][ff] == BlackKing &&\r
709             board[BOARD_HEIGHT-1][ff - 1] == EmptySquare &&\r
710             board[BOARD_HEIGHT-1][ff - 2] == EmptySquare &&\r
711             board[BOARD_HEIGHT-1][2] == EmptySquare &&\r
712             board[BOARD_HEIGHT-1][1] == EmptySquare &&\r
713             board[BOARD_HEIGHT-1][0] == BlackRook &&\r
714             castlingRights[4] >= 0 && /* [HGM] check rights */\r
715             ( castlingRights[5] == ff || castlingRights[7] == ff ) &&\r
716             (ignoreCheck ||\r
717              (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE) &&\r
718               !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, 3,      FALSE) &&\r
719               !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE)))) {\r
720 \r
721             callback(board, flags,\r
722                      ff==BOARD_WIDTH>>1 ? BlackQueenSideCastle : BlackQueenSideCastleWild,\r
723                      BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - ((BOARD_WIDTH+2)>>2), closure);\r
724         }\r
725     }\r
726 \r
727     /* PUSH Fabien */\r
728 \r
729     /* generate all potential FRC castling moves (KxR), ignoring flags */\r
730     /* [HGM] Tord! Help requested! */\r
731 \r
732     if ((flags & F_WHITE_ON_MOVE) != 0) {\r
733 \r
734        for (ff = 1; ff < BOARD_WIDTH-1; ff++) {\r
735           if (board[0][ff] == WhiteKing) {\r
736              for (ft = 0; ft < BOARD_WIDTH; ft++) {\r
737                 if (board[0][ft] == WhiteRook) {\r
738                    callback(board, flags, \r
739                             (ft > ff) ? WhiteHSideCastleFR : WhiteASideCastleFR,\r
740                             0, ff, 0, ft, closure);\r
741                 }\r
742              }\r
743           }\r
744        }\r
745 \r
746     } else {\r
747 \r
748        for (ff = 1; ff < BOARD_WIDTH-1; ff++) {\r
749           if (board[BOARD_HEIGHT-1][ff] == BlackKing) {\r
750              for (ft = 0; ft < BOARD_WIDTH; ft++) {\r
751                 if (board[BOARD_HEIGHT-1][ft] == BlackRook) {\r
752                    callback(board, flags, \r
753                             (ft > ff) ? BlackHSideCastleFR : BlackASideCastleFR,\r
754                             BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);\r
755                 }\r
756              }\r
757           }\r
758        }\r
759     }\r
760 \r
761     /* POP Fabien */\r
762 \r
763     return FALSE;\r
764 }\r
765 \r
766 \r
767 typedef struct {\r
768     int rking, fking;\r
769     int check;\r
770 } CheckTestClosure;\r
771 \r
772 \r
773 extern void CheckTestCallback P((Board board, int flags, ChessMove kind,\r
774                                  int rf, int ff, int rt, int ft,\r
775                                  VOIDSTAR closure));\r
776 \r
777 \r
778 void CheckTestCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
779      Board board;\r
780      int flags;\r
781      ChessMove kind;\r
782      int rf, ff, rt, ft;\r
783      VOIDSTAR closure;\r
784 {\r
785     register CheckTestClosure *cl = (CheckTestClosure *) closure;\r
786 \r
787     if (rt == cl->rking && ft == cl->fking) cl->check++;\r
788 }\r
789 \r
790 \r
791 /* If the player on move were to move from (rf, ff) to (rt, ft), would\r
792    he leave himself in check?  Or if rf == -1, is the player on move\r
793    in check now?  enPassant must be TRUE if the indicated move is an\r
794    e.p. capture.  The possibility of castling out of a check along the\r
795    back rank is not accounted for (i.e., we still return nonzero), as\r
796    this is illegal anyway.  Return value is the number of times the\r
797    king is in check. */ \r
798 int CheckTest(board, flags, rf, ff, rt, ft, enPassant)\r
799      Board board;\r
800      int flags;\r
801      int rf, ff, rt, ft, enPassant;\r
802 {\r
803     CheckTestClosure cl;\r
804     ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing;\r
805     ChessSquare captured = EmptySquare;\r
806     /*  Suppress warnings on uninitialized variables    */\r
807 \r
808     if (rf >= 0) {\r
809         if (enPassant) {\r
810             captured = board[rf][ft];\r
811             board[rf][ft] = EmptySquare;\r
812         } else {\r
813             captured = board[rt][ft];\r
814         }\r
815         board[rt][ft] = board[rf][ff];\r
816         board[rf][ff] = EmptySquare;\r
817     }\r
818 \r
819     /* For compatibility with ICS wild 9, we scan the board in the\r
820        order a1, a2, a3, ... b1, b2, ..., h8 to find the first king,\r
821        and we test only whether that one is in check. */\r
822     cl.check = 0;\r
823     for (cl.fking = 0; cl.fking < BOARD_WIDTH; cl.fking++)\r
824         for (cl.rking = 0; cl.rking < BOARD_HEIGHT; cl.rking++) {\r
825           if (board[cl.rking][cl.fking] == king) {\r
826               GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, -1,\r
827                              CheckTestCallback, (VOIDSTAR) &cl);\r
828               goto undo_move;  /* 2-level break */\r
829           }\r
830       }\r
831 \r
832   undo_move:\r
833 \r
834     if (rf >= 0) {\r
835         board[rf][ff] = board[rt][ft];\r
836         if (enPassant) {\r
837             board[rf][ft] = captured;\r
838             board[rt][ft] = EmptySquare;\r
839         } else {\r
840             board[rt][ft] = captured;\r
841         }\r
842     }\r
843 \r
844     return cl.check;\r
845 }\r
846 \r
847 \r
848 extern void LegalityTestCallback P((Board board, int flags, ChessMove kind,\r
849                                     int rf, int ff, int rt, int ft,\r
850                                     VOIDSTAR closure));\r
851 \r
852 void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
853      Board board;\r
854      int flags;\r
855      ChessMove kind;\r
856      int rf, ff, rt, ft;\r
857      VOIDSTAR closure;\r
858 {\r
859     register LegalityTestClosure *cl = (LegalityTestClosure *) closure;\r
860 \r
861     if (rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft)\r
862       cl->kind = kind;\r
863 }\r
864 \r
865 ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, promoChar)\r
866      Board board;\r
867      int flags, epfile;\r
868      int rf, ff, rt, ft, promoChar;\r
869      char castlingRights[];\r
870 {\r
871     LegalityTestClosure cl;\r
872     \r
873     cl.rf = rf;\r
874     cl.ff = ff;\r
875     cl.rt = rt;\r
876     cl.ft = ft;\r
877     cl.kind = IllegalMove;\r
878     GenLegal(board, flags, epfile, castlingRights, LegalityTestCallback, (VOIDSTAR) &cl);\r
879     if (promoChar != NULLCHAR && promoChar != 'x') {\r
880         if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {\r
881             cl.kind = \r
882               PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0, promoChar);\r
883         } else {\r
884             cl.kind = IllegalMove;\r
885         }\r
886     }\r
887     return cl.kind;\r
888 }\r
889 \r
890 typedef struct {\r
891     int count;\r
892 } MateTestClosure;\r
893 \r
894 extern void MateTestCallback P((Board board, int flags, ChessMove kind,\r
895                                 int rf, int ff, int rt, int ft,\r
896                                 VOIDSTAR closure));\r
897 \r
898 void MateTestCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
899      Board board;\r
900      int flags;\r
901      ChessMove kind;\r
902      int rf, ff, rt, ft;\r
903      VOIDSTAR closure;\r
904 {\r
905     register MateTestClosure *cl = (MateTestClosure *) closure;\r
906 \r
907     cl->count++;\r
908 }\r
909 \r
910 /* Return MT_NONE, MT_CHECK, MT_CHECKMATE, or MT_STALEMATE */\r
911 int MateTest(board, flags, epfile, castlingRights)\r
912      Board board;\r
913      int flags, epfile;\r
914      char castlingRights[];\r
915 {\r
916     MateTestClosure cl;\r
917     int inCheck;\r
918 \r
919     cl.count = 0;\r
920     inCheck = GenLegal(board, flags, epfile, castlingRights, MateTestCallback, (VOIDSTAR) &cl);\r
921     if (cl.count > 0) {\r
922         return inCheck ? MT_CHECK : MT_NONE;\r
923     } else {\r
924         return inCheck ? MT_CHECKMATE : MT_STALEMATE;\r
925     }\r
926 }\r
927 \r
928      \r
929 extern void DisambiguateCallback P((Board board, int flags, ChessMove kind,\r
930                                     int rf, int ff, int rt, int ft,\r
931                                     VOIDSTAR closure));\r
932 \r
933 void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
934      Board board;\r
935      int flags;\r
936      ChessMove kind;\r
937      int rf, ff, rt, ft;\r
938      VOIDSTAR closure;\r
939 {\r
940     register DisambiguateClosure *cl = (DisambiguateClosure *) closure;\r
941 \r
942     if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]) &&\r
943         (cl->rfIn == -1 || cl->rfIn == rf) &&\r
944         (cl->ffIn == -1 || cl->ffIn == ff) &&\r
945         (cl->rtIn == -1 || cl->rtIn == rt) &&\r
946         (cl->ftIn == -1 || cl->ftIn == ft)) {\r
947 \r
948         cl->count++;\r
949         cl->piece = board[rf][ff];\r
950         cl->rf = rf;\r
951         cl->ff = ff;\r
952         cl->rt = rt;\r
953         cl->ft = ft;\r
954         cl->kind = kind;\r
955     }\r
956 }\r
957 \r
958 void Disambiguate(board, flags, epfile, closure)\r
959      Board board;\r
960      int flags, epfile;\r
961      DisambiguateClosure *closure;\r
962 {\r
963     int illegal = 0;\r
964     closure->count = 0;\r
965     closure->rf = closure->ff = closure->rt = closure->ft = 0;\r
966     closure->kind = ImpossibleMove;\r
967     GenLegal(board, flags, epfile, initialRights, DisambiguateCallback, (VOIDSTAR) closure);\r
968     if (closure->count == 0) {\r
969         /* See if it's an illegal move due to check */\r
970         illegal = 1;\r
971         GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights, DisambiguateCallback,\r
972                  (VOIDSTAR) closure);   \r
973         if (closure->count == 0) {\r
974             /* No, it's not even that */\r
975             return;\r
976         }\r
977     }\r
978     if (closure->promoCharIn != NULLCHAR && closure->promoCharIn != 'x') {\r
979         if (closure->kind == WhitePromotionQueen\r
980             || closure->kind == BlackPromotionQueen) {\r
981             closure->kind = \r
982               PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0,\r
983                                   closure->promoCharIn);\r
984         } else {\r
985             closure->kind = IllegalMove;\r
986         }\r
987     }\r
988     closure->promoChar = ToLower(PieceToChar(PromoPiece(closure->kind)));\r
989     if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;\r
990     if (closure->count > 1) {\r
991         closure->kind = AmbiguousMove;\r
992     }\r
993     if (illegal) {\r
994         /* Note: If more than one illegal move matches, but no legal\r
995            moves, we return IllegalMove, not AmbiguousMove.  Caller\r
996            can look at closure->count to detect this.\r
997         */\r
998         closure->kind = IllegalMove;\r
999     }\r
1000 }\r
1001 \r
1002 \r
1003 typedef struct {\r
1004     /* Input */\r
1005     ChessSquare piece;\r
1006     int rf, ff, rt, ft;\r
1007     /* Output */\r
1008     ChessMove kind;\r
1009     int rank;\r
1010     int file;\r
1011     int either;\r
1012 } CoordsToAlgebraicClosure;\r
1013 \r
1014 extern void CoordsToAlgebraicCallback P((Board board, int flags,\r
1015                                          ChessMove kind, int rf, int ff,\r
1016                                          int rt, int ft, VOIDSTAR closure));\r
1017 \r
1018 void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
1019      Board board;\r
1020      int flags;\r
1021      ChessMove kind;\r
1022      int rf, ff, rt, ft;\r
1023      VOIDSTAR closure;\r
1024 {\r
1025     register CoordsToAlgebraicClosure *cl =\r
1026       (CoordsToAlgebraicClosure *) closure;\r
1027 \r
1028     if (rt == cl->rt && ft == cl->ft &&\r
1029         board[rf][ff] == cl->piece) {\r
1030         if (rf == cl->rf) {\r
1031             if (ff == cl->ff) {\r
1032                 cl->kind = kind; /* this is the move we want */\r
1033             } else {\r
1034                 cl->file++; /* need file to rule out this move */\r
1035             }\r
1036         } else {\r
1037             if (ff == cl->ff) {\r
1038                 cl->rank++; /* need rank to rule out this move */\r
1039             } else {\r
1040                 cl->either++; /* rank or file will rule out this move */\r
1041             }\r
1042         }           \r
1043     }\r
1044 }\r
1045 \r
1046 /* Convert coordinates to normal algebraic notation.\r
1047    promoChar must be NULLCHAR or 'x' if not a promotion.\r
1048 */\r
1049 ChessMove CoordsToAlgebraic(board, flags, epfile,\r
1050                             rf, ff, rt, ft, promoChar, out)\r
1051      Board board;\r
1052      int flags, epfile;\r
1053      int rf, ff, rt, ft;\r
1054      int promoChar;\r
1055      char out[MOVE_LEN];\r
1056 {\r
1057     ChessSquare piece;\r
1058     ChessMove kind;\r
1059     char *outp = out;\r
1060     CoordsToAlgebraicClosure cl;\r
1061     \r
1062     if (rf == DROP_RANK) {\r
1063         /* Bughouse piece drop */\r
1064         *outp++ = ToUpper(PieceToChar((ChessSquare) ff));\r
1065         *outp++ = '@';\r
1066         *outp++ = ft + 'a';\r
1067         if(rt+ONE <= '9')\r
1068            *outp++ = rt + ONE;\r
1069         else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
1070         *outp = NULLCHAR;\r
1071         return (flags & F_WHITE_ON_MOVE) ? WhiteDrop : BlackDrop;\r
1072     }\r
1073 \r
1074     if (promoChar == 'x') promoChar = NULLCHAR;\r
1075     piece = board[rf][ff];\r
1076     switch (piece) {\r
1077       case WhitePawn:\r
1078       case BlackPawn:\r
1079         kind = LegalityTest(board, flags, epfile, initialRights, rf, ff, rt, ft, promoChar);\r
1080         if (kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {\r
1081             /* Keep short notation if move is illegal only because it\r
1082                leaves the player in check, but still return IllegalMove */\r
1083             kind = LegalityTest(board, flags|F_IGNORE_CHECK, epfile, initialRights,\r
1084                                rf, ff, rt, ft, promoChar);\r
1085             if (kind == IllegalMove) break;\r
1086             kind = IllegalMove;\r
1087         }\r
1088         /* Pawn move */\r
1089         *outp++ = ff + 'a';\r
1090         if (ff == ft && board[rt][ft] == EmptySquare) { /* [HGM] Xiangqi has straight noncapts! */\r
1091             /* Non-capture; use style "e5" */\r
1092             if(rt+ONE <= '9')\r
1093                *outp++ = rt + ONE;\r
1094             else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
1095         } else {\r
1096             /* Capture; use style "exd5" */\r
1097             if(gameInfo.variant != VariantXiangqi || board[rt][ft] != EmptySquare )\r
1098             *outp++ = 'x';  /* [HGM] Xiangqi has sideway noncaptures across river! */\r
1099             *outp++ = ft + 'a';\r
1100             if(rt+ONE <= '9')\r
1101                *outp++ = rt + ONE;\r
1102             else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
1103         }\r
1104         /* Use promotion suffix style "=Q" */\r
1105         if (promoChar != NULLCHAR && promoChar != 'x') {\r
1106             *outp++ = '=';\r
1107             *outp++ = ToUpper(promoChar);\r
1108         }\r
1109         *outp = NULLCHAR;\r
1110         return kind;\r
1111 \r
1112         \r
1113       case WhiteKing:\r
1114       case BlackKing:\r
1115         /* Fabien moved code: FRC castling first (if KxR), wild castling second */\r
1116         /* Code added by Tord:  FRC castling. */\r
1117         if((piece == WhiteKing && board[rt][ft] == WhiteRook) ||\r
1118            (piece == BlackKing && board[rt][ft] == BlackRook)) {\r
1119           if(ft > ff) strcpy(out, "O-O"); else strcpy(out, "O-O-O");\r
1120             return LegalityTest(board, flags, epfile, initialRights,\r
1121                                 rf, ff, rt, ft, promoChar);\r
1122         }\r
1123         /* End of code added by Tord */\r
1124         /* Test for castling or ICS wild castling */\r
1125         /* Use style "O-O" (oh-oh) for PGN compatibility */\r
1126         else if (rf == rt &&\r
1127             rf == ((piece == WhiteKing) ? 0 : BOARD_HEIGHT-1) &&\r
1128             ((ff == BOARD_WIDTH>>1 && (ft == 2 || ft == BOARD_WIDTH-2)) ||\r
1129              (ff == (BOARD_WIDTH-1)>>1 && (ft == 1 || ft == BOARD_WIDTH-3)))) {\r
1130             if(ft==1 || ft==BOARD_WIDTH-2)\r
1131                 strcpy(out, "O-O");\r
1132             else\r
1133                 strcpy(out, "O-O-O");\r
1134 \r
1135             /* This notation is always unambiguous, unless there are\r
1136                kings on both the d and e files, with "wild castling"\r
1137                possible for the king on the d file and normal castling\r
1138                possible for the other.  ICS rules for wild 9\r
1139                effectively make castling illegal for either king in\r
1140                this situation.  So I am not going to worry about it;\r
1141                I'll just generate an ambiguous O-O in this case.\r
1142             */\r
1143             return LegalityTest(board, flags, epfile, initialRights,\r
1144                                 rf, ff, rt, ft, promoChar);\r
1145         }\r
1146 \r
1147         /* else fall through */\r
1148       default:\r
1149         /* Piece move */\r
1150         cl.rf = rf;\r
1151         cl.ff = ff;\r
1152         cl.rt = rt;\r
1153         cl.ft = ft;\r
1154         cl.piece = piece;\r
1155         cl.kind = IllegalMove;\r
1156         cl.rank = cl.file = cl.either = 0;\r
1157         GenLegal(board, flags, epfile, initialRights,\r
1158                  CoordsToAlgebraicCallback, (VOIDSTAR) &cl);\r
1159 \r
1160         if (cl.kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {\r
1161             /* Generate pretty moves for moving into check, but\r
1162                still return IllegalMove.\r
1163             */\r
1164             GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights,\r
1165                      CoordsToAlgebraicCallback, (VOIDSTAR) &cl);\r
1166             if (cl.kind == IllegalMove) break;\r
1167             cl.kind = IllegalMove;\r
1168         }\r
1169 \r
1170         /* Style is "Nf3" or "Nxf7" if this is unambiguous,\r
1171            else "Ngf3" or "Ngxf7",\r
1172            else "N1f3" or "N5xf7",\r
1173            else "Ng1f3" or "Ng5xf7".\r
1174         */\r
1175         *outp++ = ToUpper(PieceToChar(piece));\r
1176         \r
1177         if (cl.file || (cl.either && !cl.rank)) {\r
1178             *outp++ = ff + 'a';\r
1179         }\r
1180         if (cl.rank) {\r
1181             if(rf+ONE <= '9')\r
1182                 *outp++ = rf + ONE;\r
1183             else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }\r
1184         }\r
1185 \r
1186         if(board[rt][ft] != EmptySquare)\r
1187           *outp++ = 'x';\r
1188 \r
1189         *outp++ = ft + 'a';\r
1190         if(rt+ONE <= '9')\r
1191            *outp++ = rt + ONE;\r
1192         else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
1193         *outp = NULLCHAR;\r
1194         return cl.kind;\r
1195         \r
1196 #ifdef FAIRY\r
1197       /* [HGM] Always long notation for fairies, don't know how they move */\r
1198       case WhiteFairyRook:\r
1199       case BlackFairyRook:\r
1200       case WhiteFairyKnight:\r
1201       case BlackFairyKnight:\r
1202       case WhiteFairyQueen:\r
1203       case BlackFairyQueen:\r
1204 #endif\r
1205       case EmptySquare:\r
1206         /* Moving a nonexistent piece */\r
1207         break;\r
1208     }\r
1209     \r
1210     /* Not a legal move, even ignoring check.\r
1211        If there was a piece on the from square, \r
1212        use style "Ng1g3" or "Ng1xe8";\r
1213        if there was a pawn or nothing (!),\r
1214        use style "g1g3" or "g1xe8".  Use "x"\r
1215        if a piece was on the to square, even\r
1216        a piece of the same color.\r
1217     */\r
1218     outp = out;\r
1219     if (piece != EmptySquare && piece != WhitePawn && piece != BlackPawn) {\r
1220         *outp++ = ToUpper(PieceToChar(piece));\r
1221     }\r
1222     *outp++ = ff + 'a';\r
1223     if(rf+ONE <= '9')\r
1224        *outp++ = rf + ONE;\r
1225     else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }\r
1226     if (board[rt][ft] != EmptySquare) *outp++ = 'x';\r
1227     *outp++ = ft + 'a';\r
1228     if(rt+ONE <= '9')\r
1229        *outp++ = rt + ONE;\r
1230     else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
1231     /* Use promotion suffix style "=Q" */\r
1232     if (promoChar != NULLCHAR && promoChar != 'x') {\r
1233         *outp++ = '=';\r
1234         *outp++ = ToUpper(promoChar);\r
1235     }\r
1236     *outp = NULLCHAR;\r
1237 \r
1238     return IllegalMove;\r
1239 }\r
1240 \r
1241 \r