converted two files from dos to unix format
authorArun Persaud <arun@nubati.net>
Thu, 28 May 2009 07:03:32 +0000 (00:03 -0700)
committerArun Persaud <arun@nubati.net>
Fri, 29 May 2009 04:39:38 +0000 (21:39 -0700)
common.h
moves.c

index 5e51bfd..e93d0e1 100644 (file)
--- a/common.h
+++ b/common.h
-/*\r
- * common.h -- Common definitions for X and Windows NT versions of XBoard\r
- * $Id: common.h,v 2.1 2003/10/27 19:21:00 mann Exp $\r
- *\r
- * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.\r
- * Enhancements Copyright 1992-95 Free Software Foundation, Inc.\r
- *\r
- * The following terms apply to Digital Equipment Corporation's copyright\r
- * interest in XBoard:\r
- * ------------------------------------------------------------------------\r
- * All Rights Reserved\r
- *\r
- * Permission to use, copy, modify, and distribute this software and its\r
- * documentation for any purpose and without fee is hereby granted,\r
- * provided that the above copyright notice appear in all copies and that\r
- * both that copyright notice and this permission notice appear in\r
- * supporting documentation, and that the name of Digital not be\r
- * used in advertising or publicity pertaining to distribution of the\r
- * software without specific, written prior permission.\r
- *\r
- * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
- * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL\r
- * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
- * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\r
- * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\r
- * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\r
- * SOFTWARE.\r
- * ------------------------------------------------------------------------\r
- *\r
- * The following terms apply to the enhanced version of XBoard distributed\r
- * by the Free Software Foundation:\r
- * ------------------------------------------------------------------------\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
- * ------------------------------------------------------------------------\r
- */\r
-\r
-#ifndef _COMMON\r
-#define _COMMON\r
-\r
-\r
-/* Begin compatibility grunge  */\r
-\r
-#if defined(__STDC__) || defined(WIN32) || defined(_amigados)\r
-#define        P(args) args\r
-typedef void *VOIDSTAR;\r
-#else\r
-#define P(args)                ()\r
-typedef char *VOIDSTAR;\r
-#endif\r
-\r
-#ifdef WIN32\r
-typedef char Boolean;\r
-typedef char *String;\r
-#define popen _popen\r
-#define pclose _pclose\r
-\r
-#else\r
-#ifdef _amigados        /*  It is important, that these types have  */\r
-typedef int Boolean;    /*  a length of 4 bytes each, as we are     */\r
-typedef char *String;   /*  using ReadArgs() for argument parsing.  */\r
-#ifdef _DCC\r
-FILE *popen(const char *, const char *);\r
-int pclose(FILE *);\r
-#endif\r
-\r
-#else\r
-#include <X11/Intrinsic.h>\r
-#endif\r
-#endif\r
-\r
-\r
-#ifndef TRUE\r
-#define TRUE 1\r
-#define FALSE 0\r
-#endif\r
-\r
-#define UNKNOWN -1 /* [HGM] nps */\r
-\r
-#if !HAVE_RANDOM\r
-# if HAVE_RAND48\r
-#  define srandom srand48\r
-#  define random lrand48\r
-# else /* not HAVE_RAND48 */\r
-#  define srandom srand\r
-#  define random rand\r
-# endif /* not HAVE_RAND48 */\r
-#endif /* !HAVE_RANDOM */\r
-\r
-/* End compatibility grunge */\r
-\r
+/*
+ * common.h -- Common definitions for X and Windows NT versions of XBoard
+ * $Id: common.h,v 2.1 2003/10/27 19:21:00 mann Exp $
+ *
+ * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
+ * Enhancements Copyright 1992-95 Free Software Foundation, Inc.
+ *
+ * The following terms apply to Digital Equipment Corporation's copyright
+ * interest in XBoard:
+ * ------------------------------------------------------------------------
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Digital not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * ------------------------------------------------------------------------
+ *
+ * The following terms apply to the enhanced version of XBoard distributed
+ * by the Free Software Foundation:
+ * ------------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * ------------------------------------------------------------------------
+ */
+
+#ifndef _COMMON
+#define _COMMON
+
+
+/* Begin compatibility grunge  */
+
+#if defined(__STDC__) || defined(WIN32) || defined(_amigados)
+#define        P(args) args
+typedef void *VOIDSTAR;
+#else
+#define P(args)                ()
+typedef char *VOIDSTAR;
+#endif
+
+#ifdef WIN32
+typedef char Boolean;
+typedef char *String;
+#define popen _popen
+#define pclose _pclose
+
+#else
+#ifdef _amigados        /*  It is important, that these types have  */
+typedef int Boolean;    /*  a length of 4 bytes each, as we are     */
+typedef char *String;   /*  using ReadArgs() for argument parsing.  */
+#ifdef _DCC
+FILE *popen(const char *, const char *);
+int pclose(FILE *);
+#endif
+
+#else
+#include <X11/Intrinsic.h>
+#endif
+#endif
+
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define UNKNOWN -1 /* [HGM] nps */
+
+#if !HAVE_RANDOM
+# if HAVE_RAND48
+#  define srandom srand48
+#  define random lrand48
+# else /* not HAVE_RAND48 */
+#  define srandom srand
+#  define random rand
+# endif /* not HAVE_RAND48 */
+#endif /* !HAVE_RANDOM */
+
+/* End compatibility grunge */
+
 #define PROTOVER                2       /* engine protocol version */
 
 #define PROTOVER                2       /* engine protocol version */
 
-// [HGM] license: Messages that engines must print to satisfy their license requirements for patented variants\r
-#define GOTHIC "Gothic Chess (see www.GothicChess.com) is licensed under U.S. Patent #6,481,716 by Ed Trice"\r
-#define NOFALCON "Falcon Chess (see www.chessvariants.com) is licensed under U.S. Patent #5,690,334 by George W. Duke"\r
-\r
-/* [HGM] Some notes about board sizes:\r
-   In games that allow piece drops, the holdings are considered part of the\r
-   board, in the leftmost and rightmost two files. This way they are\r
-   automatically part of the game-history states, and enjoy all display\r
-   functions (including drag-drop and click-click moves to the regular part\r
-   of the board). The drawback of this is that the internal numbering of\r
-   files starts at 2 for the a-file if holdings are displayed. To ensure\r
-   consistency, this shifted numbering system is used _everywhere_ in the\r
-   code, and conversion to the 'normal' system only takes place when the\r
-   file number is converted to or from ASCII (by redefining the character\r
-   constant 'a'). This works because Winboard only communicates with the\r
-   outside world in ASCII. In a similar way, the different rank numbering\r
-   systems (starting at rank 0 or 1) are implemented by redefining '1'.\r
-*/\r
-#define BOARD_SIZE              16            /* [HGM] for in declarations */\r
-#define BOARD_HEIGHT (gameInfo.boardHeight)   // [HGM] made user adjustable \r
-#define BOARD_WIDTH  (gameInfo.boardWidth + 2*gameInfo.holdingsWidth)   \r
-#define BOARD_LEFT   (gameInfo.holdingsWidth) // [HGM] play-board edges     \r
-#define BOARD_RGHT   (gameInfo.boardWidth + gameInfo.holdingsWidth)\r
-#define ONE          ('1'-(BOARD_HEIGHT>9))   // [HGM] foremost board rank  \r
-#define AAA          ('a'-BOARD_LEFT)         // [HGM] leftmost board file  \r
-#define DROP_RANK               -3\r
-#define MAX_MOVES              1000\r
-#define MSG_SIZ                        512\r
-#define DIALOG_SIZE            256\r
-#define STAR_MATCH_N            16\r
-#define MOVE_LEN               32\r
-#define TIME_CONTROL           "5"     /* in minutes */\r
-#define TIME_DELAY_QUOTE       "1.0"   /* seconds between moves */\r
-#define TIME_DELAY              ((float) 1.0)\r
-#define MOVES_PER_SESSION      40      /* moves per TIME_CONTROL */\r
-#define TIME_INCREMENT          -1      /* if >= 0, MOVES_PER_SESSION unused */\r
-#define WhiteOnMove(move)      (((move) % 2) == 0)\r
-#define ICS_HOST                "chessclub.com"\r
-#define ICS_PORT               "5000"\r
-#define ICS_COMM_PORT           ""\r
-#define FIRST_HOST             "localhost"\r
-#define SECOND_HOST            "localhost"\r
-#define TELNET_PROGRAM          "telnet"\r
-#define MATCH_MODE             "False"\r
-#define INIT_STRING            "new\nrandom\n"\r
-#define WHITE_STRING           "white\ngo\n"\r
-#define BLACK_STRING           "black\ngo\n"\r
-#define COMPUTER_STRING         "computer\n"\r
-#define REUSE_CHESS_PROGRAMS    1\r
-#define WHITE_PIECE_COLOR      "#FFFFCC"\r
-#define BLACK_PIECE_COLOR      "#202020"\r
-#define LIGHT_SQUARE_COLOR     "#C8C365"\r
-#define DARK_SQUARE_COLOR      "#77A26D"\r
-#define JAIL_SQUARE_COLOR       "#808080"\r
-#define HIGHLIGHT_SQUARE_COLOR "#FFFF00"\r
-#define PREMOVE_HIGHLIGHT_COLOR        "#FF0000"\r
-#define BELLCHAR                '\007'\r
-#define NULLCHAR                '\000'\r
-#define FEATURE_TIMEOUT         10000 /*ms*/\r
-\r
-/* Zippy defaults */\r
-#define ZIPPY_TALK FALSE\r
-#define ZIPPY_PLAY FALSE\r
-#define ZIPPY_LINES "yow.lines"\r
-#define ZIPPY_PINHEAD ""\r
-#define ZIPPY_PASSWORD ""\r
-#define ZIPPY_PASSWORD2 ""\r
-#define ZIPPY_WRONG_PASSWORD ""\r
-#define ZIPPY_ACCEPT_ONLY ""\r
-#define ZIPPY_USE_I TRUE\r
-#define ZIPPY_BUGHOUSE 0\r
-#define ZIPPY_NOPLAY_CRAFTY FALSE\r
-#define ZIPPY_GAME_END "gameend\n"\r
-#define ZIPPY_GAME_START ""\r
-#define ZIPPY_ADJOURN FALSE\r
-#define ZIPPY_ABORT FALSE\r
-#define ZIPPY_VARIANTS "normal,fischerandom,crazyhouse,losers,suicide,3checks,twokings,bughouse,shatranj"\r
-#define ZIPPY_MAX_GAMES 0\r
-#define ZIPPY_REPLAY_TIMEOUT 120\r
-\r
-typedef enum {\r
-    BeginningOfGame, MachinePlaysWhite, MachinePlaysBlack,\r
-    AnalyzeMode, AnalyzeFile, TwoMachinesPlay,\r
-    EditGame, PlayFromGameFile, EndOfGame, EditPosition, Training,\r
-    IcsIdle, IcsPlayingWhite, IcsPlayingBlack, IcsObserving,\r
-    IcsExamining\r
-  } GameMode;\r
-\r
-typedef enum {\r
-    /* [HGM] the order here is crucial for Crazyhouse & Shogi: */\r
-    /* only the first N pieces can go into the holdings, and   */\r
-    /* promotions in those variants shift P-W to U-S           */\r
-    WhitePawn, WhiteKnight, WhiteBishop, WhiteRook, WhiteQueen, \r
-    WhiteFerz, WhiteAlfil, WhiteAngel, WhiteMarshall, WhiteWazir, WhiteMan, \r
-    WhiteCannon, WhiteNightrider, WhiteCardinal, WhiteDragon, WhiteGrasshopper,\r
-    WhiteSilver, WhiteFalcon, WhiteLance, WhiteCobra, WhiteUnicorn, WhiteKing,\r
-    BlackPawn, BlackKnight, BlackBishop, BlackRook, BlackQueen,\r
-    BlackFerz, BlackAlfil, BlackAngel, BlackMarshall, BlackWazir, BlackMan, \r
-    BlackCannon, BlackNightrider, BlackCardinal, BlackDragon, BlackGrasshopper,\r
-    BlackSilver, BlackFalcon, BlackLance, BlackCobra, BlackUnicorn, BlackKing,\r
-    EmptySquare, \r
-    ClearBoard, WhitePlay, BlackPlay, PromotePiece, DemotePiece /*for use on EditPosition menus*/\r
-  } ChessSquare;\r
-\r
-/* [HGM] some macros that can be used as prefixes to convert piece types */\r
-#define WHITE_TO_BLACK (int)BlackPawn - (int)WhitePawn + (int)\r
-#define BLACK_TO_WHITE (int)WhitePawn - (int)BlackPawn + (int)\r
-#define PROMOTED       (int)WhiteDragon - (int)WhiteRook + (int)\r
-#define DEMOTED        (int)WhiteRook - (int)WhiteDragon + (int)\r
-#define SHOGI          (int)EmptySquare + (int)\r
-\r
-\r
-typedef ChessSquare Board[BOARD_SIZE][BOARD_SIZE];\r
-\r
-typedef enum {\r
-    WhiteKingSideCastle = 1, WhiteQueenSideCastle,\r
-    WhiteKingSideCastleWild, WhiteQueenSideCastleWild,\r
-    WhiteHSideCastleFR, WhiteASideCastleFR, \r
-    BlackKingSideCastle, BlackQueenSideCastle,\r
-    BlackKingSideCastleWild, BlackQueenSideCastleWild,\r
-    BlackHSideCastleFR, BlackASideCastleFR, \r
-    WhitePromotionKnight, WhitePromotionBishop,\r
-    WhitePromotionRook, WhitePromotionQueen, WhitePromotionKing,\r
-    WhitePromotionChancellor, WhitePromotionArchbishop, WhitePromotionCentaur,\r
-    BlackPromotionKnight, BlackPromotionBishop,\r
-    BlackPromotionRook, BlackPromotionQueen, BlackPromotionKing,\r
-    BlackPromotionChancellor, BlackPromotionArchbishop, BlackPromotionCentaur,\r
-    WhiteCapturesEnPassant, BlackCapturesEnPassant,\r
-    WhiteDrop, BlackDrop, \r
-    NormalMove, AmbiguousMove, IllegalMove, ImpossibleMove,\r
-    WhiteWins, BlackWins, GameIsDrawn, GameUnfinished,\r
-    GNUChessGame, XBoardGame, MoveNumberOne, \r
-    Comment, PositionDiagram, ElapsedTime, PGNTag, NAG\r
-  } ChessMove;\r
-\r
-typedef enum {\r
-    ColorShout, ColorSShout, ColorChannel1, ColorChannel, ColorKibitz,\r
-    ColorTell, ColorChallenge, ColorRequest, ColorSeek, ColorNormal,\r
-    ColorNone, NColorClasses\r
-} ColorClass;\r
-\r
-typedef enum {\r
-    SoundMove, SoundBell, SoundAlarm, SoundIcsWin, SoundIcsLoss,\r
-    SoundIcsDraw, SoundIcsUnfinished, NSoundClasses\r
-} SoundClass;\r
-\r
-/* Names for chess variants, not necessarily supported */\r
-typedef enum {\r
-    VariantNormal,       /* Normal chess */\r
-    VariantLoadable,     /* "loadgame" command allowed (not really a variant)*/\r
-    VariantWildCastle,   /* Shuffle chess where king can castle from d file */\r
-    VariantNoCastle,     /* Shuffle chess with no castling at all */\r
-    VariantFischeRandom, /* FischeRandom */\r
-    VariantBughouse,     /* Bughouse, ICC/FICS rules */\r
-    VariantCrazyhouse,   /* Crazyhouse, ICC/FICS rules */\r
-    VariantLosers,       /* Try to lose all pieces or get mated (ICC wild 17)*/\r
-    VariantSuicide,      /* Try to lose all pieces incl. king (FICS) */\r
-    VariantGiveaway,     /* Try to have no legal moves left (ICC wild 26) */\r
-    VariantTwoKings,     /* Weird ICC wild 9 */\r
-    VariantKriegspiel,   /* Kriegspiel; pawns can capture invisible pieces */\r
-    VariantAtomic,       /* Capturing piece explodes (ICC wild 27) */\r
-    Variant3Check,       /* Win by giving check 3 times (ICC wild 25) */\r
-    VariantShatranj,     /* Unsupported (ICC wild 28) */\r
-    Variant29,           /* Temporary name for possible future ICC wild 29 */\r
-    Variant30,           /* Temporary name for possible future ICC wild 30 */\r
-    Variant31,           /* Temporary name for possible future ICC wild 31 */\r
-    Variant32,           /* Temporary name for possible future ICC wild 32 */\r
-    Variant33,           /* Temporary name for possible future ICC wild 33 */\r
-    Variant34,           /* Temporary name for possible future ICC wild 34 */\r
-    Variant35,           /* Temporary name for possible future ICC wild 35 */\r
-    Variant36,           /* Temporary name for possible future ICC wild 36 */\r
-    VariantShogi,        /* [HGM] added variants */\r
-    VariantXiangqi,\r
-    VariantCourier,\r
-    VariantGothic,\r
-    VariantCapablanca,\r
-    VariantKnightmate,\r
-    VariantFairy,        \r
-    VariantCylinder,\r
-    VariantFalcon,\r
-    VariantCapaRandom,\r
-    VariantBerolina,\r
-    VariantJanus,\r
-    VariantSuper,\r
-    VariantGreat,\r
-    VariantUnknown       /* Catchall for other unknown variants */\r
-} VariantClass;\r
-\r
-#define VARIANT_NAMES { \\r
-  "normal", \\r
-  "normal", \\r
-  "wildcastle", \\r
-  "nocastle", \\r
-  "fischerandom", \\r
-  "bughouse", \\r
-  "crazyhouse", \\r
-  "losers", \\r
-  "suicide", \\r
-  "giveaway", \\r
-  "twokings", \\r
-  "kriegspiel", \\r
-  "atomic", \\r
-  "3check", \\r
-  "shatranj", \\r
-  "wild29", \\r
-  "wild30", \\r
-  "wild31", \\r
-  "wild32", \\r
-  "wild33", \\r
-  "wild34", \\r
-  "wild35", \\r
-  "wild36", \\r
-  "shogi", \\r
-  "xiangqi", \\r
-  "courier", \\r
-  "gothic", \\r
-  "capablanca", \\r
-  "knightmate", \\r
-  "fairy", \\r
-  "cylinder", \\r
-  "falcon",\\r
-  "caparandom",\\r
-  "berolina",\\r
-  "janus",\\r
-  "super",\\r
-  "great",\\r
-  "unknown" \\r
-}\r
-\r
-typedef struct {\r
-#if !defined(_amigados)\r
-    char *whitePieceColor;\r
-    char *blackPieceColor;\r
-    char *lightSquareColor;\r
-    char *darkSquareColor;\r
-    char *jailSquareColor;\r
-    char *highlightSquareColor;\r
-    char *premoveHighlightColor;\r
-#else\r
-    int whitePieceColor;\r
-    int blackPieceColor;\r
-    int lightSquareColor;\r
-    int darkSquareColor;\r
-    int jailSquareColor;\r
-    int highlightSquareColor;\r
-    int premoveHighlightColor;\r
-#endif\r
-    int movesPerSession;\r
-    int timeIncrement;\r
-    char *initString;\r
-    char *secondInitString;\r
-    char *firstComputerString;\r
-    char *secondComputerString;\r
-    char *firstChessProgram;\r
-    char *secondChessProgram;\r
-    char *firstDirectory;\r
-    char *secondDirectory;\r
-    Boolean firstPlaysBlack;\r
-    Boolean noChessProgram;\r
-    char *firstHost;\r
-    char *secondHost;\r
-    char *bitmapDirectory;\r
-    char *remoteShell;\r
-    char *remoteUser;\r
-    float timeDelay;\r
-    char *timeControl;\r
-    Boolean icsActive;\r
-    char *icsHost;\r
-    char *icsPort;\r
-    char *icsCommPort;  /* if set, use serial port instead of tcp host/port */\r
-    char *icsLogon;     /* Hack to permit variable logon scripts. */\r
-    char *icsHelper;\r
-    Boolean icsInputBox;\r
-    Boolean useTelnet;\r
-    char *telnetProgram;\r
-    char *gateway;\r
-    char *loadGameFile;\r
-    int loadGameIndex;      /* game # within file */\r
-    char *saveGameFile;\r
-    Boolean autoSaveGames;\r
-    char *loadPositionFile;\r
-    int loadPositionIndex;  /* position # within file */\r
-    char *savePositionFile;\r
-    Boolean matchMode;\r
-    int matchGames;\r
-    Boolean monoMode;\r
-    Boolean debugMode;\r
-    Boolean clockMode;\r
-    char *boardSize;\r
-    Boolean Iconic;\r
-    char *searchTime;\r
-    int searchDepth;\r
-    Boolean showCoords;\r
-    char *clockFont;\r
-    char *messageFont; /* WinBoard only */\r
-    char *coordFont;\r
-    char *font; /* xboard only: all other fonts */\r
-    char *tagsFont; /* WinBoard only */\r
-    char *commentFont; /* WinBoard only */\r
-    char *icsFont; /* WinBoard only */\r
-    Boolean ringBellAfterMoves;\r
-    Boolean autoCallFlag;\r
-    Boolean flipView;\r
-    Boolean autoFlipView;\r
-    char *cmailGameName; /* xboard only */\r
-    Boolean alwaysPromoteToQueen;\r
-    Boolean oldSaveStyle;\r
-    Boolean quietPlay;\r
-    Boolean showThinking;\r
-    Boolean ponderNextMove;\r
-    Boolean periodicUpdates;\r
-    Boolean autoObserve;\r
-    Boolean autoComment;\r
-    Boolean getMoveList;\r
-    Boolean testLegality;\r
-    int borderXoffset; /* xboard only */\r
-    int borderYoffset; /* xboard only */\r
-    Boolean titleInWindow; /* xboard only */\r
-    Boolean localLineEditing; /* WinBoard only */\r
-    Boolean zippyTalk;\r
-    Boolean zippyPlay;\r
-    int flashCount; /* Number of times to flash (xboard only) */\r
-    int flashRate; /* Flashes per second (xboard only)  */\r
-    char *pixmapDirectory; /* Path to XPM/XIM files to use (xboard only) */\r
-    int msLoginDelay;  /* Delay per character (in msec) while sending\r
-                         ICS logon script (xboard only) */\r
-    Boolean colorize;  /* If True, use the following colors to color text */\r
-    /* Strings for colors, as "fg, bg, bold" (strings used in xboard only) */\r
-    char *colorShout;\r
-    char *colorSShout;\r
-    char *colorChannel1;\r
-    char *colorChannel;\r
-    char *colorKibitz;\r
-    char *colorTell;\r
-    char *colorChallenge;\r
-    char *colorRequest;\r
-    char *colorSeek;\r
-    char *colorNormal;\r
-    char *soundProgram; /* sound-playing program */\r
-    char *soundShout;\r
-    char *soundSShout;\r
-    char *soundChannel1;\r
-    char *soundChannel;\r
-    char *soundKibitz;\r
-    char *soundTell;\r
-    char *soundChallenge;\r
-    char *soundRequest;\r
-    char *soundSeek;\r
-    char *soundMove;\r
-    char *soundIcsWin;\r
-    char *soundIcsLoss;\r
-    char *soundIcsDraw;\r
-    char *soundIcsUnfinished;\r
-    char *soundIcsAlarm;\r
-    Boolean reuseFirst;\r
-    Boolean reuseSecond;\r
-    Boolean animateDragging; /* If True, animate mouse dragging of pieces */\r
-    Boolean animate;   /* If True, animate non-mouse moves */\r
-    int animSpeed;     /* Delay in milliseconds between animation frames */\r
-    Boolean popupMoveErrors;\r
-    Boolean popupExitMessage;\r
-    int showJail;\r
-    Boolean highlightLastMove;\r
-    Boolean highlightDragging;\r
-    Boolean blindfold;          /* if true, no pieces are drawn */\r
-    Boolean premove;           /* true if premove feature enabled */ \r
-    Boolean premoveWhite;      /* true if premoving White first move  */ \r
-    char *premoveWhiteText;    /* text of White premove 1 */ \r
-    Boolean premoveBlack;      /* true if premoving Black first move */ \r
-    char *premoveBlackText;    /* text of Black premove 1 */ \r
-    Boolean icsAlarm;          /* true if sounding alarm at a certain time */  \r
-    int icsAlarmTime;          /* time to sound alarm, in milliseconds */\r
-    Boolean autoRaiseBoard;\r
-    int fontSizeTolerance; /* xboard only */\r
-    char *initialMode;\r
-    char *variant;\r
-    int firstProtocolVersion;\r
-    int secondProtocolVersion;\r
-    Boolean showButtonBar;\r
-    Boolean icsEngineAnalyze; \r
-\r
-    /* [AS] New properties (down to the "ZIPPY" part) */\r
-    Boolean firstScoreIsAbsolute;  /* If true, engine score is always from white side */\r
-    Boolean secondScoreIsAbsolute; /* If true, engine score is always from white side */\r
-    Boolean saveExtendedInfoInPGN; /* If true, saved PGN games contain extended info */\r
-    Boolean hideThinkingFromHuman; /* If true, program thinking is generated but not displayed in human/computer matches */\r
-    char * liteBackTextureFile; /* Name of texture bitmap for lite squares */\r
-    char * darkBackTextureFile; /* Name of texture bitmap for dark squares */\r
-    int liteBackTextureMode;\r
-    int darkBackTextureMode;\r
-    char * renderPiecesWithFont; /* Name of font for rendering chess pieces */\r
-    char * fontToPieceTable; /* Map to translate font character to chess pieces */\r
-    int fontBackColorWhite;\r
-    int fontForeColorWhite;\r
-    int fontBackColorBlack;\r
-    int fontForeColorBlack;\r
-    int fontPieceSize; /* Size of font relative to square (percentage) */\r
-    int overrideLineGap; /* If >= 0 overrides the lineGap value of the board size properties */\r
-    int adjudicateLossThreshold; /* Adjudicate a two-machine game if both engines agree the score is below this for 6 plies */\r
-    int delayBeforeQuit;\r
-    int delayAfterQuit;\r
-    char * nameOfDebugFile;\r
-    char * pgnEventHeader;\r
-    int defaultFrcPosition;\r
-    char * gameListTags;\r
-    Boolean saveOutOfBookInfo;\r
-    Boolean showEvalInMoveHistory;\r
-    int evalHistColorWhite;\r
-    int evalHistColorBlack;\r
-    Boolean highlightMoveWithArrow;\r
-    int highlightArrowColor;\r
-    Boolean useStickyWindows;\r
-    int adjudicateDrawMoves;\r
-    Boolean autoDisplayComment;\r
-    Boolean autoDisplayTags;\r
-    Boolean firstIsUCI;\r
-    Boolean secondIsUCI;\r
-    Boolean firstHasOwnBookUCI;\r
-    Boolean secondHasOwnBookUCI;\r
-    char * polyglotDir;\r
-    Boolean usePolyglotBook;\r
-    char * polyglotBook;\r
-    int defaultHashSize;\r
-    int defaultCacheSizeEGTB;\r
-    char * defaultPathEGTB;\r
-\r
-    /* [HGM] Board size */\r
-    int NrFiles;\r
-    int NrRanks;\r
-    int holdingsSize;\r
-    int matchPause;\r
-    char * pieceToCharTable;\r
-    Boolean allWhite;\r
-    Boolean upsideDown;\r
-    Boolean alphaRank;\r
-    Boolean testClaims;\r
-    Boolean checkMates;\r
-    Boolean materialDraws;\r
-    Boolean trivialDraws;\r
-    int ruleMoves;\r
-    int drawRepeats;\r
-\r
-#if ZIPPY\r
-    char *zippyLines;\r
-    char *zippyPinhead;\r
-    char *zippyPassword;\r
-    char *zippyPassword2;\r
-    char *zippyWrongPassword;\r
-    char *zippyAcceptOnly;\r
-    int zippyUseI;\r
-    int zippyBughouse;\r
-    int zippyNoplayCrafty;\r
-    char *zippyGameEnd;\r
-    char *zippyGameStart;\r
-    int zippyAdjourn;\r
-    int zippyAbort;\r
-    char *zippyVariants;\r
-    int zippyMaxGames;\r
-    int zippyReplayTimeout; /*seconds*/\r
-#endif\r
-\r
-    char *serverMovesName;\r
-    Boolean suppressLoadMoves;\r
-    int serverPause;\r
-    int firstTimeOdds;\r
-    int secondTimeOdds;\r
-    int timeOddsMode;\r
-    int firstAccumulateTC;\r
-    int secondAccumulateTC;\r
-    int firstNPS;\r
-    int secondNPS;\r
-    Boolean autoKibitz;\r
-    int engineComments;\r
-    char *userName;\r
-    int rewindIndex;    /* [HGM] autoinc   */\r
-    int sameColorGames; /* [HGM] alternate */\r
-    int smpCores;       /* [HGM] SMP       */\r
-    char *egtFormats;\r
-    int niceEngines;    /* [HGM] nice      */\r
-    char *firstLogo;    /* [HGM] logo      */\r
-    char *secondLogo;\r
-    Boolean autoLogo;\r
-    Boolean noGUI;      /* [HGM] fast: suppress all display updates */\r
-    char *firstOptions; /* [HGM] options   */\r
-    char *secondOptions;\r
-} AppData, *AppDataPtr;\r
-\r
-/* [AS] PGN tags (for showing in the game list) */\r
-#define GLT_EVENT           'e'\r
-#define GLT_SITE            's'\r
-#define GLT_DATE            'd'\r
-#define GLT_ROUND           'o'\r
-#define GLT_PLAYERS         'p'     /* I.e. white "-" black */\r
-#define GLT_RESULT          'r'\r
-#define GLT_WHITE_ELO       'w'\r
-#define GLT_BLACK_ELO       'b'\r
-#define GLT_TIME_CONTROL    't'\r
-#define GLT_VARIANT         'v'\r
-#define GLT_OUT_OF_BOOK     'a'\r
-\r
-#define GLT_DEFAULT_TAGS    "eprd"  /* Event, players, result, date */\r
-\r
-#define GLT_ALL_TAGS        "esdoprwbtva"\r
-\r
-#define PGN_OUT_OF_BOOK     "Annotator"\r
-\r
-extern AppData appData;\r
-\r
-typedef struct {\r
-    /* PGN 7-tag info */\r
-    char *event;\r
-    char *site;\r
-    char *date;\r
-    char *round;\r
-    char *white;\r
-    char *black;\r
-    ChessMove result;\r
-    /* Additional info */\r
-    char *fen;          /* NULL or FEN for starting position; input only */\r
-    char *resultDetails;\r
-    char *timeControl;\r
-    char *extraTags;    /* NULL or "[Tag \"Value\"]\n", etc. */\r
-    int whiteRating;    /* -1 if unknown */\r
-    int blackRating;    /* -1 if unknown */\r
-    VariantClass variant;\r
-    char *outOfBook;    /* [AS] Move and score when engine went out of book */\r
-    int boardWidth;     /* [HGM] adjustable board size */\r
-    int boardHeight;\r
-/* [HGM] For Shogi and Crazyhouse: */\r
-    int holdingsSize;  /* number of different piece types in holdings       */\r
-    int holdingsWidth; /* number of files left and right of board, 0 or 2   */\r
-} GameInfo;\r
-\r
-\r
-#endif\r
-\r
+// [HGM] license: Messages that engines must print to satisfy their license requirements for patented variants
+#define GOTHIC "Gothic Chess (see www.GothicChess.com) is licensed under U.S. Patent #6,481,716 by Ed Trice"
+#define NOFALCON "Falcon Chess (see www.chessvariants.com) is licensed under U.S. Patent #5,690,334 by George W. Duke"
+
+/* [HGM] Some notes about board sizes:
+   In games that allow piece drops, the holdings are considered part of the
+   board, in the leftmost and rightmost two files. This way they are
+   automatically part of the game-history states, and enjoy all display
+   functions (including drag-drop and click-click moves to the regular part
+   of the board). The drawback of this is that the internal numbering of
+   files starts at 2 for the a-file if holdings are displayed. To ensure
+   consistency, this shifted numbering system is used _everywhere_ in the
+   code, and conversion to the 'normal' system only takes place when the
+   file number is converted to or from ASCII (by redefining the character
+   constant 'a'). This works because Winboard only communicates with the
+   outside world in ASCII. In a similar way, the different rank numbering
+   systems (starting at rank 0 or 1) are implemented by redefining '1'.
+*/
+#define BOARD_SIZE              16            /* [HGM] for in declarations */
+#define BOARD_HEIGHT (gameInfo.boardHeight)   // [HGM] made user adjustable 
+#define BOARD_WIDTH  (gameInfo.boardWidth + 2*gameInfo.holdingsWidth)   
+#define BOARD_LEFT   (gameInfo.holdingsWidth) // [HGM] play-board edges     
+#define BOARD_RGHT   (gameInfo.boardWidth + gameInfo.holdingsWidth)
+#define ONE          ('1'-(BOARD_HEIGHT>9))   // [HGM] foremost board rank  
+#define AAA          ('a'-BOARD_LEFT)         // [HGM] leftmost board file  
+#define DROP_RANK               -3
+#define MAX_MOVES              1000
+#define MSG_SIZ                        512
+#define DIALOG_SIZE            256
+#define STAR_MATCH_N            16
+#define MOVE_LEN               32
+#define TIME_CONTROL           "5"     /* in minutes */
+#define TIME_DELAY_QUOTE       "1.0"   /* seconds between moves */
+#define TIME_DELAY              ((float) 1.0)
+#define MOVES_PER_SESSION      40      /* moves per TIME_CONTROL */
+#define TIME_INCREMENT          -1      /* if >= 0, MOVES_PER_SESSION unused */
+#define WhiteOnMove(move)      (((move) % 2) == 0)
+#define ICS_HOST                "chessclub.com"
+#define ICS_PORT               "5000"
+#define ICS_COMM_PORT           ""
+#define FIRST_HOST             "localhost"
+#define SECOND_HOST            "localhost"
+#define TELNET_PROGRAM          "telnet"
+#define MATCH_MODE             "False"
+#define INIT_STRING            "new\nrandom\n"
+#define WHITE_STRING           "white\ngo\n"
+#define BLACK_STRING           "black\ngo\n"
+#define COMPUTER_STRING         "computer\n"
+#define REUSE_CHESS_PROGRAMS    1
+#define WHITE_PIECE_COLOR      "#FFFFCC"
+#define BLACK_PIECE_COLOR      "#202020"
+#define LIGHT_SQUARE_COLOR     "#C8C365"
+#define DARK_SQUARE_COLOR      "#77A26D"
+#define JAIL_SQUARE_COLOR       "#808080"
+#define HIGHLIGHT_SQUARE_COLOR "#FFFF00"
+#define PREMOVE_HIGHLIGHT_COLOR        "#FF0000"
+#define BELLCHAR                '\007'
+#define NULLCHAR                '\000'
+#define FEATURE_TIMEOUT         10000 /*ms*/
+
+/* Zippy defaults */
+#define ZIPPY_TALK FALSE
+#define ZIPPY_PLAY FALSE
+#define ZIPPY_LINES "yow.lines"
+#define ZIPPY_PINHEAD ""
+#define ZIPPY_PASSWORD ""
+#define ZIPPY_PASSWORD2 ""
+#define ZIPPY_WRONG_PASSWORD ""
+#define ZIPPY_ACCEPT_ONLY ""
+#define ZIPPY_USE_I TRUE
+#define ZIPPY_BUGHOUSE 0
+#define ZIPPY_NOPLAY_CRAFTY FALSE
+#define ZIPPY_GAME_END "gameend\n"
+#define ZIPPY_GAME_START ""
+#define ZIPPY_ADJOURN FALSE
+#define ZIPPY_ABORT FALSE
+#define ZIPPY_VARIANTS "normal,fischerandom,crazyhouse,losers,suicide,3checks,twokings,bughouse,shatranj"
+#define ZIPPY_MAX_GAMES 0
+#define ZIPPY_REPLAY_TIMEOUT 120
+
+typedef enum {
+    BeginningOfGame, MachinePlaysWhite, MachinePlaysBlack,
+    AnalyzeMode, AnalyzeFile, TwoMachinesPlay,
+    EditGame, PlayFromGameFile, EndOfGame, EditPosition, Training,
+    IcsIdle, IcsPlayingWhite, IcsPlayingBlack, IcsObserving,
+    IcsExamining
+  } GameMode;
+
+typedef enum {
+    /* [HGM] the order here is crucial for Crazyhouse & Shogi: */
+    /* only the first N pieces can go into the holdings, and   */
+    /* promotions in those variants shift P-W to U-S           */
+    WhitePawn, WhiteKnight, WhiteBishop, WhiteRook, WhiteQueen, 
+    WhiteFerz, WhiteAlfil, WhiteAngel, WhiteMarshall, WhiteWazir, WhiteMan, 
+    WhiteCannon, WhiteNightrider, WhiteCardinal, WhiteDragon, WhiteGrasshopper,
+    WhiteSilver, WhiteFalcon, WhiteLance, WhiteCobra, WhiteUnicorn, WhiteKing,
+    BlackPawn, BlackKnight, BlackBishop, BlackRook, BlackQueen,
+    BlackFerz, BlackAlfil, BlackAngel, BlackMarshall, BlackWazir, BlackMan, 
+    BlackCannon, BlackNightrider, BlackCardinal, BlackDragon, BlackGrasshopper,
+    BlackSilver, BlackFalcon, BlackLance, BlackCobra, BlackUnicorn, BlackKing,
+    EmptySquare, 
+    ClearBoard, WhitePlay, BlackPlay, PromotePiece, DemotePiece /*for use on EditPosition menus*/
+  } ChessSquare;
+
+/* [HGM] some macros that can be used as prefixes to convert piece types */
+#define WHITE_TO_BLACK (int)BlackPawn - (int)WhitePawn + (int)
+#define BLACK_TO_WHITE (int)WhitePawn - (int)BlackPawn + (int)
+#define PROMOTED       (int)WhiteDragon - (int)WhiteRook + (int)
+#define DEMOTED        (int)WhiteRook - (int)WhiteDragon + (int)
+#define SHOGI          (int)EmptySquare + (int)
+
+
+typedef ChessSquare Board[BOARD_SIZE][BOARD_SIZE];
+
+typedef enum {
+    WhiteKingSideCastle = 1, WhiteQueenSideCastle,
+    WhiteKingSideCastleWild, WhiteQueenSideCastleWild,
+    WhiteHSideCastleFR, WhiteASideCastleFR, 
+    BlackKingSideCastle, BlackQueenSideCastle,
+    BlackKingSideCastleWild, BlackQueenSideCastleWild,
+    BlackHSideCastleFR, BlackASideCastleFR, 
+    WhitePromotionKnight, WhitePromotionBishop,
+    WhitePromotionRook, WhitePromotionQueen, WhitePromotionKing,
+    WhitePromotionChancellor, WhitePromotionArchbishop, WhitePromotionCentaur,
+    BlackPromotionKnight, BlackPromotionBishop,
+    BlackPromotionRook, BlackPromotionQueen, BlackPromotionKing,
+    BlackPromotionChancellor, BlackPromotionArchbishop, BlackPromotionCentaur,
+    WhiteCapturesEnPassant, BlackCapturesEnPassant,
+    WhiteDrop, BlackDrop, 
+    NormalMove, AmbiguousMove, IllegalMove, ImpossibleMove,
+    WhiteWins, BlackWins, GameIsDrawn, GameUnfinished,
+    GNUChessGame, XBoardGame, MoveNumberOne, 
+    Comment, PositionDiagram, ElapsedTime, PGNTag, NAG
+  } ChessMove;
+
+typedef enum {
+    ColorShout, ColorSShout, ColorChannel1, ColorChannel, ColorKibitz,
+    ColorTell, ColorChallenge, ColorRequest, ColorSeek, ColorNormal,
+    ColorNone, NColorClasses
+} ColorClass;
+
+typedef enum {
+    SoundMove, SoundBell, SoundAlarm, SoundIcsWin, SoundIcsLoss,
+    SoundIcsDraw, SoundIcsUnfinished, NSoundClasses
+} SoundClass;
+
+/* Names for chess variants, not necessarily supported */
+typedef enum {
+    VariantNormal,       /* Normal chess */
+    VariantLoadable,     /* "loadgame" command allowed (not really a variant)*/
+    VariantWildCastle,   /* Shuffle chess where king can castle from d file */
+    VariantNoCastle,     /* Shuffle chess with no castling at all */
+    VariantFischeRandom, /* FischeRandom */
+    VariantBughouse,     /* Bughouse, ICC/FICS rules */
+    VariantCrazyhouse,   /* Crazyhouse, ICC/FICS rules */
+    VariantLosers,       /* Try to lose all pieces or get mated (ICC wild 17)*/
+    VariantSuicide,      /* Try to lose all pieces incl. king (FICS) */
+    VariantGiveaway,     /* Try to have no legal moves left (ICC wild 26) */
+    VariantTwoKings,     /* Weird ICC wild 9 */
+    VariantKriegspiel,   /* Kriegspiel; pawns can capture invisible pieces */
+    VariantAtomic,       /* Capturing piece explodes (ICC wild 27) */
+    Variant3Check,       /* Win by giving check 3 times (ICC wild 25) */
+    VariantShatranj,     /* Unsupported (ICC wild 28) */
+    Variant29,           /* Temporary name for possible future ICC wild 29 */
+    Variant30,           /* Temporary name for possible future ICC wild 30 */
+    Variant31,           /* Temporary name for possible future ICC wild 31 */
+    Variant32,           /* Temporary name for possible future ICC wild 32 */
+    Variant33,           /* Temporary name for possible future ICC wild 33 */
+    Variant34,           /* Temporary name for possible future ICC wild 34 */
+    Variant35,           /* Temporary name for possible future ICC wild 35 */
+    Variant36,           /* Temporary name for possible future ICC wild 36 */
+    VariantShogi,        /* [HGM] added variants */
+    VariantXiangqi,
+    VariantCourier,
+    VariantGothic,
+    VariantCapablanca,
+    VariantKnightmate,
+    VariantFairy,        
+    VariantCylinder,
+    VariantFalcon,
+    VariantCapaRandom,
+    VariantBerolina,
+    VariantJanus,
+    VariantSuper,
+    VariantGreat,
+    VariantUnknown       /* Catchall for other unknown variants */
+} VariantClass;
+
+#define VARIANT_NAMES { \
+  "normal", \
+  "normal", \
+  "wildcastle", \
+  "nocastle", \
+  "fischerandom", \
+  "bughouse", \
+  "crazyhouse", \
+  "losers", \
+  "suicide", \
+  "giveaway", \
+  "twokings", \
+  "kriegspiel", \
+  "atomic", \
+  "3check", \
+  "shatranj", \
+  "wild29", \
+  "wild30", \
+  "wild31", \
+  "wild32", \
+  "wild33", \
+  "wild34", \
+  "wild35", \
+  "wild36", \
+  "shogi", \
+  "xiangqi", \
+  "courier", \
+  "gothic", \
+  "capablanca", \
+  "knightmate", \
+  "fairy", \
+  "cylinder", \
+  "falcon",\
+  "caparandom",\
+  "berolina",\
+  "janus",\
+  "super",\
+  "great",\
+  "unknown" \
+}
+
+typedef struct {
+#if !defined(_amigados)
+    char *whitePieceColor;
+    char *blackPieceColor;
+    char *lightSquareColor;
+    char *darkSquareColor;
+    char *jailSquareColor;
+    char *highlightSquareColor;
+    char *premoveHighlightColor;
+#else
+    int whitePieceColor;
+    int blackPieceColor;
+    int lightSquareColor;
+    int darkSquareColor;
+    int jailSquareColor;
+    int highlightSquareColor;
+    int premoveHighlightColor;
+#endif
+    int movesPerSession;
+    int timeIncrement;
+    char *initString;
+    char *secondInitString;
+    char *firstComputerString;
+    char *secondComputerString;
+    char *firstChessProgram;
+    char *secondChessProgram;
+    char *firstDirectory;
+    char *secondDirectory;
+    Boolean firstPlaysBlack;
+    Boolean noChessProgram;
+    char *firstHost;
+    char *secondHost;
+    char *bitmapDirectory;
+    char *remoteShell;
+    char *remoteUser;
+    float timeDelay;
+    char *timeControl;
+    Boolean icsActive;
+    char *icsHost;
+    char *icsPort;
+    char *icsCommPort;  /* if set, use serial port instead of tcp host/port */
+    char *icsLogon;     /* Hack to permit variable logon scripts. */
+    char *icsHelper;
+    Boolean icsInputBox;
+    Boolean useTelnet;
+    char *telnetProgram;
+    char *gateway;
+    char *loadGameFile;
+    int loadGameIndex;      /* game # within file */
+    char *saveGameFile;
+    Boolean autoSaveGames;
+    char *loadPositionFile;
+    int loadPositionIndex;  /* position # within file */
+    char *savePositionFile;
+    Boolean matchMode;
+    int matchGames;
+    Boolean monoMode;
+    Boolean debugMode;
+    Boolean clockMode;
+    char *boardSize;
+    Boolean Iconic;
+    char *searchTime;
+    int searchDepth;
+    Boolean showCoords;
+    char *clockFont;
+    char *messageFont; /* WinBoard only */
+    char *coordFont;
+    char *font; /* xboard only: all other fonts */
+    char *tagsFont; /* WinBoard only */
+    char *commentFont; /* WinBoard only */
+    char *icsFont; /* WinBoard only */
+    Boolean ringBellAfterMoves;
+    Boolean autoCallFlag;
+    Boolean flipView;
+    Boolean autoFlipView;
+    char *cmailGameName; /* xboard only */
+    Boolean alwaysPromoteToQueen;
+    Boolean oldSaveStyle;
+    Boolean quietPlay;
+    Boolean showThinking;
+    Boolean ponderNextMove;
+    Boolean periodicUpdates;
+    Boolean autoObserve;
+    Boolean autoComment;
+    Boolean getMoveList;
+    Boolean testLegality;
+    int borderXoffset; /* xboard only */
+    int borderYoffset; /* xboard only */
+    Boolean titleInWindow; /* xboard only */
+    Boolean localLineEditing; /* WinBoard only */
+    Boolean zippyTalk;
+    Boolean zippyPlay;
+    int flashCount; /* Number of times to flash (xboard only) */
+    int flashRate; /* Flashes per second (xboard only)  */
+    char *pixmapDirectory; /* Path to XPM/XIM files to use (xboard only) */
+    int msLoginDelay;  /* Delay per character (in msec) while sending
+                         ICS logon script (xboard only) */
+    Boolean colorize;  /* If True, use the following colors to color text */
+    /* Strings for colors, as "fg, bg, bold" (strings used in xboard only) */
+    char *colorShout;
+    char *colorSShout;
+    char *colorChannel1;
+    char *colorChannel;
+    char *colorKibitz;
+    char *colorTell;
+    char *colorChallenge;
+    char *colorRequest;
+    char *colorSeek;
+    char *colorNormal;
+    char *soundProgram; /* sound-playing program */
+    char *soundShout;
+    char *soundSShout;
+    char *soundChannel1;
+    char *soundChannel;
+    char *soundKibitz;
+    char *soundTell;
+    char *soundChallenge;
+    char *soundRequest;
+    char *soundSeek;
+    char *soundMove;
+    char *soundIcsWin;
+    char *soundIcsLoss;
+    char *soundIcsDraw;
+    char *soundIcsUnfinished;
+    char *soundIcsAlarm;
+    Boolean reuseFirst;
+    Boolean reuseSecond;
+    Boolean animateDragging; /* If True, animate mouse dragging of pieces */
+    Boolean animate;   /* If True, animate non-mouse moves */
+    int animSpeed;     /* Delay in milliseconds between animation frames */
+    Boolean popupMoveErrors;
+    Boolean popupExitMessage;
+    int showJail;
+    Boolean highlightLastMove;
+    Boolean highlightDragging;
+    Boolean blindfold;          /* if true, no pieces are drawn */
+    Boolean premove;           /* true if premove feature enabled */ 
+    Boolean premoveWhite;      /* true if premoving White first move  */ 
+    char *premoveWhiteText;    /* text of White premove 1 */ 
+    Boolean premoveBlack;      /* true if premoving Black first move */ 
+    char *premoveBlackText;    /* text of Black premove 1 */ 
+    Boolean icsAlarm;          /* true if sounding alarm at a certain time */  
+    int icsAlarmTime;          /* time to sound alarm, in milliseconds */
+    Boolean autoRaiseBoard;
+    int fontSizeTolerance; /* xboard only */
+    char *initialMode;
+    char *variant;
+    int firstProtocolVersion;
+    int secondProtocolVersion;
+    Boolean showButtonBar;
+    Boolean icsEngineAnalyze; 
+
+    /* [AS] New properties (down to the "ZIPPY" part) */
+    Boolean firstScoreIsAbsolute;  /* If true, engine score is always from white side */
+    Boolean secondScoreIsAbsolute; /* If true, engine score is always from white side */
+    Boolean saveExtendedInfoInPGN; /* If true, saved PGN games contain extended info */
+    Boolean hideThinkingFromHuman; /* If true, program thinking is generated but not displayed in human/computer matches */
+    char * liteBackTextureFile; /* Name of texture bitmap for lite squares */
+    char * darkBackTextureFile; /* Name of texture bitmap for dark squares */
+    int liteBackTextureMode;
+    int darkBackTextureMode;
+    char * renderPiecesWithFont; /* Name of font for rendering chess pieces */
+    char * fontToPieceTable; /* Map to translate font character to chess pieces */
+    int fontBackColorWhite;
+    int fontForeColorWhite;
+    int fontBackColorBlack;
+    int fontForeColorBlack;
+    int fontPieceSize; /* Size of font relative to square (percentage) */
+    int overrideLineGap; /* If >= 0 overrides the lineGap value of the board size properties */
+    int adjudicateLossThreshold; /* Adjudicate a two-machine game if both engines agree the score is below this for 6 plies */
+    int delayBeforeQuit;
+    int delayAfterQuit;
+    char * nameOfDebugFile;
+    char * pgnEventHeader;
+    int defaultFrcPosition;
+    char * gameListTags;
+    Boolean saveOutOfBookInfo;
+    Boolean showEvalInMoveHistory;
+    int evalHistColorWhite;
+    int evalHistColorBlack;
+    Boolean highlightMoveWithArrow;
+    int highlightArrowColor;
+    Boolean useStickyWindows;
+    int adjudicateDrawMoves;
+    Boolean autoDisplayComment;
+    Boolean autoDisplayTags;
+    Boolean firstIsUCI;
+    Boolean secondIsUCI;
+    Boolean firstHasOwnBookUCI;
+    Boolean secondHasOwnBookUCI;
+    char * polyglotDir;
+    Boolean usePolyglotBook;
+    char * polyglotBook;
+    int defaultHashSize;
+    int defaultCacheSizeEGTB;
+    char * defaultPathEGTB;
+
+    /* [HGM] Board size */
+    int NrFiles;
+    int NrRanks;
+    int holdingsSize;
+    int matchPause;
+    char * pieceToCharTable;
+    Boolean allWhite;
+    Boolean upsideDown;
+    Boolean alphaRank;
+    Boolean testClaims;
+    Boolean checkMates;
+    Boolean materialDraws;
+    Boolean trivialDraws;
+    int ruleMoves;
+    int drawRepeats;
+
+#if ZIPPY
+    char *zippyLines;
+    char *zippyPinhead;
+    char *zippyPassword;
+    char *zippyPassword2;
+    char *zippyWrongPassword;
+    char *zippyAcceptOnly;
+    int zippyUseI;
+    int zippyBughouse;
+    int zippyNoplayCrafty;
+    char *zippyGameEnd;
+    char *zippyGameStart;
+    int zippyAdjourn;
+    int zippyAbort;
+    char *zippyVariants;
+    int zippyMaxGames;
+    int zippyReplayTimeout; /*seconds*/
+#endif
+
+    char *serverMovesName;
+    Boolean suppressLoadMoves;
+    int serverPause;
+    int firstTimeOdds;
+    int secondTimeOdds;
+    int timeOddsMode;
+    int firstAccumulateTC;
+    int secondAccumulateTC;
+    int firstNPS;
+    int secondNPS;
+    Boolean autoKibitz;
+    int engineComments;
+    char *userName;
+    int rewindIndex;    /* [HGM] autoinc   */
+    int sameColorGames; /* [HGM] alternate */
+    int smpCores;       /* [HGM] SMP       */
+    char *egtFormats;
+    int niceEngines;    /* [HGM] nice      */
+    char *firstLogo;    /* [HGM] logo      */
+    char *secondLogo;
+    Boolean autoLogo;
+    Boolean noGUI;      /* [HGM] fast: suppress all display updates */
+    char *firstOptions; /* [HGM] options   */
+    char *secondOptions;
+} AppData, *AppDataPtr;
+
+/* [AS] PGN tags (for showing in the game list) */
+#define GLT_EVENT           'e'
+#define GLT_SITE            's'
+#define GLT_DATE            'd'
+#define GLT_ROUND           'o'
+#define GLT_PLAYERS         'p'     /* I.e. white "-" black */
+#define GLT_RESULT          'r'
+#define GLT_WHITE_ELO       'w'
+#define GLT_BLACK_ELO       'b'
+#define GLT_TIME_CONTROL    't'
+#define GLT_VARIANT         'v'
+#define GLT_OUT_OF_BOOK     'a'
+
+#define GLT_DEFAULT_TAGS    "eprd"  /* Event, players, result, date */
+
+#define GLT_ALL_TAGS        "esdoprwbtva"
+
+#define PGN_OUT_OF_BOOK     "Annotator"
+
+extern AppData appData;
+
+typedef struct {
+    /* PGN 7-tag info */
+    char *event;
+    char *site;
+    char *date;
+    char *round;
+    char *white;
+    char *black;
+    ChessMove result;
+    /* Additional info */
+    char *fen;          /* NULL or FEN for starting position; input only */
+    char *resultDetails;
+    char *timeControl;
+    char *extraTags;    /* NULL or "[Tag \"Value\"]\n", etc. */
+    int whiteRating;    /* -1 if unknown */
+    int blackRating;    /* -1 if unknown */
+    VariantClass variant;
+    char *outOfBook;    /* [AS] Move and score when engine went out of book */
+    int boardWidth;     /* [HGM] adjustable board size */
+    int boardHeight;
+/* [HGM] For Shogi and Crazyhouse: */
+    int holdingsSize;  /* number of different piece types in holdings       */
+    int holdingsWidth; /* number of files left and right of board, 0 or 2   */
+} GameInfo;
+
+
+#endif
+
diff --git a/moves.c b/moves.c
index eb0701c..e58cfa0 100644 (file)
--- a/moves.c
+++ b/moves.c
-/*\r
- * moves.c - Move generation and checking\r
- * $Id: moves.c,v 2.1 2003/10/27 19:21:00 mann Exp $\r
- *\r
- * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.\r
- * Enhancements Copyright 1992-95 Free Software Foundation, Inc.\r
- *\r
- * The following terms apply to Digital Equipment Corporation's copyright\r
- * interest in XBoard:\r
- * ------------------------------------------------------------------------\r
- * All Rights Reserved\r
- *\r
- * Permission to use, copy, modify, and distribute this software and its\r
- * documentation for any purpose and without fee is hereby granted,\r
- * provided that the above copyright notice appear in all copies and that\r
- * both that copyright notice and this permission notice appear in\r
- * supporting documentation, and that the name of Digital not be\r
- * used in advertising or publicity pertaining to distribution of the\r
- * software without specific, written prior permission.\r
- *\r
- * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
- * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL\r
- * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
- * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\r
- * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\r
- * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\r
- * SOFTWARE.\r
- * ------------------------------------------------------------------------\r
- *\r
- * The following terms apply to the enhanced version of XBoard distributed\r
- * by the Free Software Foundation:\r
- * ------------------------------------------------------------------------\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
- * ------------------------------------------------------------------------\r
- */\r
-\r
-#include "config.h"\r
-\r
-#include <stdio.h>\r
-#if HAVE_STRING_H\r
-# include <string.h>\r
-#else /* not HAVE_STRING_H */\r
-# include <strings.h>\r
-#endif /* not HAVE_STRING_H */\r
-#include "common.h"\r
-#include "backend.h" \r
-#include "moves.h"\r
-#include "parser.h"\r
-\r
-int WhitePiece P((ChessSquare));\r
-int BlackPiece P((ChessSquare));\r
-int SameColor P((ChessSquare, ChessSquare));\r
-\r
-extern char initialRights[BOARD_SIZE]; /* [HGM] all rights enabled, set in InitPosition */\r
-\r
-\r
-int WhitePiece(piece)\r
-     ChessSquare piece;\r
-{\r
-    return (int) piece >= (int) WhitePawn && (int) piece < (int) BlackPawn;\r
-}\r
-\r
-int BlackPiece(piece)\r
-     ChessSquare piece;\r
-{\r
-    return (int) piece >= (int) BlackPawn && (int) piece < (int) EmptySquare;\r
-}\r
-\r
-int SameColor(piece1, piece2)\r
-     ChessSquare piece1, piece2;\r
-{\r
-    return ((int) piece1 >= (int) WhitePawn &&   /* [HGM] can be > King ! */\r
-            (int) piece1 <  (int) BlackPawn &&\r
-           (int) piece2 >= (int) WhitePawn &&\r
-            (int) piece2 <  (int) BlackPawn)\r
-      ||   ((int) piece1 >= (int) BlackPawn &&\r
-            (int) piece1 <  (int) EmptySquare &&\r
-           (int) piece2 >= (int) BlackPawn &&\r
-            (int) piece2 <  (int) EmptySquare);\r
-}\r
-\r
-ChessSquare PromoPiece(moveType)\r
-     ChessMove moveType;\r
-{\r
-    switch (moveType) {\r
-      default:\r
-       return EmptySquare;\r
-      case WhitePromotionQueen:\r
-       return WhiteQueen;\r
-      case BlackPromotionQueen:\r
-       return BlackQueen;\r
-      case WhitePromotionRook:\r
-       return WhiteRook;\r
-      case BlackPromotionRook:\r
-       return BlackRook;\r
-      case WhitePromotionBishop:\r
-       return WhiteBishop;\r
-      case BlackPromotionBishop:\r
-       return BlackBishop;\r
-      case WhitePromotionKnight:\r
-       return WhiteKnight;\r
-      case BlackPromotionKnight:\r
-       return BlackKnight;\r
-      case WhitePromotionKing:\r
-       return WhiteKing;\r
-      case BlackPromotionKing:\r
-       return BlackKing;\r
-      case WhitePromotionChancellor:\r
-        return WhiteMarshall;\r
-      case BlackPromotionChancellor:\r
-        return BlackMarshall;\r
-      case WhitePromotionArchbishop:\r
-        return WhiteAngel;\r
-      case BlackPromotionArchbishop:\r
-        return BlackAngel;\r
-      case WhitePromotionCentaur:\r
-        return WhiteSilver;\r
-      case BlackPromotionCentaur:\r
-        return BlackSilver;\r
-    }\r
-}\r
-\r
-char pieceToChar[] = {\r
-                        'P', 'N', 'B', 'R', 'Q', 'F', 'E', 'A', 'C', 'W', 'M', \r
-                        'O', 'H', 'I', 'J', 'G', 'D', 'V', 'L', 's', 'U', 'K',\r
-                        'p', 'n', 'b', 'r', 'q', 'f', 'e', 'a', 'c', 'w', 'm', \r
-                        'o', 'h', 'i', 'j', 'g', 'd', 'v', 'l', 's', 'u', 'k', \r
-                        'x' };\r
-\r
-char PieceToChar(p)\r
-     ChessSquare p;\r
-{\r
-    if((int)p < 0 || (int)p >= (int)EmptySquare) return('x'); /* [HGM] for safety */\r
-    return pieceToChar[(int) p];\r
-}\r
-\r
-int PieceToNumber(p)  /* [HGM] holdings: count piece type, ignoring non-participating piece types */\r
-     ChessSquare p;\r
-{\r
-    int i=0;\r
-    ChessSquare start = (int)p >= (int)BlackPawn ? BlackPawn : WhitePawn;\r
-\r
-    while(start++ != p) if(pieceToChar[(int)start-1] != '.') i++;\r
-    return i;\r
-}\r
-\r
-ChessSquare CharToPiece(c)\r
-     int c;\r
-{\r
-     int i;\r
-     for(i=0; i< (int) EmptySquare; i++)\r
-          if(pieceToChar[i] == c) return (ChessSquare) i;\r
-     return EmptySquare;\r
-}\r
-\r
-ChessMove PromoCharToMoveType(whiteOnMove, promoChar)\r
-     int whiteOnMove;\r
-     int promoChar;\r
-{      /* [HGM] made dependent on CharToPiece to alow alternate piece letters */\r
-       ChessSquare piece = CharToPiece(whiteOnMove ? ToUpper(promoChar) : ToLower(promoChar) );\r
-\r
-
-       if(promoChar == NULLCHAR) return NormalMove;\r
-\r
-       switch(piece) {\r
-               case WhiteQueen:\r
-                       return WhitePromotionQueen;\r
-               case WhiteRook:\r
-                       return WhitePromotionRook;\r
-               case WhiteBishop:\r
-                       return WhitePromotionBishop;\r
-               case WhiteKnight:\r
-                       return WhitePromotionKnight;\r
-               case WhiteKing:\r
-                       return WhitePromotionKing;\r
-               case WhiteAngel:\r
-                       return WhitePromotionArchbishop;\r
-               case WhiteMarshall:\r
-                       return WhitePromotionChancellor;\r
-               case WhiteSilver:\r
-                       return WhitePromotionCentaur;\r
-               case BlackQueen:\r
-                       return BlackPromotionQueen;\r
-               case BlackRook:\r
-                       return BlackPromotionRook;\r
-               case BlackBishop:\r
-                       return BlackPromotionBishop;\r
-               case BlackKnight:\r
-                       return BlackPromotionKnight;\r
-               case BlackKing:\r
-                       return BlackPromotionKing;\r
-               case BlackAngel:\r
-                       return BlackPromotionArchbishop;\r
-               case BlackMarshall:\r
-                       return BlackPromotionChancellor;\r
-               case BlackSilver:\r
-                       return BlackPromotionCentaur;\r
-               default:\r
-                       // not all promotion implemented yet! Take Queen for those we don't know.\r
-                       return (whiteOnMove ? WhitePromotionQueen : BlackPromotionQueen);\r
-       }\r
-}\r
-\r
-void CopyBoard(to, from)\r
-     Board to, from;\r
-{\r
-    int i, j;\r
-    \r
-    for (i = 0; i < BOARD_HEIGHT; i++)\r
-      for (j = 0; j < BOARD_WIDTH; j++)\r
-       to[i][j] = from[i][j];\r
-}\r
-\r
-int CompareBoards(board1, board2)\r
-     Board board1, board2;\r
-{\r
-    int i, j;\r
-    \r
-    for (i = 0; i < BOARD_HEIGHT; i++)\r
-      for (j = 0; j < BOARD_WIDTH; j++) {\r
-         if (board1[i][j] != board2[i][j])\r
-           return FALSE;\r
-    }\r
-    return TRUE;\r
-}\r
-\r
-\r
-/* Call callback once for each pseudo-legal move in the given\r
-   position, except castling moves. A move is pseudo-legal if it is\r
-   legal, or if it would be legal except that it leaves the king in\r
-   check.  In the arguments, epfile is EP_NONE if the previous move\r
-   was not a double pawn push, or the file 0..7 if it was, or\r
-   EP_UNKNOWN if we don't know and want to allow all e.p. captures.\r
-   Promotion moves generated are to Queen only.\r
-*/\r
-void GenPseudoLegal(board, flags, epfile, callback, closure)\r
-     Board board;\r
-     int flags;\r
-     int epfile;\r
-     MoveCallback callback;\r
-     VOIDSTAR closure;\r
-{\r
-    int rf, ff;\r
-    int i, j, d, s, fs, rs, rt, ft, m;\r
-\r
-    for (rf = 0; rf < BOARD_HEIGHT; rf++) \r
-      for (ff = BOARD_LEFT; ff < BOARD_RGHT; ff++) {\r
-          ChessSquare piece;\r
-\r
-         if (flags & F_WHITE_ON_MOVE) {\r
-             if (!WhitePiece(board[rf][ff])) continue;\r
-         } else {\r
-             if (!BlackPiece(board[rf][ff])) continue;\r
-         }\r
-          m = 0; piece = board[rf][ff];\r
-          if(PieceToChar(piece) == '~') \r
-                 piece = (ChessSquare) ( DEMOTED piece );\r
-          if(gameInfo.variant == VariantShogi)\r
-                 piece = (ChessSquare) ( SHOGI piece );\r
-\r
-          switch (piece) {\r
-            /* case EmptySquare: [HGM] this is nonsense, and conflicts with Shogi cases */\r
-           default:\r
-             /* can't happen ([HGM] except for faries...) */\r
-             break;\r
-\r
-             case WhitePawn:\r
-              if(gameInfo.variant == VariantXiangqi) {\r
-                  /* [HGM] capture and move straight ahead in Xiangqi */\r
-                  if (rf < BOARD_HEIGHT-1 &&\r
-                           !SameColor(board[rf][ff], board[rf + 1][ff]) ) {\r
-                           callback(board, flags, NormalMove,\r
-                                    rf, ff, rf + 1, ff, closure);\r
-                  }\r
-                  /* and move sideways when across the river */\r
-                  for (s = -1; s <= 1; s += 2) {\r
-                      if (rf >= BOARD_HEIGHT>>1 &&\r
-                          ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
-                          !WhitePiece(board[rf][ff+s]) ) {\r
-                           callback(board, flags, NormalMove,\r
-                                    rf, ff, rf, ff+s, closure);\r
-                      }\r
-                  }\r
-                  break;\r
-              }\r
-              if (rf < BOARD_HEIGHT-1 && board[rf + 1][ff] == EmptySquare) {\r
-                 callback(board, flags,\r
-                          rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,\r
-                          rf, ff, rf + 1, ff, closure);\r
-             }\r
-             if (rf == 1 && board[2][ff] == EmptySquare &&\r
-                  gameInfo.variant != VariantShatranj && /* [HGM] */\r
-                  gameInfo.variant != VariantCourier  && /* [HGM] */\r
-                  board[3][ff] == EmptySquare ) {\r
-                      callback(board, flags, NormalMove,\r
-                               rf, ff, 3, ff, closure);\r
-             }\r
-             for (s = -1; s <= 1; s += 2) {\r
-                  if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
-                     ((flags & F_KRIEGSPIEL_CAPTURE) ||\r
-                      BlackPiece(board[rf + 1][ff + s]))) {\r
-                     callback(board, flags, \r
-                              rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,\r
-                              rf, ff, rf + 1, ff + s, closure);\r
-                 }\r
-                 if (rf == BOARD_HEIGHT-4) {\r
-                      if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
-                         (epfile == ff + s || epfile == EP_UNKNOWN) &&\r
-                          board[BOARD_HEIGHT-4][ff + s] == BlackPawn &&\r
-                          board[BOARD_HEIGHT-3][ff + s] == EmptySquare) {\r
-                         callback(board, flags, WhiteCapturesEnPassant,\r
-                                  rf, ff, 5, ff + s, closure);\r
-                     }\r
-                 }\r
-             }             \r
-             break;\r
-\r
-           case BlackPawn:\r
-              if(gameInfo.variant == VariantXiangqi) {\r
-                  /* [HGM] capture straight ahead in Xiangqi */\r
-                  if (rf > 0 && !SameColor(board[rf][ff], board[rf - 1][ff]) ) {\r
-                           callback(board, flags, NormalMove,\r
-                                    rf, ff, rf - 1, ff, closure);\r
-                  }\r
-                  /* and move sideways when across the river */\r
-                  for (s = -1; s <= 1; s += 2) {\r
-                      if (rf < BOARD_HEIGHT>>1 &&\r
-                          ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
-                          !BlackPiece(board[rf][ff+s]) ) {\r
-                           callback(board, flags, NormalMove,\r
-                                    rf, ff, rf, ff+s, closure);\r
-                      }\r
-                  }\r
-                  break;\r
-              }\r
-             if (rf > 0 && board[rf - 1][ff] == EmptySquare) {\r
-                 callback(board, flags, \r
-                          rf == 1 ? BlackPromotionQueen : NormalMove,\r
-                          rf, ff, rf - 1, ff, closure);\r
-             }\r
-             if (rf == BOARD_HEIGHT-2 && board[BOARD_HEIGHT-3][ff] == EmptySquare &&\r
-                  gameInfo.variant != VariantShatranj && /* [HGM] */\r
-                  gameInfo.variant != VariantCourier  && /* [HGM] */\r
-                 board[BOARD_HEIGHT-4][ff] == EmptySquare) {\r
-                 callback(board, flags, NormalMove,\r
-                          rf, ff, BOARD_HEIGHT-4, ff, closure);\r
-             }\r
-             for (s = -1; s <= 1; s += 2) {\r
-                  if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
-                     ((flags & F_KRIEGSPIEL_CAPTURE) ||\r
-                      WhitePiece(board[rf - 1][ff + s]))) {\r
-                     callback(board, flags, \r
-                              rf == 1 ? BlackPromotionQueen : NormalMove,\r
-                              rf, ff, rf - 1, ff + s, closure);\r
-                 }\r
-                 if (rf == 3) {\r
-                      if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
-                         (epfile == ff + s || epfile == EP_UNKNOWN) &&\r
-                         board[3][ff + s] == WhitePawn &&\r
-                         board[2][ff + s] == EmptySquare) {\r
-                         callback(board, flags, BlackCapturesEnPassant,\r
-                                  rf, ff, 2, ff + s, closure);\r
-                     }\r
-                 }\r
-             }             \r
-             break;\r
-\r
-            case WhiteUnicorn:\r
-            case BlackUnicorn:\r
-           case WhiteKnight:\r
-           case BlackKnight:\r
-            mounted:\r
-             for (i = -1; i <= 1; i += 2)\r
-               for (j = -1; j <= 1; j += 2)\r
-                 for (s = 1; s <= 2; s++) {\r
-                     rt = rf + i*s;\r
-                     ft = ff + j*(3-s);\r
-                      if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)\r
-                          && ( gameInfo.variant != VariantXiangqi || board[rf+i*(s-1)][ff+j*(2-s)] == EmptySquare)\r
-                          && !SameColor(board[rf][ff], board[rt][ft]))\r
-                     callback(board, flags, NormalMove,\r
-                              rf, ff, rt, ft, closure);\r
-                 }\r
-             break;\r
-\r
-            case SHOGI WhiteKnight:\r
-             for (s = -1; s <= 1; s += 2) {\r
-                  if (rf < BOARD_HEIGHT-2 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
-                      !SameColor(board[rf][ff], board[rf + 2][ff + s])) {\r
-                      callback(board, flags, NormalMove,\r
-                               rf, ff, rf + 2, ff + s, closure);\r
-                 }\r
-              }\r
-             break;\r
-\r
-            case SHOGI BlackKnight:\r
-             for (s = -1; s <= 1; s += 2) {\r
-                  if (rf > 1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
-                      !SameColor(board[rf][ff], board[rf - 2][ff + s])) {\r
-                      callback(board, flags, NormalMove,\r
-                               rf, ff, rf - 2, ff + s, closure);\r
-                 }\r
-             }             \r
-             break;\r
-\r
-            case WhiteCannon:\r
-            case BlackCannon:\r
-              for (d = 0; d <= 1; d++)\r
-                for (s = -1; s <= 1; s += 2) {\r
-                  m = 0;\r
-                 for (i = 1;; i++) {\r
-                     rt = rf + (i * s) * d;\r
-                     ft = ff + (i * s) * (1 - d);\r
-                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;\r
-                      if (m == 0 && board[rt][ft] == EmptySquare)\r
-                                 callback(board, flags, NormalMove,\r
-                                          rf, ff, rt, ft, closure);\r
-                      if (m == 1 && board[rt][ft] != EmptySquare &&\r
-                          !SameColor(board[rf][ff], board[rt][ft]) )\r
-                                 callback(board, flags, NormalMove,\r
-                                          rf, ff, rt, ft, closure);\r
-                      if (board[rt][ft] != EmptySquare && m++) break;\r
-                  }\r
-                }\r
-             break;\r
-\r
-            /* Gold General (and all its promoted versions) . First do the */\r
-            /* diagonal forward steps, then proceed as normal Wazir        */\r
-            case SHOGI WhiteWazir:\r
-            case SHOGI (PROMOTED WhitePawn):\r
-            case SHOGI (PROMOTED WhiteKnight):\r
-            case SHOGI (PROMOTED WhiteQueen):\r
-            case SHOGI (PROMOTED WhiteFerz):\r
-             for (s = -1; s <= 1; s += 2) {\r
-                  if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
-                      !SameColor(board[rf][ff], board[rf + 1][ff + s])) {\r
-                      callback(board, flags, NormalMove,\r
-                              rf, ff, rf + 1, ff + s, closure);\r
-                 }\r
-              }\r
-              goto finishGold;\r
-\r
-            case SHOGI BlackWazir:\r
-            case SHOGI (PROMOTED BlackPawn):\r
-            case SHOGI (PROMOTED BlackKnight):\r
-            case SHOGI (PROMOTED BlackQueen):\r
-            case SHOGI (PROMOTED BlackFerz):\r
-             for (s = -1; s <= 1; s += 2) {\r
-                  if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
-                      !SameColor(board[rf][ff], board[rf - 1][ff + s])) {\r
-                      callback(board, flags, NormalMove,\r
-                              rf, ff, rf - 1, ff + s, closure);\r
-                 }\r
-             }             \r
-\r
-            case WhiteWazir:\r
-            case BlackWazir:\r
-            finishGold:\r
-              for (d = 0; d <= 1; d++)\r
-                for (s = -1; s <= 1; s += 2) {\r
-                      rt = rf + s * d;\r
-                      ft = ff + s * (1 - d);\r
-                      if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)\r
-                          && !SameColor(board[rf][ff], board[rt][ft]) &&\r
-                          (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) )\r
-                               callback(board, flags, NormalMove,\r
-                                        rf, ff, rt, ft, closure);\r
-                      }\r
-             break;\r
-\r
-            case WhiteAlfil:\r
-            case BlackAlfil:\r
-                /* [HGM] support Shatranj pieces */\r
-                for (rs = -1; rs <= 1; rs += 2) \r
-                  for (fs = -1; fs <= 1; fs += 2) {\r
-                      rt = rf + 2 * rs;\r
-                      ft = ff + 2 * fs;\r
-                      if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)\r
-                          && ( gameInfo.variant != VariantXiangqi ||\r
-                               board[rf+rs][ff+fs] == EmptySquare && (2*rf < BOARD_HEIGHT) == (2*rt < BOARD_HEIGHT) )\r
-                         \r
-                          && !SameColor(board[rf][ff], board[rt][ft]))\r
-                               callback(board, flags, NormalMove,\r
-                                        rf, ff, rt, ft, closure);\r
-                 }\r
-                break;\r
-\r
-            /* Shogi Dragon Horse has to continue with Wazir after Bishop */\r
-            case SHOGI WhiteCardinal:\r
-            case SHOGI BlackCardinal:\r
-              m++;\r
-\r
-            /* Capablanca Archbishop continues as Knight                  */\r
-            case WhiteAngel:\r
-            case BlackAngel:\r
-              m++;\r
-\r
-            /* Shogi Bishops are ordinary Bishops */\r
-            case SHOGI WhiteBishop:\r
-            case SHOGI BlackBishop:\r
-           case WhiteBishop:\r
-           case BlackBishop:\r
-             for (rs = -1; rs <= 1; rs += 2) \r
-                for (fs = -1; fs <= 1; fs += 2) \r
-                 for (i = 1;; i++) {\r
-                     rt = rf + (i * rs);\r
-                     ft = ff + (i * fs);\r
-                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;\r
-                     if (SameColor(board[rf][ff], board[rt][ft])) break;\r
-                     callback(board, flags, NormalMove,\r
-                              rf, ff, rt, ft, closure);\r
-                     if (board[rt][ft] != EmptySquare) break;\r
-                 }\r
-                if(m==1) goto mounted;\r
-                if(m==2) goto finishGold;\r
-                /* Bishop falls through */\r
-             break;\r
-\r
-            /* Shogi Lance is unlike anything, and asymmetric at that */\r
-            case SHOGI WhiteQueen:\r
-              for(i = 1;; i++) {\r
-                      rt = rf + i;\r
-                      ft = ff;\r
-                      if (rt >= BOARD_HEIGHT) break;\r
-                     if (SameColor(board[rf][ff], board[rt][ft])) break;\r
-                     callback(board, flags, NormalMove,\r
-                              rf, ff, rt, ft, closure);\r
-                      if (board[rt][ft] != EmptySquare) break;\r
-              }\r
-              break;\r
-\r
-            case SHOGI BlackQueen:\r
-              for(i = 1;; i++) {\r
-                      rt = rf - i;\r
-                      ft = ff;\r
-                      if (rt < 0) break;\r
-                     if (SameColor(board[rf][ff], board[rt][ft])) break;\r
-                     callback(board, flags, NormalMove,\r
-                              rf, ff, rt, ft, closure);\r
-                      if (board[rt][ft] != EmptySquare) break;\r
-              }\r
-              break;\r
-\r
-            /* Shogi Dragon King has to continue as Ferz after Rook moves */\r
-            case SHOGI WhiteDragon:\r
-            case SHOGI BlackDragon:\r
-              m++;\r
-\r
-            /* Capablanca Chancellor sets flag to continue as Knight      */\r
-            case WhiteMarshall:\r
-            case BlackMarshall:\r
-              m++;\r
-\r
-            /* Shogi Rooks are ordinary Rooks */\r
-            case SHOGI WhiteRook:\r
-            case SHOGI BlackRook:\r
-           case WhiteRook:\r
-           case BlackRook:\r
-              for (d = 0; d <= 1; d++)\r
-                for (s = -1; s <= 1; s += 2)\r
-                 for (i = 1;; i++) {\r
-                     rt = rf + (i * s) * d;\r
-                     ft = ff + (i * s) * (1 - d);\r
-                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;\r
-                     if (SameColor(board[rf][ff], board[rt][ft])) break;\r
-                     callback(board, flags, NormalMove,\r
-                              rf, ff, rt, ft, closure);\r
-                     if (board[rt][ft] != EmptySquare) break;\r
-                 }\r
-                if(m==1) goto mounted;\r
-                if(m==2) goto finishGold;\r
-             break;\r
-\r
-           case WhiteQueen:\r
-           case BlackQueen:\r
-             for (rs = -1; rs <= 1; rs++) \r
-               for (fs = -1; fs <= 1; fs++) {\r
-                   if (rs == 0 && fs == 0) continue;\r
-                   for (i = 1;; i++) {\r
-                       rt = rf + (i * rs);\r
-                       ft = ff + (i * fs);\r
-                        if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;\r
-                       if (SameColor(board[rf][ff], board[rt][ft])) break;\r
-                       callback(board, flags, NormalMove,\r
-                                rf, ff, rt, ft, closure);\r
-                       if (board[rt][ft] != EmptySquare) break;\r
-                   }\r
-               }\r
-             break;\r
-\r
-            /* Shogi Pawn and Silver General: first the Pawn move,    */\r
-            /* then the General continues like a Ferz                 */\r
-            case SHOGI WhitePawn:\r
-            case SHOGI WhiteFerz:\r
-                  if (rf < BOARD_HEIGHT-1 &&\r
-                           !SameColor(board[rf][ff], board[rf + 1][ff]) ) \r
-                           callback(board, flags, NormalMove,\r
-                                    rf, ff, rf + 1, ff, closure);\r
-              if(piece != SHOGI WhitePawn) goto finishSilver;\r
-              break;\r
-\r
-            case SHOGI BlackPawn:\r
-            case SHOGI BlackFerz:\r
-                  if (rf > 0 &&\r
-                           !SameColor(board[rf][ff], board[rf - 1][ff]) ) \r
-                           callback(board, flags, NormalMove,\r
-                                    rf, ff, rf - 1, ff, closure);\r
-              if(piece == SHOGI BlackPawn) break;\r
-\r
-            case WhiteFerz:\r
-            case BlackFerz:\r
-            finishSilver:\r
-                /* [HGM] support Shatranj pieces */\r
-                for (rs = -1; rs <= 1; rs += 2) \r
-                  for (fs = -1; fs <= 1; fs += 2) {\r
-                      rt = rf + rs;\r
-                      ft = ff + fs;\r
-                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;\r
-                      if (!SameColor(board[rf][ff], board[rt][ft]) &&\r
-                          (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) )\r
-                               callback(board, flags, NormalMove,\r
-                                        rf, ff, rt, ft, closure);\r
-                 }\r
-                break;\r
-\r
-           case WhiteSilver:\r
-           case BlackSilver:\r
-               m++; // [HGM] superchess: use for Centaur\r
-            case WhiteMan:\r
-            case BlackMan:\r
-            case SHOGI WhiteKing:\r
-            case SHOGI BlackKing:\r
-           case WhiteKing:\r
-           case BlackKing:\r
-            walking:\r
-             for (i = -1; i <= 1; i++)\r
-               for (j = -1; j <= 1; j++) {\r
-                   if (i == 0 && j == 0) continue;\r
-                   rt = rf + i;\r
-                   ft = ff + j;\r
-                    if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;\r
-                   if (SameColor(board[rf][ff], board[rt][ft])) continue;\r
-                   callback(board, flags, NormalMove,\r
-                            rf, ff, rt, ft, closure);\r
-               }\r
-               if(m==1) goto mounted;\r
-             break;\r
-\r
-           case WhiteNightrider:\r
-           case BlackNightrider:\r
-             for (i = -1; i <= 1; i += 2)\r
-               for (j = -1; j <= 1; j += 2)\r
-                 for (s = 1; s <= 2; s++) {  int k;\r
-                    for(k=1;; k++) {\r
-                     rt = rf + k*i*s;\r
-                     ft = ff + k*j*(3-s);\r
-                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;\r
-                     if (SameColor(board[rf][ff], board[rt][ft])) break;\r
-                     callback(board, flags, NormalMove,\r
-                              rf, ff, rt, ft, closure);\r
-                     if (board[rt][ft] != EmptySquare) break;\r
-                    }\r
-                 }\r
-             break;\r
-\r
-         }\r
-      }\r
-}\r
-\r
-\r
-typedef struct {\r
-    MoveCallback cb;\r
-    VOIDSTAR cl;\r
-} GenLegalClosure;\r
-\r
-extern void GenLegalCallback P((Board board, int flags, ChessMove kind,\r
-                               int rf, int ff, int rt, int ft,\r
-                               VOIDSTAR closure));\r
-\r
-void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
-     Board board;\r
-     int flags;\r
-     ChessMove kind;\r
-     int rf, ff, rt, ft;\r
-     VOIDSTAR closure;\r
-{\r
-    register GenLegalClosure *cl = (GenLegalClosure *) closure;\r
-\r
-    if (!(flags & F_IGNORE_CHECK) &&\r
-       CheckTest(board, flags, rf, ff, rt, ft,\r
-                 kind == WhiteCapturesEnPassant ||\r
-                 kind == BlackCapturesEnPassant)) return;\r
-    if (flags & F_ATOMIC_CAPTURE) {\r
-      if (board[rt][ft] != EmptySquare ||\r
-         kind == WhiteCapturesEnPassant || kind == BlackCapturesEnPassant) {\r
-       int r, f;\r
-       ChessSquare king = (flags & F_WHITE_ON_MOVE) ? WhiteKing : BlackKing;\r
-       if (board[rf][ff] == king) return;\r
-       for (r = rt-1; r <= rt+1; r++) {\r
-         for (f = ft-1; f <= ft+1; f++) {\r
-            if (r >= 0 && r < BOARD_HEIGHT && f >= BOARD_LEFT && f < BOARD_RGHT &&\r
-               board[r][f] == king) return;\r
-         }\r
-       }\r
-      }\r
-    }\r
-    cl->cb(board, flags, kind, rf, ff, rt, ft, cl->cl);\r
-}\r
-\r
-\r
-typedef struct {\r
-    int rf, ff, rt, ft;\r
-    ChessMove kind;\r
-} LegalityTestClosure;\r
-\r
-\r
-/* Like GenPseudoLegal, but (1) include castling moves, (2) unless\r
-   F_IGNORE_CHECK is set in the flags, omit moves that would leave the\r
-   king in check, and (3) if F_ATOMIC_CAPTURE is set in the flags, omit\r
-   moves that would destroy your own king.  The CASTLE_OK flags are\r
-   true if castling is not yet ruled out by a move of the king or\r
-   rook.  Return TRUE if the player on move is currently in check and\r
-   F_IGNORE_CHECK is not set.  [HGM] add castlingRights parameter */\r
-int GenLegal(board, flags, epfile, castlingRights, callback, closure)\r
-     Board board;\r
-     int flags;\r
-     int epfile;\r
-     char castlingRights[];\r
-     MoveCallback callback;\r
-     VOIDSTAR closure;\r
-{\r
-    GenLegalClosure cl;\r
-    int ff, ft, k, left, right;\r
-    int ignoreCheck = (flags & F_IGNORE_CHECK) != 0;\r
-    ChessSquare wKing = WhiteKing, bKing = BlackKing;\r
-\r
-    cl.cb = callback;\r
-    cl.cl = closure;\r
-    GenPseudoLegal(board, flags, epfile, GenLegalCallback, (VOIDSTAR) &cl);\r
-\r
-    if (!ignoreCheck &&\r
-       CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE;\r
-\r
-    /* Generate castling moves */\r
-    if(gameInfo.variant == VariantKnightmate) { /* [HGM] Knightmate */\r
-        wKing = WhiteUnicorn; bKing = BlackUnicorn;\r
-    }\r
-\r
-    for (ff = BOARD_WIDTH>>1; ff >= (BOARD_WIDTH-1)>>1; ff-- /*ics wild 1*/) {\r
-       if ((flags & F_WHITE_ON_MOVE) &&\r
-           (flags & F_WHITE_KCASTLE_OK) &&\r
-            board[0][ff] == wKing &&\r
-            board[0][ff + 1] == EmptySquare &&\r
-            board[0][ff + 2] == EmptySquare &&\r
-            board[0][BOARD_RGHT-3] == EmptySquare &&\r
-            board[0][BOARD_RGHT-2] == EmptySquare &&\r
-            board[0][BOARD_RGHT-1] == WhiteRook &&\r
-            castlingRights[0] >= 0 && /* [HGM] check rights */\r
-            ( castlingRights[2] == ff || castlingRights[6] == ff ) &&\r
-            (ignoreCheck ||                             \r
-            (!CheckTest(board, flags, 0, ff, 0, ff + 1, FALSE) &&\r
-              !CheckTest(board, flags, 0, ff, 0, BOARD_RGHT-3, FALSE) &&\r
-              (gameInfo.variant != VariantJanus || !CheckTest(board, flags, 0, ff, 0, BOARD_RGHT-2, FALSE)) &&\r
-             !CheckTest(board, flags, 0, ff, 0, ff + 2, FALSE)))) {\r
-\r
-           callback(board, flags,\r
-                     ff==BOARD_WIDTH>>1 ? WhiteKingSideCastle : WhiteKingSideCastleWild,\r
-                     0, ff, 0, ff + ((gameInfo.boardWidth+2)>>2) + (gameInfo.variant == VariantJanus), closure);\r
-       }\r
-       if ((flags & F_WHITE_ON_MOVE) &&\r
-           (flags & F_WHITE_QCASTLE_OK) &&\r
-            board[0][ff] == wKing &&\r
-           board[0][ff - 1] == EmptySquare &&\r
-           board[0][ff - 2] == EmptySquare &&\r
-            board[0][BOARD_LEFT+2] == EmptySquare &&\r
-            board[0][BOARD_LEFT+1] == EmptySquare &&\r
-            board[0][BOARD_LEFT+0] == WhiteRook &&\r
-            castlingRights[1] >= 0 && /* [HGM] check rights */\r
-            ( castlingRights[2] == ff || castlingRights[6] == ff ) &&\r
-           (ignoreCheck ||\r
-            (!CheckTest(board, flags, 0, ff, 0, ff - 1, FALSE) &&\r
-              !CheckTest(board, flags, 0, ff, 0, BOARD_LEFT+3, FALSE) &&\r
-             !CheckTest(board, flags, 0, ff, 0, ff - 2, FALSE)))) {\r
-\r
-           callback(board, flags,\r
-                    ff==BOARD_WIDTH>>1 ? WhiteQueenSideCastle : WhiteQueenSideCastleWild,\r
-                     0, ff, 0, ff - ((gameInfo.boardWidth+2)>>2), closure);\r
-       }\r
-       if (!(flags & F_WHITE_ON_MOVE) &&\r
-           (flags & F_BLACK_KCASTLE_OK) &&\r
-            board[BOARD_HEIGHT-1][ff] == bKing &&\r
-           board[BOARD_HEIGHT-1][ff + 1] == EmptySquare &&\r
-           board[BOARD_HEIGHT-1][ff + 2] == EmptySquare &&\r
-            board[BOARD_HEIGHT-1][BOARD_RGHT-3] == EmptySquare &&\r
-            board[BOARD_HEIGHT-1][BOARD_RGHT-2] == EmptySquare &&\r
-            board[BOARD_HEIGHT-1][BOARD_RGHT-1] == BlackRook &&\r
-            castlingRights[3] >= 0 && /* [HGM] check rights */\r
-            ( castlingRights[5] == ff || castlingRights[7] == ff ) &&\r
-           (ignoreCheck ||\r
-            (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 1, FALSE) &&\r
-              !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_RGHT-3, FALSE) &&\r
-              (gameInfo.variant != VariantJanus || !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_RGHT-2, FALSE)) &&\r
-             !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 2, FALSE)))) {\r
-\r
-           callback(board, flags,\r
-                    ff==BOARD_WIDTH>>1 ? BlackKingSideCastle : BlackKingSideCastleWild,\r
-                     BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + ((gameInfo.boardWidth+2)>>2) + (gameInfo.variant == VariantJanus), closure);\r
-       }\r
-       if (!(flags & F_WHITE_ON_MOVE) &&\r
-           (flags & F_BLACK_QCASTLE_OK) &&\r
-            board[BOARD_HEIGHT-1][ff] == bKing &&\r
-           board[BOARD_HEIGHT-1][ff - 1] == EmptySquare &&\r
-           board[BOARD_HEIGHT-1][ff - 2] == EmptySquare &&\r
-            board[BOARD_HEIGHT-1][BOARD_LEFT+2] == EmptySquare &&\r
-            board[BOARD_HEIGHT-1][BOARD_LEFT+1] == EmptySquare &&\r
-            board[BOARD_HEIGHT-1][BOARD_LEFT+0] == BlackRook &&\r
-            castlingRights[4] >= 0 && /* [HGM] check rights */\r
-            ( castlingRights[5] == ff || castlingRights[7] == ff ) &&\r
-           (ignoreCheck ||\r
-            (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE) &&\r
-              !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_LEFT+3, FALSE) &&\r
-              !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 2, FALSE)))) {\r
-\r
-           callback(board, flags,\r
-                    ff==BOARD_WIDTH>>1 ? BlackQueenSideCastle : BlackQueenSideCastleWild,\r
-                     BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - ((gameInfo.boardWidth+2)>>2), closure);\r
-       }\r
-    }\r
-\r
-  if(gameInfo.variant == VariantFischeRandom) {\r
-\r
-    /* generate all potential FRC castling moves (KxR), ignoring flags */\r
-    /* [HGM] test if the Rooks we find have castling rights */\r
-\r
-\r
-    if ((flags & F_WHITE_ON_MOVE) != 0) {\r
-        ff = castlingRights[2]; /* King file if we have any rights */\r
-        if(ff > 0 && board[0][ff] == WhiteKing) {\r
-    if (appData.debugMode) {\r
-        fprintf(debugFP, "FRC castling, %d %d %d %d %d %d\n",\r
-                castlingRights[0],castlingRights[1],ff,castlingRights[3],castlingRights[4],castlingRights[5]);\r
-    }\r
-            ft = castlingRights[0]; /* Rook file if we have H-side rights */\r
-            left  = ff+1;\r
-            right = BOARD_RGHT-2;\r
-            if(ff == BOARD_RGHT-2) left = right = ff-1;    /* special case */\r
-            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */\r
-                if(k != ft && board[0][k] != EmptySquare) ft = -1;\r
-            for(k=left; k<right && ft >= 0; k++) /* then if not checked */\r
-                if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = -1;\r
-            if(ft >= 0 && board[0][ft] == WhiteRook)\r
-                callback(board, flags, WhiteHSideCastleFR, 0, ff, 0, ft, closure);\r
-\r
-            ft = castlingRights[1]; /* Rook file if we have A-side rights */\r
-            left  = BOARD_LEFT+2;\r
-            right = ff-1;\r
-            if(ff <= BOARD_LEFT+2) { left = ff+1; right = BOARD_LEFT+3; }\r
-            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */\r
-                if(k != ft && board[0][k] != EmptySquare) ft = -1;\r
-            if(ff > BOARD_LEFT+2) \r
-            for(k=left+1; k<=right && ft >= 0; k++) /* then if not checked */\r
-                if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = -1;\r
-            if(ft >= 0 && board[0][ft] == WhiteRook)\r
-                callback(board, flags, WhiteASideCastleFR, 0, ff, 0, ft, closure);\r
-        }\r
-    } else {\r
-        ff = castlingRights[5]; /* King file if we have any rights */\r
-        if(ff > 0 && board[BOARD_HEIGHT-1][ff] == BlackKing) {\r
-            ft = castlingRights[3]; /* Rook file if we have H-side rights */\r
-            left  = ff+1;\r
-            right = BOARD_RGHT-2;\r
-            if(ff == BOARD_RGHT-2) left = right = ff-1;    /* special case */\r
-            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */\r
-                if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = -1;\r
-            for(k=left; k<right && ft >= 0; k++) /* then if not checked */\r
-                if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = -1;\r
-            if(ft >= 0 && board[BOARD_HEIGHT-1][ft] == BlackRook)\r
-                callback(board, flags, BlackHSideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);\r
-\r
-            ft = castlingRights[4]; /* Rook file if we have A-side rights */\r
-            left  = BOARD_LEFT+2;\r
-            right = ff-1;\r
-            if(ff <= BOARD_LEFT+2) { left = ff+1; right = BOARD_LEFT+3; }\r
-            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */\r
-                if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = -1;\r
-            if(ff > BOARD_LEFT+2) \r
-            for(k=left+1; k<=right && ft >= 0; k++) /* then if not checked */\r
-                if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = -1;\r
-            if(ft >= 0 && board[BOARD_HEIGHT-1][ft] == BlackRook)\r
-                callback(board, flags, BlackASideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);\r
-        }\r
-    }\r
-\r
-  }\r
-\r
-    return FALSE;\r
-}\r
-\r
-\r
-typedef struct {\r
-    int rking, fking;\r
-    int check;\r
-} CheckTestClosure;\r
-\r
-\r
-extern void CheckTestCallback P((Board board, int flags, ChessMove kind,\r
-                                int rf, int ff, int rt, int ft,\r
-                                VOIDSTAR closure));\r
-\r
-\r
-void CheckTestCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
-     Board board;\r
-     int flags;\r
-     ChessMove kind;\r
-     int rf, ff, rt, ft;\r
-     VOIDSTAR closure;\r
-{\r
-    register CheckTestClosure *cl = (CheckTestClosure *) closure;\r
-\r
-    if (rt == cl->rking && ft == cl->fking) cl->check++;\r
-}\r
-\r
-\r
-/* If the player on move were to move from (rf, ff) to (rt, ft), would\r
-   he leave himself in check?  Or if rf == -1, is the player on move\r
-   in check now?  enPassant must be TRUE if the indicated move is an\r
-   e.p. capture.  The possibility of castling out of a check along the\r
-   back rank is not accounted for (i.e., we still return nonzero), as\r
-   this is illegal anyway.  Return value is the number of times the\r
-   king is in check. */ \r
-int CheckTest(board, flags, rf, ff, rt, ft, enPassant)\r
-     Board board;\r
-     int flags;\r
-     int rf, ff, rt, ft, enPassant;\r
-{\r
-    CheckTestClosure cl;\r
-    ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing;\r
-    ChessSquare captured = EmptySquare;\r
-    /*  Suppress warnings on uninitialized variables    */\r
-\r
-    if(gameInfo.variant == VariantXiangqi)\r
-        king = flags & F_WHITE_ON_MOVE ? WhiteWazir : BlackWazir;\r
-    if(gameInfo.variant == VariantKnightmate)\r
-        king = flags & F_WHITE_ON_MOVE ? WhiteUnicorn : BlackUnicorn;\r
-\r
-    if (rf >= 0) {\r
-       if (enPassant) {\r
-           captured = board[rf][ft];\r
-           board[rf][ft] = EmptySquare;\r
-       } else {\r
-           captured = board[rt][ft];\r
-       }\r
-       board[rt][ft] = board[rf][ff];\r
-       board[rf][ff] = EmptySquare;\r
-    }\r
-\r
-    /* For compatibility with ICS wild 9, we scan the board in the\r
-       order a1, a2, a3, ... b1, b2, ..., h8 to find the first king,\r
-       and we test only whether that one is in check. */\r
-    cl.check = 0;\r
-    for (cl.fking = BOARD_LEFT+0; cl.fking < BOARD_RGHT; cl.fking++)\r
-       for (cl.rking = 0; cl.rking < BOARD_HEIGHT; cl.rking++) {\r
-          if (board[cl.rking][cl.fking] == king) {\r
-              if(gameInfo.variant == VariantXiangqi) {\r
-                  /* [HGM] In Xiangqi opposing Kings means check as well */\r
-                  int i, dir;\r
-                  dir = (king >= BlackPawn) ? -1 : 1;\r
-                  for( i=cl.rking+dir; i>=0 && i<BOARD_HEIGHT &&\r
-                                board[i][cl.fking] == EmptySquare; i+=dir );\r
-                  if(i>=0 && i<BOARD_HEIGHT &&\r
-                      board[i][cl.fking] == (dir>0 ? BlackWazir : WhiteWazir) )\r
-                          cl.check++;\r
-              }\r
-\r
-             GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, -1,\r
-                            CheckTestCallback, (VOIDSTAR) &cl);\r
-             goto undo_move;  /* 2-level break */\r
-         }\r
-      }\r
-\r
-  undo_move:\r
-\r
-    if (rf >= 0) {\r
-       board[rf][ff] = board[rt][ft];\r
-       if (enPassant) {\r
-           board[rf][ft] = captured;\r
-           board[rt][ft] = EmptySquare;\r
-       } else {\r
-           board[rt][ft] = captured;\r
-       }\r
-    }\r
-\r
-    return cl.check;\r
-}\r
-\r
-\r
-extern void LegalityTestCallback P((Board board, int flags, ChessMove kind,\r
-                                   int rf, int ff, int rt, int ft,\r
-                                   VOIDSTAR closure));\r
-\r
-void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
-     Board board;\r
-     int flags;\r
-     ChessMove kind;\r
-     int rf, ff, rt, ft;\r
-     VOIDSTAR closure;\r
-{\r
-    register LegalityTestClosure *cl = (LegalityTestClosure *) closure;\r
-\r
-//    if (appData.debugMode) {\r
-//        fprintf(debugFP, "Legality test: %c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE);\r
-//    }\r
-    if (rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft)\r
-      cl->kind = kind;\r
-}\r
-\r
-ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, promoChar)\r
-     Board board;\r
-     int flags, epfile;\r
-     int rf, ff, rt, ft, promoChar;\r
-     char castlingRights[];\r
-{\r
-    LegalityTestClosure cl; ChessSquare piece = board[rf][ff];\r
-    \r
-    if (appData.debugMode) {\r
-        int i;\r
-        for(i=0; i<6; i++) fprintf(debugFP, "%d ", castlingRights[i]);\r
-        fprintf(debugFP, "Legality test? %c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE);\r
-    }\r
-    /* [HGM] Lance, Cobra and Falcon are wildcard pieces; consider all their moves legal */\r
-    /* (perhaps we should disallow moves that obviously leave us in check?)              */\r
-    if(piece == WhiteFalcon || piece == BlackFalcon ||\r
-       piece == WhiteCobra  || piece == BlackCobra  ||\r
-       piece == WhiteLance  || piece == BlackLance)\r
-        return NormalMove;\r
-\r
-    cl.rf = rf;\r
-    cl.ff = ff;\r
-    cl.rt = rt;\r
-    cl.ft = ft;\r
-    cl.kind = IllegalMove;\r
-    GenLegal(board, flags, epfile, castlingRights, LegalityTestCallback, (VOIDSTAR) &cl);\r
-\r
-    if(gameInfo.variant == VariantShogi) {\r
-        /* [HGM] Shogi promotions. '=' means defer */\r
-        if(rf != DROP_RANK && cl.kind == NormalMove) {\r
-            ChessSquare piece = board[rf][ff];\r
-\r
-            if(promoChar == PieceToChar(BlackQueen)) promoChar = NULLCHAR; /* [HGM] Kludge */\r
-            if(promoChar != NULLCHAR && promoChar != 'x' &&\r
-               promoChar != '+' && promoChar != '=' &&\r
-               ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(promoChar) )\r
-                    cl.kind = IllegalMove;\r
-            else if(flags & F_WHITE_ON_MOVE) {\r
-                if( (int) piece < (int) WhiteWazir &&\r
-                     (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) {\r
-                    if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||\r
-                         piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */\r
-                             cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight;\r
-                    else /* promotion optional, default is promote */\r
-                             cl.kind = promoChar == '=' ? NormalMove  : WhitePromotionQueen;\r
-                   \r
-                } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
-                                            NormalMove : IllegalMove;\r
-            } else {\r
-                if( (int) piece < (int) BlackWazir && (rf < 3 || rt < 3) ) {\r
-                    if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||\r
-                         piece == BlackKnight && rt < 2 ) /* promotion obligatory */\r
-                             cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight;\r
-                    else /* promotion optional, default is promote */\r
-                             cl.kind = promoChar == '=' ? NormalMove  : BlackPromotionQueen;\r
-\r
-                } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
-                                            NormalMove : IllegalMove;\r
-            }\r
-        }\r
-    } else\r
-    if (promoChar != NULLCHAR && promoChar != 'x') {\r
-       if(promoChar == '=') cl.kind = IllegalMove; else // [HGM] shogi: no deferred promotion outside Shogi\r
-       if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {\r
-           cl.kind = \r
-             PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0, promoChar);\r
-       } else {\r
-           cl.kind = IllegalMove;\r
-       }\r
-    }\r
-    /* [HGM] For promotions, 'ToQueen' = optional, 'ToKnight' = mandatory */\r
-    return cl.kind;\r
-}\r
-\r
-typedef struct {\r
-    int count;\r
-} MateTestClosure;\r
-\r
-extern void MateTestCallback P((Board board, int flags, ChessMove kind,\r
-                               int rf, int ff, int rt, int ft,\r
-                               VOIDSTAR closure));\r
-\r
-void MateTestCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
-     Board board;\r
-     int flags;\r
-     ChessMove kind;\r
-     int rf, ff, rt, ft;\r
-     VOIDSTAR closure;\r
-{\r
-    register MateTestClosure *cl = (MateTestClosure *) closure;\r
-\r
-    cl->count++;\r
-}\r
-\r
-/* Return MT_NONE, MT_CHECK, MT_CHECKMATE, or MT_STALEMATE */\r
-int MateTest(board, flags, epfile, castlingRights)\r
-     Board board;\r
-     int flags, epfile;\r
-     char castlingRights[];\r
-{\r
-    MateTestClosure cl;\r
-    int inCheck;\r
-\r
-    cl.count = 0;\r
-    inCheck = GenLegal(board, flags, epfile, castlingRights, MateTestCallback, (VOIDSTAR) &cl);\r
-    if (cl.count > 0) {\r
-       return inCheck ? MT_CHECK : MT_NONE;\r
-    } else {\r
-        return inCheck || gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj ?\r
-                         MT_CHECKMATE : MT_STALEMATE;\r
-    }\r
-}\r
-\r
-     \r
-extern void DisambiguateCallback P((Board board, int flags, ChessMove kind,\r
-                                   int rf, int ff, int rt, int ft,\r
-                                   VOIDSTAR closure));\r
-\r
-void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
-     Board board;\r
-     int flags;\r
-     ChessMove kind;\r
-     int rf, ff, rt, ft;\r
-     VOIDSTAR closure;\r
-{\r
-    register DisambiguateClosure *cl = (DisambiguateClosure *) closure;\r
-\r
-    if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]\r
-         || PieceToChar(board[rf][ff]) == '~'\r
-              && cl->pieceIn == (ChessSquare)(DEMOTED board[rf][ff])\r
-                                                                      ) &&\r
-       (cl->rfIn == -1 || cl->rfIn == rf) &&\r
-       (cl->ffIn == -1 || cl->ffIn == ff) &&\r
-       (cl->rtIn == -1 || cl->rtIn == rt) &&\r
-       (cl->ftIn == -1 || cl->ftIn == ft)) {\r
-\r
-       cl->count++;\r
-        cl->piece = board[rf][ff];\r
-       cl->rf = rf;\r
-       cl->ff = ff;\r
-       cl->rt = rt;\r
-       cl->ft = ft;\r
-       cl->kind = kind;\r
-    }\r
-}\r
-\r
-void Disambiguate(board, flags, epfile, closure)\r
-     Board board;\r
-     int flags, epfile;\r
-     DisambiguateClosure *closure;\r
-{\r
-    int illegal = 0; char c = closure->promoCharIn;\r
-    closure->count = 0;\r
-    closure->rf = closure->ff = closure->rt = closure->ft = 0;\r
-    closure->kind = ImpossibleMove;\r
-    if (appData.debugMode) {\r
-        fprintf(debugFP, "Disambiguate in:  %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
-                             closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,\r
-                             closure->promoCharIn, closure->promoCharIn >= ' ' ? closure->promoCharIn : '-');\r
-    }\r
-    GenLegal(board, flags, epfile, initialRights, DisambiguateCallback, (VOIDSTAR) closure);\r
-    if (closure->count == 0) {\r
-       /* See if it's an illegal move due to check */\r
-        illegal = 1;\r
-        GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights, DisambiguateCallback,\r
-                (VOIDSTAR) closure);   \r
-       if (closure->count == 0) {\r
-           /* No, it's not even that */\r
-    if (appData.debugMode) { int i, j;\r
-       for(i=BOARD_HEIGHT-1; i>=0; i--) {\r
-               for(j=0; j<BOARD_WIDTH; j++)\r
-                       fprintf(debugFP, "%3d", (int) board[i][j]);\r
-               fprintf(debugFP, "\n");\r
-       }\r
-    }\r
-           return;\r
-       }\r
-    }\r
-\r
-    if(gameInfo.variant == VariantShogi) {\r
-        /* [HGM] Shogi promotions. '=' means defer */\r
-        if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) {\r
-            ChessSquare piece = closure->piece;\r
-#if 0\r
-    if (appData.debugMode) {\r
-        fprintf(debugFP, "Disambiguate A:   %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
-                          closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,\r
-                          closure->promoCharIn,closure->promoCharIn);\r
-    }\r
-#endif\r
-            if(c != NULLCHAR && c != 'x' && c != '+' && c != '=' &&\r
-               ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(c) ) \r
-                    closure->kind = IllegalMove;\r
-            else if(flags & F_WHITE_ON_MOVE) {\r
-#if 0\r
-    if (appData.debugMode) {\r
-        fprintf(debugFP, "Disambiguate B:   %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
-                          closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,\r
-                          closure->promoCharIn,closure->promoCharIn);\r
-    }\r
-#endif\r
-                if( (int) piece < (int) WhiteWazir &&\r
-                     (closure->rf > BOARD_HEIGHT-4 || closure->rt > BOARD_HEIGHT-4) ) {\r
-                    if( (piece == WhitePawn || piece == WhiteQueen) && closure->rt > BOARD_HEIGHT-2 ||\r
-                         piece == WhiteKnight && closure->rt > BOARD_HEIGHT-3) /* promotion mandatory */\r
-                             closure->kind = c == '=' ? IllegalMove : WhitePromotionKnight;\r
-                    else /* promotion optional, default is promote */\r
-                             closure->kind = c == '=' ? NormalMove  : WhitePromotionQueen;\r
-                   \r
-                } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ?\r
-                                            NormalMove : IllegalMove;\r
-            } else {\r
-                if( (int) piece < (int) BlackWazir && (closure->rf < 3 || closure->rt < 3) ) {\r
-                    if( (piece == BlackPawn || piece == BlackQueen) && closure->rt < 1 ||\r
-                         piece == BlackKnight && closure->rt < 2 ) /* promotion obligatory */\r
-                             closure->kind = c == '=' ? IllegalMove : BlackPromotionKnight;\r
-                    else /* promotion optional, default is promote */\r
-                             closure->kind = c == '=' ? NormalMove  : BlackPromotionQueen;\r
-\r
-                } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ?\r
-                                            NormalMove : IllegalMove;\r
-            }\r
-        }\r
-    } else\r
-    if (closure->promoCharIn != NULLCHAR && closure->promoCharIn != 'x') {\r
-       if (closure->kind == WhitePromotionQueen\r
-           || closure->kind == BlackPromotionQueen) {\r
-           closure->kind = \r
-             PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0,\r
-                                 closure->promoCharIn);\r
-       } else {\r
-           closure->kind = IllegalMove;\r
-       }\r
-    }\r
-#if 0\r
-    if (appData.debugMode) {\r
-        fprintf(debugFP, "Disambiguate C:   %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
-                          closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,\r
-                          closure->promoCharIn,closure->promoCharIn);\r
-    }\r
-#endif\r
-    /* [HGM] returns 'q' for optional promotion, 'n' for mandatory */\r
-    if(closure->promoCharIn != '=')\r
-        closure->promoChar = ToLower(closure->promoCharIn);\r
-    else closure->promoChar = '=';\r
-    if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;\r
-    if (closure->count > 1) {\r
-       closure->kind = AmbiguousMove;\r
-    }\r
-    if (illegal) {\r
-       /* Note: If more than one illegal move matches, but no legal\r
-          moves, we return IllegalMove, not AmbiguousMove.  Caller\r
-          can look at closure->count to detect this.\r
-       */\r
-       closure->kind = IllegalMove;\r
-    }\r
-    if(closure->kind == IllegalMove)\r
-    /* [HGM] might be a variant we don't understand, pass on promotion info */\r
-        closure->promoChar = ToLower(closure->promoCharIn);\r
-    if (appData.debugMode) {\r
-        fprintf(debugFP, "Disambiguate out: %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
-        closure->piece,closure->ff,closure->rf,closure->ft,closure->rt,closure->promoChar,\r
-       closure->promoChar >= ' ' ? closure->promoChar:'-');\r
-    }\r
-}\r
-\r
-\r
-typedef struct {\r
-    /* Input */\r
-    ChessSquare piece;\r
-    int rf, ff, rt, ft;\r
-    /* Output */\r
-    ChessMove kind;\r
-    int rank;\r
-    int file;\r
-    int either;\r
-} CoordsToAlgebraicClosure;\r
-\r
-extern void CoordsToAlgebraicCallback P((Board board, int flags,\r
-                                        ChessMove kind, int rf, int ff,\r
-                                        int rt, int ft, VOIDSTAR closure));\r
-\r
-void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
-     Board board;\r
-     int flags;\r
-     ChessMove kind;\r
-     int rf, ff, rt, ft;\r
-     VOIDSTAR closure;\r
-{\r
-    register CoordsToAlgebraicClosure *cl =\r
-      (CoordsToAlgebraicClosure *) closure;\r
-\r
-    if (rt == cl->rt && ft == cl->ft &&\r
-        (board[rf][ff] == cl->piece\r
-         || PieceToChar(board[rf][ff]) == '~' &&\r
-            (ChessSquare) (DEMOTED board[rf][ff]) == cl->piece)\r
-                                     ) {\r
-       if (rf == cl->rf) {\r
-           if (ff == cl->ff) {\r
-               cl->kind = kind; /* this is the move we want */\r
-           } else {\r
-               cl->file++; /* need file to rule out this move */\r
-           }\r
-       } else {\r
-           if (ff == cl->ff) {\r
-               cl->rank++; /* need rank to rule out this move */\r
-           } else {\r
-               cl->either++; /* rank or file will rule out this move */\r
-           }\r
-       }           \r
-    }\r
-}\r
-\r
-/* Convert coordinates to normal algebraic notation.\r
-   promoChar must be NULLCHAR or 'x' if not a promotion.\r
-*/\r
-ChessMove CoordsToAlgebraic(board, flags, epfile,\r
-                           rf, ff, rt, ft, promoChar, out)\r
-     Board board;\r
-     int flags, epfile;\r
-     int rf, ff, rt, ft;\r
-     int promoChar;\r
-     char out[MOVE_LEN];\r
-{\r
-    ChessSquare piece;\r
-    ChessMove kind;\r
-    char *outp = out, c;\r
-    CoordsToAlgebraicClosure cl;\r
-    \r
-    if (rf == DROP_RANK) {\r
-       /* Bughouse piece drop */\r
-       *outp++ = ToUpper(PieceToChar((ChessSquare) ff));\r
-       *outp++ = '@';\r
-        *outp++ = ft + AAA;\r
-        if(rt+ONE <= '9')\r
-           *outp++ = rt + ONE;\r
-        else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
-       *outp = NULLCHAR;\r
-       return (flags & F_WHITE_ON_MOVE) ? WhiteDrop : BlackDrop;\r
-    }\r
-\r
-    if (promoChar == 'x') promoChar = NULLCHAR;\r
-    piece = board[rf][ff];\r
-    if(PieceToChar(piece)=='~') piece = (ChessSquare)(DEMOTED piece);\r
-\r
-  if (appData.debugMode)\r
-          fprintf(debugFP, "CoordsToAlgebraic, piece=%d (%d,%d)-(%d,%d) %c\n", (int)piece,ff,rf,ft,rt,promoChar >= ' ' ? promoChar : '-');\r
-    switch (piece) {\r
-      case WhitePawn:\r
-      case BlackPawn:\r
-        kind = LegalityTest(board, flags, epfile, initialRights, rf, ff, rt, ft, promoChar);\r
-       if (kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {\r
-           /* Keep short notation if move is illegal only because it\r
-               leaves the player in check, but still return IllegalMove */\r
-            kind = LegalityTest(board, flags|F_IGNORE_CHECK, epfile, initialRights,\r
-                              rf, ff, rt, ft, promoChar);\r
-           if (kind == IllegalMove) break;\r
-           kind = IllegalMove;\r
-       }\r
-       /* Pawn move */\r
-        *outp++ = ff + AAA;\r
-        if (ff == ft && board[rt][ft] == EmptySquare) { /* [HGM] Xiangqi has straight noncapts! */\r
-           /* Non-capture; use style "e5" */\r
-            if(rt+ONE <= '9')\r
-               *outp++ = rt + ONE;\r
-            else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
-       } else {\r
-           /* Capture; use style "exd5" */\r
-            if(gameInfo.variant != VariantXiangqi || board[rt][ft] != EmptySquare )\r
-            *outp++ = 'x';  /* [HGM] Xiangqi has sideway noncaptures across river! */\r
-            *outp++ = ft + AAA;\r
-            if(rt+ONE <= '9')\r
-               *outp++ = rt + ONE;\r
-            else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
-       }\r
-       /* Use promotion suffix style "=Q" */\r
-       *outp = NULLCHAR;\r
-  if (appData.debugMode)\r
-          fprintf(debugFP, "movetype=%d, promochar=%d=%c\n", (int)kind, promoChar, promoChar >= ' ' ? promoChar : '-');\r
-        if (promoChar != NULLCHAR) {\r
-            if(gameInfo.variant == VariantShogi) {\r
-                /* [HGM] ... but not in Shogi! */\r
-                *outp++ = promoChar == '=' ? '=' : '+';\r
-            } else {\r
-                *outp++ = '=';\r
-                *outp++ = ToUpper(promoChar);\r
-            }\r
-            *outp = NULLCHAR;\r
-       }\r
-        return kind;\r
-\r
-       \r
-      case WhiteKing:\r
-      case BlackKing:\r
-        /* Fabien moved code: FRC castling first (if KxR), wild castling second */\r
-       /* Code added by Tord:  FRC castling. */\r
-       if((piece == WhiteKing && board[rt][ft] == WhiteRook) ||\r
-          (piece == BlackKing && board[rt][ft] == BlackRook)) {\r
-         if(ft > ff) strcpy(out, "O-O"); else strcpy(out, "O-O-O");\r
-            return LegalityTest(board, flags, epfile, initialRights,\r
-                               rf, ff, rt, ft, promoChar);\r
-       }\r
-       /* End of code added by Tord */\r
-       /* Test for castling or ICS wild castling */\r
-       /* Use style "O-O" (oh-oh) for PGN compatibility */\r
-       else if (rf == rt &&\r
-           rf == ((piece == WhiteKing) ? 0 : BOARD_HEIGHT-1) &&\r
-            ((ff == BOARD_WIDTH>>1 && (ft == BOARD_LEFT+2 || ft == BOARD_RGHT-2)) ||\r
-             (ff == (BOARD_WIDTH-1)>>1 && (ft == BOARD_LEFT+1 || ft == BOARD_RGHT-3)))) {\r
-            if(ft==BOARD_LEFT+1 || ft==BOARD_RGHT-2)\r
-               strcpy(out, "O-O");\r
-            else\r
-               strcpy(out, "O-O-O");\r
-\r
-           /* This notation is always unambiguous, unless there are\r
-              kings on both the d and e files, with "wild castling"\r
-              possible for the king on the d file and normal castling\r
-              possible for the other.  ICS rules for wild 9\r
-              effectively make castling illegal for either king in\r
-              this situation.  So I am not going to worry about it;\r
-              I'll just generate an ambiguous O-O in this case.\r
-           */\r
-            return LegalityTest(board, flags, epfile, initialRights,\r
-                               rf, ff, rt, ft, promoChar);\r
-       }\r
-\r
-       /* else fall through */\r
-      default:\r
-       /* Piece move */\r
-       cl.rf = rf;\r
-       cl.ff = ff;\r
-       cl.rt = rt;\r
-       cl.ft = ft;\r
-       cl.piece = piece;\r
-       cl.kind = IllegalMove;\r
-       cl.rank = cl.file = cl.either = 0;\r
-        GenLegal(board, flags, epfile, initialRights,\r
-                CoordsToAlgebraicCallback, (VOIDSTAR) &cl);\r
-\r
-       if (cl.kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {\r
-           /* Generate pretty moves for moving into check, but\r
-              still return IllegalMove.\r
-           */\r
-            GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights,\r
-                    CoordsToAlgebraicCallback, (VOIDSTAR) &cl);\r
-           if (cl.kind == IllegalMove) break;\r
-           cl.kind = IllegalMove;\r
-       }\r
-\r
-       /* Style is "Nf3" or "Nxf7" if this is unambiguous,\r
-          else "Ngf3" or "Ngxf7",\r
-          else "N1f3" or "N5xf7",\r
-          else "Ng1f3" or "Ng5xf7".\r
-       */\r
-        c = PieceToChar(piece) ;\r
-        if( c == '~' || c == '+') {\r
-           /* [HGM] print nonexistent piece as its demoted version */\r
-           piece = (ChessSquare) (DEMOTED piece);\r
-        }\r
-        if(c=='+') *outp++ = c;\r
-        *outp++ = ToUpper(PieceToChar(piece));\r
-\r
-       if (cl.file || (cl.either && !cl.rank)) {\r
-            *outp++ = ff + AAA;\r
-       }\r
-       if (cl.rank) {\r
-            if(rf+ONE <= '9')\r
-                *outp++ = rf + ONE;\r
-            else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }\r
-       }\r
-\r
-       if(board[rt][ft] != EmptySquare)\r
-         *outp++ = 'x';\r
-\r
-        *outp++ = ft + AAA;\r
-        if(rt+ONE <= '9')\r
-           *outp++ = rt + ONE;\r
-        else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
-       *outp = NULLCHAR;\r
-        if (gameInfo.variant == VariantShogi) {\r
-            /* [HGM] in Shogi non-pawns can promote */\r
-            if(flags & F_WHITE_ON_MOVE) {\r
-                if( (int) cl.piece < (int) WhiteWazir &&\r
-                     (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) {\r
-                    if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||\r
-                         piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */\r
-                             cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight;\r
-                    else cl.kind =  WhitePromotionQueen; /* promotion optional */\r
-                   \r
-                } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
-                                            NormalMove : IllegalMove;\r
-            } else {\r
-                if( (int) cl.piece < (int) BlackWazir && (rf < 3 || rt < 3) ) {\r
-                    if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||\r
-                         piece == BlackKnight && rt < 2 ) /* promotion obligatory */\r
-                             cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight;\r
-                    else cl.kind =  BlackPromotionQueen; /* promotion optional */\r
-                } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
-                                            NormalMove : IllegalMove;\r
-            }\r
-            if(cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {\r
-                /* for optional promotions append '+' or '=' */\r
-                if(promoChar == '=') {\r
-                    *outp++ = '=';\r
-                    cl.kind = NormalMove;\r
-                } else *outp++ = '+';\r
-                *outp = NULLCHAR;\r
-            } else if(cl.kind == IllegalMove) {\r
-                /* Illegal move specifies any given promotion */\r
-                if(promoChar != NULLCHAR && promoChar != 'x') {\r
-                    *outp++ = '=';\r
-                    *outp++ = ToUpper(promoChar);\r
-                    *outp = NULLCHAR;\r
-                }\r
-            }\r
-        }\r
-        return cl.kind;\r
-       \r
-      /* [HGM] Always long notation for fairies we don't know */\r
-      case WhiteFalcon:\r
-      case BlackFalcon:\r
-      case WhiteLance:\r
-      case BlackLance:\r
-      case WhiteGrasshopper:\r
-      case BlackGrasshopper:\r
-      case EmptySquare:\r
-       /* Moving a nonexistent piece */\r
-       break;\r
-    }\r
-    \r
-    /* Not a legal move, even ignoring check.\r
-       If there was a piece on the from square, \r
-       use style "Ng1g3" or "Ng1xe8";\r
-       if there was a pawn or nothing (!),\r
-       use style "g1g3" or "g1xe8".  Use "x"\r
-       if a piece was on the to square, even\r
-       a piece of the same color.\r
-    */\r
-    outp = out;\r
-    if (piece != EmptySquare && piece != WhitePawn && piece != BlackPawn) {\r
-       *outp++ = ToUpper(PieceToChar(piece));\r
-    }\r
-    *outp++ = ff + AAA;\r
-    if(rf+ONE <= '9')\r
-       *outp++ = rf + ONE;\r
-    else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }\r
-    if (board[rt][ft] != EmptySquare) *outp++ = 'x';\r
-    *outp++ = ft + AAA;\r
-    if(rt+ONE <= '9')\r
-       *outp++ = rt + ONE;\r
-    else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
-    /* Use promotion suffix style "=Q" */\r
-    if (promoChar != NULLCHAR && promoChar != 'x') {\r
-       *outp++ = '=';\r
-       *outp++ = ToUpper(promoChar);\r
-    }\r
-    *outp = NULLCHAR;\r
-\r
-    return IllegalMove;\r
-}\r
-\r
-\r
+/*
+ * moves.c - Move generation and checking
+ * $Id: moves.c,v 2.1 2003/10/27 19:21:00 mann Exp $
+ *
+ * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
+ * Enhancements Copyright 1992-95 Free Software Foundation, Inc.
+ *
+ * The following terms apply to Digital Equipment Corporation's copyright
+ * interest in XBoard:
+ * ------------------------------------------------------------------------
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Digital not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * ------------------------------------------------------------------------
+ *
+ * The following terms apply to the enhanced version of XBoard distributed
+ * by the Free Software Foundation:
+ * ------------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * ------------------------------------------------------------------------
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#if HAVE_STRING_H
+# include <string.h>
+#else /* not HAVE_STRING_H */
+# include <strings.h>
+#endif /* not HAVE_STRING_H */
+#include "common.h"
+#include "backend.h" 
+#include "moves.h"
+#include "parser.h"
+
+int WhitePiece P((ChessSquare));
+int BlackPiece P((ChessSquare));
+int SameColor P((ChessSquare, ChessSquare));
+
+extern char initialRights[BOARD_SIZE]; /* [HGM] all rights enabled, set in InitPosition */
+
+
+int WhitePiece(piece)
+     ChessSquare piece;
+{
+    return (int) piece >= (int) WhitePawn && (int) piece < (int) BlackPawn;
+}
+
+int BlackPiece(piece)
+     ChessSquare piece;
+{
+    return (int) piece >= (int) BlackPawn && (int) piece < (int) EmptySquare;
+}
+
+int SameColor(piece1, piece2)
+     ChessSquare piece1, piece2;
+{
+    return ((int) piece1 >= (int) WhitePawn &&   /* [HGM] can be > King ! */
+            (int) piece1 <  (int) BlackPawn &&
+           (int) piece2 >= (int) WhitePawn &&
+            (int) piece2 <  (int) BlackPawn)
+      ||   ((int) piece1 >= (int) BlackPawn &&
+            (int) piece1 <  (int) EmptySquare &&
+           (int) piece2 >= (int) BlackPawn &&
+            (int) piece2 <  (int) EmptySquare);
+}
+
+ChessSquare PromoPiece(moveType)
+     ChessMove moveType;
+{
+    switch (moveType) {
+      default:
+       return EmptySquare;
+      case WhitePromotionQueen:
+       return WhiteQueen;
+      case BlackPromotionQueen:
+       return BlackQueen;
+      case WhitePromotionRook:
+       return WhiteRook;
+      case BlackPromotionRook:
+       return BlackRook;
+      case WhitePromotionBishop:
+       return WhiteBishop;
+      case BlackPromotionBishop:
+       return BlackBishop;
+      case WhitePromotionKnight:
+       return WhiteKnight;
+      case BlackPromotionKnight:
+       return BlackKnight;
+      case WhitePromotionKing:
+       return WhiteKing;
+      case BlackPromotionKing:
+       return BlackKing;
+      case WhitePromotionChancellor:
+        return WhiteMarshall;
+      case BlackPromotionChancellor:
+        return BlackMarshall;
+      case WhitePromotionArchbishop:
+        return WhiteAngel;
+      case BlackPromotionArchbishop:
+        return BlackAngel;
+      case WhitePromotionCentaur:
+        return WhiteSilver;
+      case BlackPromotionCentaur:
+        return BlackSilver;
+    }
+}
+
+char pieceToChar[] = {
+                        'P', 'N', 'B', 'R', 'Q', 'F', 'E', 'A', 'C', 'W', 'M', 
+                        'O', 'H', 'I', 'J', 'G', 'D', 'V', 'L', 's', 'U', 'K',
+                        'p', 'n', 'b', 'r', 'q', 'f', 'e', 'a', 'c', 'w', 'm', 
+                        'o', 'h', 'i', 'j', 'g', 'd', 'v', 'l', 's', 'u', 'k', 
+                        'x' };
+
+char PieceToChar(p)
+     ChessSquare p;
+{
+    if((int)p < 0 || (int)p >= (int)EmptySquare) return('x'); /* [HGM] for safety */
+    return pieceToChar[(int) p];
+}
+
+int PieceToNumber(p)  /* [HGM] holdings: count piece type, ignoring non-participating piece types */
+     ChessSquare p;
+{
+    int i=0;
+    ChessSquare start = (int)p >= (int)BlackPawn ? BlackPawn : WhitePawn;
+
+    while(start++ != p) if(pieceToChar[(int)start-1] != '.') i++;
+    return i;
+}
+
+ChessSquare CharToPiece(c)
+     int c;
+{
+     int i;
+     for(i=0; i< (int) EmptySquare; i++)
+          if(pieceToChar[i] == c) return (ChessSquare) i;
+     return EmptySquare;
+}
+
+ChessMove PromoCharToMoveType(whiteOnMove, promoChar)
+     int whiteOnMove;
+     int promoChar;
+{      /* [HGM] made dependent on CharToPiece to alow alternate piece letters */
+       ChessSquare piece = CharToPiece(whiteOnMove ? ToUpper(promoChar) : ToLower(promoChar) );
+
+
+       if(promoChar == NULLCHAR) return NormalMove;
+
+       switch(piece) {
+               case WhiteQueen:
+                       return WhitePromotionQueen;
+               case WhiteRook:
+                       return WhitePromotionRook;
+               case WhiteBishop:
+                       return WhitePromotionBishop;
+               case WhiteKnight:
+                       return WhitePromotionKnight;
+               case WhiteKing:
+                       return WhitePromotionKing;
+               case WhiteAngel:
+                       return WhitePromotionArchbishop;
+               case WhiteMarshall:
+                       return WhitePromotionChancellor;
+               case WhiteSilver:
+                       return WhitePromotionCentaur;
+               case BlackQueen:
+                       return BlackPromotionQueen;
+               case BlackRook:
+                       return BlackPromotionRook;
+               case BlackBishop:
+                       return BlackPromotionBishop;
+               case BlackKnight:
+                       return BlackPromotionKnight;
+               case BlackKing:
+                       return BlackPromotionKing;
+               case BlackAngel:
+                       return BlackPromotionArchbishop;
+               case BlackMarshall:
+                       return BlackPromotionChancellor;
+               case BlackSilver:
+                       return BlackPromotionCentaur;
+               default:
+                       // not all promotion implemented yet! Take Queen for those we don't know.
+                       return (whiteOnMove ? WhitePromotionQueen : BlackPromotionQueen);
+       }
+}
+
+void CopyBoard(to, from)
+     Board to, from;
+{
+    int i, j;
+    
+    for (i = 0; i < BOARD_HEIGHT; i++)
+      for (j = 0; j < BOARD_WIDTH; j++)
+       to[i][j] = from[i][j];
+}
+
+int CompareBoards(board1, board2)
+     Board board1, board2;
+{
+    int i, j;
+    
+    for (i = 0; i < BOARD_HEIGHT; i++)
+      for (j = 0; j < BOARD_WIDTH; j++) {
+         if (board1[i][j] != board2[i][j])
+           return FALSE;
+    }
+    return TRUE;
+}
+
+
+/* Call callback once for each pseudo-legal move in the given
+   position, except castling moves. A move is pseudo-legal if it is
+   legal, or if it would be legal except that it leaves the king in
+   check.  In the arguments, epfile is EP_NONE if the previous move
+   was not a double pawn push, or the file 0..7 if it was, or
+   EP_UNKNOWN if we don't know and want to allow all e.p. captures.
+   Promotion moves generated are to Queen only.
+*/
+void GenPseudoLegal(board, flags, epfile, callback, closure)
+     Board board;
+     int flags;
+     int epfile;
+     MoveCallback callback;
+     VOIDSTAR closure;
+{
+    int rf, ff;
+    int i, j, d, s, fs, rs, rt, ft, m;
+
+    for (rf = 0; rf < BOARD_HEIGHT; rf++) 
+      for (ff = BOARD_LEFT; ff < BOARD_RGHT; ff++) {
+          ChessSquare piece;
+
+         if (flags & F_WHITE_ON_MOVE) {
+             if (!WhitePiece(board[rf][ff])) continue;
+         } else {
+             if (!BlackPiece(board[rf][ff])) continue;
+         }
+          m = 0; piece = board[rf][ff];
+          if(PieceToChar(piece) == '~') 
+                 piece = (ChessSquare) ( DEMOTED piece );
+          if(gameInfo.variant == VariantShogi)
+                 piece = (ChessSquare) ( SHOGI piece );
+
+          switch (piece) {
+            /* case EmptySquare: [HGM] this is nonsense, and conflicts with Shogi cases */
+           default:
+             /* can't happen ([HGM] except for faries...) */
+             break;
+
+             case WhitePawn:
+              if(gameInfo.variant == VariantXiangqi) {
+                  /* [HGM] capture and move straight ahead in Xiangqi */
+                  if (rf < BOARD_HEIGHT-1 &&
+                           !SameColor(board[rf][ff], board[rf + 1][ff]) ) {
+                           callback(board, flags, NormalMove,
+                                    rf, ff, rf + 1, ff, closure);
+                  }
+                  /* and move sideways when across the river */
+                  for (s = -1; s <= 1; s += 2) {
+                      if (rf >= BOARD_HEIGHT>>1 &&
+                          ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
+                          !WhitePiece(board[rf][ff+s]) ) {
+                           callback(board, flags, NormalMove,
+                                    rf, ff, rf, ff+s, closure);
+                      }
+                  }
+                  break;
+              }
+              if (rf < BOARD_HEIGHT-1 && board[rf + 1][ff] == EmptySquare) {
+                 callback(board, flags,
+                          rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,
+                          rf, ff, rf + 1, ff, closure);
+             }
+             if (rf == 1 && board[2][ff] == EmptySquare &&
+                  gameInfo.variant != VariantShatranj && /* [HGM] */
+                  gameInfo.variant != VariantCourier  && /* [HGM] */
+                  board[3][ff] == EmptySquare ) {
+                      callback(board, flags, NormalMove,
+                               rf, ff, 3, ff, closure);
+             }
+             for (s = -1; s <= 1; s += 2) {
+                  if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
+                     ((flags & F_KRIEGSPIEL_CAPTURE) ||
+                      BlackPiece(board[rf + 1][ff + s]))) {
+                     callback(board, flags, 
+                              rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,
+                              rf, ff, rf + 1, ff + s, closure);
+                 }
+                 if (rf == BOARD_HEIGHT-4) {
+                      if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
+                         (epfile == ff + s || epfile == EP_UNKNOWN) &&
+                          board[BOARD_HEIGHT-4][ff + s] == BlackPawn &&
+                          board[BOARD_HEIGHT-3][ff + s] == EmptySquare) {
+                         callback(board, flags, WhiteCapturesEnPassant,
+                                  rf, ff, 5, ff + s, closure);
+                     }
+                 }
+             }             
+             break;
+
+           case BlackPawn:
+              if(gameInfo.variant == VariantXiangqi) {
+                  /* [HGM] capture straight ahead in Xiangqi */
+                  if (rf > 0 && !SameColor(board[rf][ff], board[rf - 1][ff]) ) {
+                           callback(board, flags, NormalMove,
+                                    rf, ff, rf - 1, ff, closure);
+                  }
+                  /* and move sideways when across the river */
+                  for (s = -1; s <= 1; s += 2) {
+                      if (rf < BOARD_HEIGHT>>1 &&
+                          ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
+                          !BlackPiece(board[rf][ff+s]) ) {
+                           callback(board, flags, NormalMove,
+                                    rf, ff, rf, ff+s, closure);
+                      }
+                  }
+                  break;
+              }
+             if (rf > 0 && board[rf - 1][ff] == EmptySquare) {
+                 callback(board, flags, 
+                          rf == 1 ? BlackPromotionQueen : NormalMove,
+                          rf, ff, rf - 1, ff, closure);
+             }
+             if (rf == BOARD_HEIGHT-2 && board[BOARD_HEIGHT-3][ff] == EmptySquare &&
+                  gameInfo.variant != VariantShatranj && /* [HGM] */
+                  gameInfo.variant != VariantCourier  && /* [HGM] */
+                 board[BOARD_HEIGHT-4][ff] == EmptySquare) {
+                 callback(board, flags, NormalMove,
+                          rf, ff, BOARD_HEIGHT-4, ff, closure);
+             }
+             for (s = -1; s <= 1; s += 2) {
+                  if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
+                     ((flags & F_KRIEGSPIEL_CAPTURE) ||
+                      WhitePiece(board[rf - 1][ff + s]))) {
+                     callback(board, flags, 
+                              rf == 1 ? BlackPromotionQueen : NormalMove,
+                              rf, ff, rf - 1, ff + s, closure);
+                 }
+                 if (rf == 3) {
+                      if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
+                         (epfile == ff + s || epfile == EP_UNKNOWN) &&
+                         board[3][ff + s] == WhitePawn &&
+                         board[2][ff + s] == EmptySquare) {
+                         callback(board, flags, BlackCapturesEnPassant,
+                                  rf, ff, 2, ff + s, closure);
+                     }
+                 }
+             }             
+             break;
+
+            case WhiteUnicorn:
+            case BlackUnicorn:
+           case WhiteKnight:
+           case BlackKnight:
+            mounted:
+             for (i = -1; i <= 1; i += 2)
+               for (j = -1; j <= 1; j += 2)
+                 for (s = 1; s <= 2; s++) {
+                     rt = rf + i*s;
+                     ft = ff + j*(3-s);
+                      if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
+                          && ( gameInfo.variant != VariantXiangqi || board[rf+i*(s-1)][ff+j*(2-s)] == EmptySquare)
+                          && !SameColor(board[rf][ff], board[rt][ft]))
+                     callback(board, flags, NormalMove,
+                              rf, ff, rt, ft, closure);
+                 }
+             break;
+
+            case SHOGI WhiteKnight:
+             for (s = -1; s <= 1; s += 2) {
+                  if (rf < BOARD_HEIGHT-2 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
+                      !SameColor(board[rf][ff], board[rf + 2][ff + s])) {
+                      callback(board, flags, NormalMove,
+                               rf, ff, rf + 2, ff + s, closure);
+                 }
+              }
+             break;
+
+            case SHOGI BlackKnight:
+             for (s = -1; s <= 1; s += 2) {
+                  if (rf > 1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
+                      !SameColor(board[rf][ff], board[rf - 2][ff + s])) {
+                      callback(board, flags, NormalMove,
+                               rf, ff, rf - 2, ff + s, closure);
+                 }
+             }             
+             break;
+
+            case WhiteCannon:
+            case BlackCannon:
+              for (d = 0; d <= 1; d++)
+                for (s = -1; s <= 1; s += 2) {
+                  m = 0;
+                 for (i = 1;; i++) {
+                     rt = rf + (i * s) * d;
+                     ft = ff + (i * s) * (1 - d);
+                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
+                      if (m == 0 && board[rt][ft] == EmptySquare)
+                                 callback(board, flags, NormalMove,
+                                          rf, ff, rt, ft, closure);
+                      if (m == 1 && board[rt][ft] != EmptySquare &&
+                          !SameColor(board[rf][ff], board[rt][ft]) )
+                                 callback(board, flags, NormalMove,
+                                          rf, ff, rt, ft, closure);
+                      if (board[rt][ft] != EmptySquare && m++) break;
+                  }
+                }
+             break;
+
+            /* Gold General (and all its promoted versions) . First do the */
+            /* diagonal forward steps, then proceed as normal Wazir        */
+            case SHOGI WhiteWazir:
+            case SHOGI (PROMOTED WhitePawn):
+            case SHOGI (PROMOTED WhiteKnight):
+            case SHOGI (PROMOTED WhiteQueen):
+            case SHOGI (PROMOTED WhiteFerz):
+             for (s = -1; s <= 1; s += 2) {
+                  if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
+                      !SameColor(board[rf][ff], board[rf + 1][ff + s])) {
+                      callback(board, flags, NormalMove,
+                              rf, ff, rf + 1, ff + s, closure);
+                 }
+              }
+              goto finishGold;
+
+            case SHOGI BlackWazir:
+            case SHOGI (PROMOTED BlackPawn):
+            case SHOGI (PROMOTED BlackKnight):
+            case SHOGI (PROMOTED BlackQueen):
+            case SHOGI (PROMOTED BlackFerz):
+             for (s = -1; s <= 1; s += 2) {
+                  if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
+                      !SameColor(board[rf][ff], board[rf - 1][ff + s])) {
+                      callback(board, flags, NormalMove,
+                              rf, ff, rf - 1, ff + s, closure);
+                 }
+             }             
+
+            case WhiteWazir:
+            case BlackWazir:
+            finishGold:
+              for (d = 0; d <= 1; d++)
+                for (s = -1; s <= 1; s += 2) {
+                      rt = rf + s * d;
+                      ft = ff + s * (1 - d);
+                      if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
+                          && !SameColor(board[rf][ff], board[rt][ft]) &&
+                          (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) )
+                               callback(board, flags, NormalMove,
+                                        rf, ff, rt, ft, closure);
+                      }
+             break;
+
+            case WhiteAlfil:
+            case BlackAlfil:
+                /* [HGM] support Shatranj pieces */
+                for (rs = -1; rs <= 1; rs += 2) 
+                  for (fs = -1; fs <= 1; fs += 2) {
+                      rt = rf + 2 * rs;
+                      ft = ff + 2 * fs;
+                      if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
+                          && ( gameInfo.variant != VariantXiangqi ||
+                               board[rf+rs][ff+fs] == EmptySquare && (2*rf < BOARD_HEIGHT) == (2*rt < BOARD_HEIGHT) )
+                         
+                          && !SameColor(board[rf][ff], board[rt][ft]))
+                               callback(board, flags, NormalMove,
+                                        rf, ff, rt, ft, closure);
+                 }
+                break;
+
+            /* Shogi Dragon Horse has to continue with Wazir after Bishop */
+            case SHOGI WhiteCardinal:
+            case SHOGI BlackCardinal:
+              m++;
+
+            /* Capablanca Archbishop continues as Knight                  */
+            case WhiteAngel:
+            case BlackAngel:
+              m++;
+
+            /* Shogi Bishops are ordinary Bishops */
+            case SHOGI WhiteBishop:
+            case SHOGI BlackBishop:
+           case WhiteBishop:
+           case BlackBishop:
+             for (rs = -1; rs <= 1; rs += 2) 
+                for (fs = -1; fs <= 1; fs += 2) 
+                 for (i = 1;; i++) {
+                     rt = rf + (i * rs);
+                     ft = ff + (i * fs);
+                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
+                     if (SameColor(board[rf][ff], board[rt][ft])) break;
+                     callback(board, flags, NormalMove,
+                              rf, ff, rt, ft, closure);
+                     if (board[rt][ft] != EmptySquare) break;
+                 }
+                if(m==1) goto mounted;
+                if(m==2) goto finishGold;
+                /* Bishop falls through */
+             break;
+
+            /* Shogi Lance is unlike anything, and asymmetric at that */
+            case SHOGI WhiteQueen:
+              for(i = 1;; i++) {
+                      rt = rf + i;
+                      ft = ff;
+                      if (rt >= BOARD_HEIGHT) break;
+                     if (SameColor(board[rf][ff], board[rt][ft])) break;
+                     callback(board, flags, NormalMove,
+                              rf, ff, rt, ft, closure);
+                      if (board[rt][ft] != EmptySquare) break;
+              }
+              break;
+
+            case SHOGI BlackQueen:
+              for(i = 1;; i++) {
+                      rt = rf - i;
+                      ft = ff;
+                      if (rt < 0) break;
+                     if (SameColor(board[rf][ff], board[rt][ft])) break;
+                     callback(board, flags, NormalMove,
+                              rf, ff, rt, ft, closure);
+                      if (board[rt][ft] != EmptySquare) break;
+              }
+              break;
+
+            /* Shogi Dragon King has to continue as Ferz after Rook moves */
+            case SHOGI WhiteDragon:
+            case SHOGI BlackDragon:
+              m++;
+
+            /* Capablanca Chancellor sets flag to continue as Knight      */
+            case WhiteMarshall:
+            case BlackMarshall:
+              m++;
+
+            /* Shogi Rooks are ordinary Rooks */
+            case SHOGI WhiteRook:
+            case SHOGI BlackRook:
+           case WhiteRook:
+           case BlackRook:
+              for (d = 0; d <= 1; d++)
+                for (s = -1; s <= 1; s += 2)
+                 for (i = 1;; i++) {
+                     rt = rf + (i * s) * d;
+                     ft = ff + (i * s) * (1 - d);
+                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
+                     if (SameColor(board[rf][ff], board[rt][ft])) break;
+                     callback(board, flags, NormalMove,
+                              rf, ff, rt, ft, closure);
+                     if (board[rt][ft] != EmptySquare) break;
+                 }
+                if(m==1) goto mounted;
+                if(m==2) goto finishGold;
+             break;
+
+           case WhiteQueen:
+           case BlackQueen:
+             for (rs = -1; rs <= 1; rs++) 
+               for (fs = -1; fs <= 1; fs++) {
+                   if (rs == 0 && fs == 0) continue;
+                   for (i = 1;; i++) {
+                       rt = rf + (i * rs);
+                       ft = ff + (i * fs);
+                        if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
+                       if (SameColor(board[rf][ff], board[rt][ft])) break;
+                       callback(board, flags, NormalMove,
+                                rf, ff, rt, ft, closure);
+                       if (board[rt][ft] != EmptySquare) break;
+                   }
+               }
+             break;
+
+            /* Shogi Pawn and Silver General: first the Pawn move,    */
+            /* then the General continues like a Ferz                 */
+            case SHOGI WhitePawn:
+            case SHOGI WhiteFerz:
+                  if (rf < BOARD_HEIGHT-1 &&
+                           !SameColor(board[rf][ff], board[rf + 1][ff]) ) 
+                           callback(board, flags, NormalMove,
+                                    rf, ff, rf + 1, ff, closure);
+              if(piece != SHOGI WhitePawn) goto finishSilver;
+              break;
+
+            case SHOGI BlackPawn:
+            case SHOGI BlackFerz:
+                  if (rf > 0 &&
+                           !SameColor(board[rf][ff], board[rf - 1][ff]) ) 
+                           callback(board, flags, NormalMove,
+                                    rf, ff, rf - 1, ff, closure);
+              if(piece == SHOGI BlackPawn) break;
+
+            case WhiteFerz:
+            case BlackFerz:
+            finishSilver:
+                /* [HGM] support Shatranj pieces */
+                for (rs = -1; rs <= 1; rs += 2) 
+                  for (fs = -1; fs <= 1; fs += 2) {
+                      rt = rf + rs;
+                      ft = ff + fs;
+                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
+                      if (!SameColor(board[rf][ff], board[rt][ft]) &&
+                          (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) )
+                               callback(board, flags, NormalMove,
+                                        rf, ff, rt, ft, closure);
+                 }
+                break;
+
+           case WhiteSilver:
+           case BlackSilver:
+               m++; // [HGM] superchess: use for Centaur
+            case WhiteMan:
+            case BlackMan:
+            case SHOGI WhiteKing:
+            case SHOGI BlackKing:
+           case WhiteKing:
+           case BlackKing:
+            walking:
+             for (i = -1; i <= 1; i++)
+               for (j = -1; j <= 1; j++) {
+                   if (i == 0 && j == 0) continue;
+                   rt = rf + i;
+                   ft = ff + j;
+                    if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
+                   if (SameColor(board[rf][ff], board[rt][ft])) continue;
+                   callback(board, flags, NormalMove,
+                            rf, ff, rt, ft, closure);
+               }
+               if(m==1) goto mounted;
+             break;
+
+           case WhiteNightrider:
+           case BlackNightrider:
+             for (i = -1; i <= 1; i += 2)
+               for (j = -1; j <= 1; j += 2)
+                 for (s = 1; s <= 2; s++) {  int k;
+                    for(k=1;; k++) {
+                     rt = rf + k*i*s;
+                     ft = ff + k*j*(3-s);
+                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;
+                     if (SameColor(board[rf][ff], board[rt][ft])) break;
+                     callback(board, flags, NormalMove,
+                              rf, ff, rt, ft, closure);
+                     if (board[rt][ft] != EmptySquare) break;
+                    }
+                 }
+             break;
+
+         }
+      }
+}
+
+
+typedef struct {
+    MoveCallback cb;
+    VOIDSTAR cl;
+} GenLegalClosure;
+
+extern void GenLegalCallback P((Board board, int flags, ChessMove kind,
+                               int rf, int ff, int rt, int ft,
+                               VOIDSTAR closure));
+
+void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure)
+     Board board;
+     int flags;
+     ChessMove kind;
+     int rf, ff, rt, ft;
+     VOIDSTAR closure;
+{
+    register GenLegalClosure *cl = (GenLegalClosure *) closure;
+
+    if (!(flags & F_IGNORE_CHECK) &&
+       CheckTest(board, flags, rf, ff, rt, ft,
+                 kind == WhiteCapturesEnPassant ||
+                 kind == BlackCapturesEnPassant)) return;
+    if (flags & F_ATOMIC_CAPTURE) {
+      if (board[rt][ft] != EmptySquare ||
+         kind == WhiteCapturesEnPassant || kind == BlackCapturesEnPassant) {
+       int r, f;
+       ChessSquare king = (flags & F_WHITE_ON_MOVE) ? WhiteKing : BlackKing;
+       if (board[rf][ff] == king) return;
+       for (r = rt-1; r <= rt+1; r++) {
+         for (f = ft-1; f <= ft+1; f++) {
+            if (r >= 0 && r < BOARD_HEIGHT && f >= BOARD_LEFT && f < BOARD_RGHT &&
+               board[r][f] == king) return;
+         }
+       }
+      }
+    }
+    cl->cb(board, flags, kind, rf, ff, rt, ft, cl->cl);
+}
+
+
+typedef struct {
+    int rf, ff, rt, ft;
+    ChessMove kind;
+} LegalityTestClosure;
+
+
+/* Like GenPseudoLegal, but (1) include castling moves, (2) unless
+   F_IGNORE_CHECK is set in the flags, omit moves that would leave the
+   king in check, and (3) if F_ATOMIC_CAPTURE is set in the flags, omit
+   moves that would destroy your own king.  The CASTLE_OK flags are
+   true if castling is not yet ruled out by a move of the king or
+   rook.  Return TRUE if the player on move is currently in check and
+   F_IGNORE_CHECK is not set.  [HGM] add castlingRights parameter */
+int GenLegal(board, flags, epfile, castlingRights, callback, closure)
+     Board board;
+     int flags;
+     int epfile;
+     char castlingRights[];
+     MoveCallback callback;
+     VOIDSTAR closure;
+{
+    GenLegalClosure cl;
+    int ff, ft, k, left, right;
+    int ignoreCheck = (flags & F_IGNORE_CHECK) != 0;
+    ChessSquare wKing = WhiteKing, bKing = BlackKing;
+
+    cl.cb = callback;
+    cl.cl = closure;
+    GenPseudoLegal(board, flags, epfile, GenLegalCallback, (VOIDSTAR) &cl);
+
+    if (!ignoreCheck &&
+       CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE;
+
+    /* Generate castling moves */
+    if(gameInfo.variant == VariantKnightmate) { /* [HGM] Knightmate */
+        wKing = WhiteUnicorn; bKing = BlackUnicorn;
+    }
+
+    for (ff = BOARD_WIDTH>>1; ff >= (BOARD_WIDTH-1)>>1; ff-- /*ics wild 1*/) {
+       if ((flags & F_WHITE_ON_MOVE) &&
+           (flags & F_WHITE_KCASTLE_OK) &&
+            board[0][ff] == wKing &&
+            board[0][ff + 1] == EmptySquare &&
+            board[0][ff + 2] == EmptySquare &&
+            board[0][BOARD_RGHT-3] == EmptySquare &&
+            board[0][BOARD_RGHT-2] == EmptySquare &&
+            board[0][BOARD_RGHT-1] == WhiteRook &&
+            castlingRights[0] >= 0 && /* [HGM] check rights */
+            ( castlingRights[2] == ff || castlingRights[6] == ff ) &&
+            (ignoreCheck ||                             
+            (!CheckTest(board, flags, 0, ff, 0, ff + 1, FALSE) &&
+              !CheckTest(board, flags, 0, ff, 0, BOARD_RGHT-3, FALSE) &&
+              (gameInfo.variant != VariantJanus || !CheckTest(board, flags, 0, ff, 0, BOARD_RGHT-2, FALSE)) &&
+             !CheckTest(board, flags, 0, ff, 0, ff + 2, FALSE)))) {
+
+           callback(board, flags,
+                     ff==BOARD_WIDTH>>1 ? WhiteKingSideCastle : WhiteKingSideCastleWild,
+                     0, ff, 0, ff + ((gameInfo.boardWidth+2)>>2) + (gameInfo.variant == VariantJanus), closure);
+       }
+       if ((flags & F_WHITE_ON_MOVE) &&
+           (flags & F_WHITE_QCASTLE_OK) &&
+            board[0][ff] == wKing &&
+           board[0][ff - 1] == EmptySquare &&
+           board[0][ff - 2] == EmptySquare &&
+            board[0][BOARD_LEFT+2] == EmptySquare &&
+            board[0][BOARD_LEFT+1] == EmptySquare &&
+            board[0][BOARD_LEFT+0] == WhiteRook &&
+            castlingRights[1] >= 0 && /* [HGM] check rights */
+            ( castlingRights[2] == ff || castlingRights[6] == ff ) &&
+           (ignoreCheck ||
+            (!CheckTest(board, flags, 0, ff, 0, ff - 1, FALSE) &&
+              !CheckTest(board, flags, 0, ff, 0, BOARD_LEFT+3, FALSE) &&
+             !CheckTest(board, flags, 0, ff, 0, ff - 2, FALSE)))) {
+
+           callback(board, flags,
+                    ff==BOARD_WIDTH>>1 ? WhiteQueenSideCastle : WhiteQueenSideCastleWild,
+                     0, ff, 0, ff - ((gameInfo.boardWidth+2)>>2), closure);
+       }
+       if (!(flags & F_WHITE_ON_MOVE) &&
+           (flags & F_BLACK_KCASTLE_OK) &&
+            board[BOARD_HEIGHT-1][ff] == bKing &&
+           board[BOARD_HEIGHT-1][ff + 1] == EmptySquare &&
+           board[BOARD_HEIGHT-1][ff + 2] == EmptySquare &&
+            board[BOARD_HEIGHT-1][BOARD_RGHT-3] == EmptySquare &&
+            board[BOARD_HEIGHT-1][BOARD_RGHT-2] == EmptySquare &&
+            board[BOARD_HEIGHT-1][BOARD_RGHT-1] == BlackRook &&
+            castlingRights[3] >= 0 && /* [HGM] check rights */
+            ( castlingRights[5] == ff || castlingRights[7] == ff ) &&
+           (ignoreCheck ||
+            (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 1, FALSE) &&
+              !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_RGHT-3, FALSE) &&
+              (gameInfo.variant != VariantJanus || !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_RGHT-2, FALSE)) &&
+             !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 2, FALSE)))) {
+
+           callback(board, flags,
+                    ff==BOARD_WIDTH>>1 ? BlackKingSideCastle : BlackKingSideCastleWild,
+                     BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + ((gameInfo.boardWidth+2)>>2) + (gameInfo.variant == VariantJanus), closure);
+       }
+       if (!(flags & F_WHITE_ON_MOVE) &&
+           (flags & F_BLACK_QCASTLE_OK) &&
+            board[BOARD_HEIGHT-1][ff] == bKing &&
+           board[BOARD_HEIGHT-1][ff - 1] == EmptySquare &&
+           board[BOARD_HEIGHT-1][ff - 2] == EmptySquare &&
+            board[BOARD_HEIGHT-1][BOARD_LEFT+2] == EmptySquare &&
+            board[BOARD_HEIGHT-1][BOARD_LEFT+1] == EmptySquare &&
+            board[BOARD_HEIGHT-1][BOARD_LEFT+0] == BlackRook &&
+            castlingRights[4] >= 0 && /* [HGM] check rights */
+            ( castlingRights[5] == ff || castlingRights[7] == ff ) &&
+           (ignoreCheck ||
+            (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE) &&
+              !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_LEFT+3, FALSE) &&
+              !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 2, FALSE)))) {
+
+           callback(board, flags,
+                    ff==BOARD_WIDTH>>1 ? BlackQueenSideCastle : BlackQueenSideCastleWild,
+                     BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - ((gameInfo.boardWidth+2)>>2), closure);
+       }
+    }
+
+  if(gameInfo.variant == VariantFischeRandom) {
+
+    /* generate all potential FRC castling moves (KxR), ignoring flags */
+    /* [HGM] test if the Rooks we find have castling rights */
+
+
+    if ((flags & F_WHITE_ON_MOVE) != 0) {
+        ff = castlingRights[2]; /* King file if we have any rights */
+        if(ff > 0 && board[0][ff] == WhiteKing) {
+    if (appData.debugMode) {
+        fprintf(debugFP, "FRC castling, %d %d %d %d %d %d\n",
+                castlingRights[0],castlingRights[1],ff,castlingRights[3],castlingRights[4],castlingRights[5]);
+    }
+            ft = castlingRights[0]; /* Rook file if we have H-side rights */
+            left  = ff+1;
+            right = BOARD_RGHT-2;
+            if(ff == BOARD_RGHT-2) left = right = ff-1;    /* special case */
+            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */
+                if(k != ft && board[0][k] != EmptySquare) ft = -1;
+            for(k=left; k<right && ft >= 0; k++) /* then if not checked */
+                if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = -1;
+            if(ft >= 0 && board[0][ft] == WhiteRook)
+                callback(board, flags, WhiteHSideCastleFR, 0, ff, 0, ft, closure);
+
+            ft = castlingRights[1]; /* Rook file if we have A-side rights */
+            left  = BOARD_LEFT+2;
+            right = ff-1;
+            if(ff <= BOARD_LEFT+2) { left = ff+1; right = BOARD_LEFT+3; }
+            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */
+                if(k != ft && board[0][k] != EmptySquare) ft = -1;
+            if(ff > BOARD_LEFT+2) 
+            for(k=left+1; k<=right && ft >= 0; k++) /* then if not checked */
+                if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = -1;
+            if(ft >= 0 && board[0][ft] == WhiteRook)
+                callback(board, flags, WhiteASideCastleFR, 0, ff, 0, ft, closure);
+        }
+    } else {
+        ff = castlingRights[5]; /* King file if we have any rights */
+        if(ff > 0 && board[BOARD_HEIGHT-1][ff] == BlackKing) {
+            ft = castlingRights[3]; /* Rook file if we have H-side rights */
+            left  = ff+1;
+            right = BOARD_RGHT-2;
+            if(ff == BOARD_RGHT-2) left = right = ff-1;    /* special case */
+            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */
+                if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = -1;
+            for(k=left; k<right && ft >= 0; k++) /* then if not checked */
+                if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = -1;
+            if(ft >= 0 && board[BOARD_HEIGHT-1][ft] == BlackRook)
+                callback(board, flags, BlackHSideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);
+
+            ft = castlingRights[4]; /* Rook file if we have A-side rights */
+            left  = BOARD_LEFT+2;
+            right = ff-1;
+            if(ff <= BOARD_LEFT+2) { left = ff+1; right = BOARD_LEFT+3; }
+            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */
+                if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = -1;
+            if(ff > BOARD_LEFT+2) 
+            for(k=left+1; k<=right && ft >= 0; k++) /* then if not checked */
+                if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = -1;
+            if(ft >= 0 && board[BOARD_HEIGHT-1][ft] == BlackRook)
+                callback(board, flags, BlackASideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);
+        }
+    }
+
+  }
+
+    return FALSE;
+}
+
+
+typedef struct {
+    int rking, fking;
+    int check;
+} CheckTestClosure;
+
+
+extern void CheckTestCallback P((Board board, int flags, ChessMove kind,
+                                int rf, int ff, int rt, int ft,
+                                VOIDSTAR closure));
+
+
+void CheckTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
+     Board board;
+     int flags;
+     ChessMove kind;
+     int rf, ff, rt, ft;
+     VOIDSTAR closure;
+{
+    register CheckTestClosure *cl = (CheckTestClosure *) closure;
+
+    if (rt == cl->rking && ft == cl->fking) cl->check++;
+}
+
+
+/* If the player on move were to move from (rf, ff) to (rt, ft), would
+   he leave himself in check?  Or if rf == -1, is the player on move
+   in check now?  enPassant must be TRUE if the indicated move is an
+   e.p. capture.  The possibility of castling out of a check along the
+   back rank is not accounted for (i.e., we still return nonzero), as
+   this is illegal anyway.  Return value is the number of times the
+   king is in check. */ 
+int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
+     Board board;
+     int flags;
+     int rf, ff, rt, ft, enPassant;
+{
+    CheckTestClosure cl;
+    ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing;
+    ChessSquare captured = EmptySquare;
+    /*  Suppress warnings on uninitialized variables    */
+
+    if(gameInfo.variant == VariantXiangqi)
+        king = flags & F_WHITE_ON_MOVE ? WhiteWazir : BlackWazir;
+    if(gameInfo.variant == VariantKnightmate)
+        king = flags & F_WHITE_ON_MOVE ? WhiteUnicorn : BlackUnicorn;
+
+    if (rf >= 0) {
+       if (enPassant) {
+           captured = board[rf][ft];
+           board[rf][ft] = EmptySquare;
+       } else {
+           captured = board[rt][ft];
+       }
+       board[rt][ft] = board[rf][ff];
+       board[rf][ff] = EmptySquare;
+    }
+
+    /* For compatibility with ICS wild 9, we scan the board in the
+       order a1, a2, a3, ... b1, b2, ..., h8 to find the first king,
+       and we test only whether that one is in check. */
+    cl.check = 0;
+    for (cl.fking = BOARD_LEFT+0; cl.fking < BOARD_RGHT; cl.fking++)
+       for (cl.rking = 0; cl.rking < BOARD_HEIGHT; cl.rking++) {
+          if (board[cl.rking][cl.fking] == king) {
+              if(gameInfo.variant == VariantXiangqi) {
+                  /* [HGM] In Xiangqi opposing Kings means check as well */
+                  int i, dir;
+                  dir = (king >= BlackPawn) ? -1 : 1;
+                  for( i=cl.rking+dir; i>=0 && i<BOARD_HEIGHT &&
+                                board[i][cl.fking] == EmptySquare; i+=dir );
+                  if(i>=0 && i<BOARD_HEIGHT &&
+                      board[i][cl.fking] == (dir>0 ? BlackWazir : WhiteWazir) )
+                          cl.check++;
+              }
+
+             GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, -1,
+                            CheckTestCallback, (VOIDSTAR) &cl);
+             goto undo_move;  /* 2-level break */
+         }
+      }
+
+  undo_move:
+
+    if (rf >= 0) {
+       board[rf][ff] = board[rt][ft];
+       if (enPassant) {
+           board[rf][ft] = captured;
+           board[rt][ft] = EmptySquare;
+       } else {
+           board[rt][ft] = captured;
+       }
+    }
+
+    return cl.check;
+}
+
+
+extern void LegalityTestCallback P((Board board, int flags, ChessMove kind,
+                                   int rf, int ff, int rt, int ft,
+                                   VOIDSTAR closure));
+
+void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
+     Board board;
+     int flags;
+     ChessMove kind;
+     int rf, ff, rt, ft;
+     VOIDSTAR closure;
+{
+    register LegalityTestClosure *cl = (LegalityTestClosure *) closure;
+
+//    if (appData.debugMode) {
+//        fprintf(debugFP, "Legality test: %c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE);
+//    }
+    if (rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft)
+      cl->kind = kind;
+}
+
+ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, promoChar)
+     Board board;
+     int flags, epfile;
+     int rf, ff, rt, ft, promoChar;
+     char castlingRights[];
+{
+    LegalityTestClosure cl; ChessSquare piece = board[rf][ff];
+    
+    if (appData.debugMode) {
+        int i;
+        for(i=0; i<6; i++) fprintf(debugFP, "%d ", castlingRights[i]);
+        fprintf(debugFP, "Legality test? %c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE);
+    }
+    /* [HGM] Lance, Cobra and Falcon are wildcard pieces; consider all their moves legal */
+    /* (perhaps we should disallow moves that obviously leave us in check?)              */
+    if(piece == WhiteFalcon || piece == BlackFalcon ||
+       piece == WhiteCobra  || piece == BlackCobra  ||
+       piece == WhiteLance  || piece == BlackLance)
+        return NormalMove;
+
+    cl.rf = rf;
+    cl.ff = ff;
+    cl.rt = rt;
+    cl.ft = ft;
+    cl.kind = IllegalMove;
+    GenLegal(board, flags, epfile, castlingRights, LegalityTestCallback, (VOIDSTAR) &cl);
+
+    if(gameInfo.variant == VariantShogi) {
+        /* [HGM] Shogi promotions. '=' means defer */
+        if(rf != DROP_RANK && cl.kind == NormalMove) {
+            ChessSquare piece = board[rf][ff];
+
+            if(promoChar == PieceToChar(BlackQueen)) promoChar = NULLCHAR; /* [HGM] Kludge */
+            if(promoChar != NULLCHAR && promoChar != 'x' &&
+               promoChar != '+' && promoChar != '=' &&
+               ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(promoChar) )
+                    cl.kind = IllegalMove;
+            else if(flags & F_WHITE_ON_MOVE) {
+                if( (int) piece < (int) WhiteWazir &&
+                     (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) {
+                    if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||
+                         piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */
+                             cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight;
+                    else /* promotion optional, default is promote */
+                             cl.kind = promoChar == '=' ? NormalMove  : WhitePromotionQueen;
+                   
+                } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?
+                                            NormalMove : IllegalMove;
+            } else {
+                if( (int) piece < (int) BlackWazir && (rf < 3 || rt < 3) ) {
+                    if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||
+                         piece == BlackKnight && rt < 2 ) /* promotion obligatory */
+                             cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight;
+                    else /* promotion optional, default is promote */
+                             cl.kind = promoChar == '=' ? NormalMove  : BlackPromotionQueen;
+
+                } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?
+                                            NormalMove : IllegalMove;
+            }
+        }
+    } else
+    if (promoChar != NULLCHAR && promoChar != 'x') {
+       if(promoChar == '=') cl.kind = IllegalMove; else // [HGM] shogi: no deferred promotion outside Shogi
+       if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {
+           cl.kind = 
+             PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0, promoChar);
+       } else {
+           cl.kind = IllegalMove;
+       }
+    }
+    /* [HGM] For promotions, 'ToQueen' = optional, 'ToKnight' = mandatory */
+    return cl.kind;
+}
+
+typedef struct {
+    int count;
+} MateTestClosure;
+
+extern void MateTestCallback P((Board board, int flags, ChessMove kind,
+                               int rf, int ff, int rt, int ft,
+                               VOIDSTAR closure));
+
+void MateTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
+     Board board;
+     int flags;
+     ChessMove kind;
+     int rf, ff, rt, ft;
+     VOIDSTAR closure;
+{
+    register MateTestClosure *cl = (MateTestClosure *) closure;
+
+    cl->count++;
+}
+
+/* Return MT_NONE, MT_CHECK, MT_CHECKMATE, or MT_STALEMATE */
+int MateTest(board, flags, epfile, castlingRights)
+     Board board;
+     int flags, epfile;
+     char castlingRights[];
+{
+    MateTestClosure cl;
+    int inCheck;
+
+    cl.count = 0;
+    inCheck = GenLegal(board, flags, epfile, castlingRights, MateTestCallback, (VOIDSTAR) &cl);
+    if (cl.count > 0) {
+       return inCheck ? MT_CHECK : MT_NONE;
+    } else {
+        return inCheck || gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj ?
+                         MT_CHECKMATE : MT_STALEMATE;
+    }
+}
+
+     
+extern void DisambiguateCallback P((Board board, int flags, ChessMove kind,
+                                   int rf, int ff, int rt, int ft,
+                                   VOIDSTAR closure));
+
+void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure)
+     Board board;
+     int flags;
+     ChessMove kind;
+     int rf, ff, rt, ft;
+     VOIDSTAR closure;
+{
+    register DisambiguateClosure *cl = (DisambiguateClosure *) closure;
+
+    if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]
+         || PieceToChar(board[rf][ff]) == '~'
+              && cl->pieceIn == (ChessSquare)(DEMOTED board[rf][ff])
+                                                                      ) &&
+       (cl->rfIn == -1 || cl->rfIn == rf) &&
+       (cl->ffIn == -1 || cl->ffIn == ff) &&
+       (cl->rtIn == -1 || cl->rtIn == rt) &&
+       (cl->ftIn == -1 || cl->ftIn == ft)) {
+
+       cl->count++;
+        cl->piece = board[rf][ff];
+       cl->rf = rf;
+       cl->ff = ff;
+       cl->rt = rt;
+       cl->ft = ft;
+       cl->kind = kind;
+    }
+}
+
+void Disambiguate(board, flags, epfile, closure)
+     Board board;
+     int flags, epfile;
+     DisambiguateClosure *closure;
+{
+    int illegal = 0; char c = closure->promoCharIn;
+    closure->count = 0;
+    closure->rf = closure->ff = closure->rt = closure->ft = 0;
+    closure->kind = ImpossibleMove;
+    if (appData.debugMode) {
+        fprintf(debugFP, "Disambiguate in:  %d(%d,%d)-(%d,%d) = %d (%c)\n",
+                             closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,
+                             closure->promoCharIn, closure->promoCharIn >= ' ' ? closure->promoCharIn : '-');
+    }
+    GenLegal(board, flags, epfile, initialRights, DisambiguateCallback, (VOIDSTAR) closure);
+    if (closure->count == 0) {
+       /* See if it's an illegal move due to check */
+        illegal = 1;
+        GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights, DisambiguateCallback,
+                (VOIDSTAR) closure);   
+       if (closure->count == 0) {
+           /* No, it's not even that */
+    if (appData.debugMode) { int i, j;
+       for(i=BOARD_HEIGHT-1; i>=0; i--) {
+               for(j=0; j<BOARD_WIDTH; j++)
+                       fprintf(debugFP, "%3d", (int) board[i][j]);
+               fprintf(debugFP, "\n");
+       }
+    }
+           return;
+       }
+    }
+
+    if(gameInfo.variant == VariantShogi) {
+        /* [HGM] Shogi promotions. '=' means defer */
+        if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) {
+            ChessSquare piece = closure->piece;
+#if 0
+    if (appData.debugMode) {
+        fprintf(debugFP, "Disambiguate A:   %d(%d,%d)-(%d,%d) = %d (%c)\n",
+                          closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,
+                          closure->promoCharIn,closure->promoCharIn);
+    }
+#endif
+            if(c != NULLCHAR && c != 'x' && c != '+' && c != '=' &&
+               ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(c) ) 
+                    closure->kind = IllegalMove;
+            else if(flags & F_WHITE_ON_MOVE) {
+#if 0
+    if (appData.debugMode) {
+        fprintf(debugFP, "Disambiguate B:   %d(%d,%d)-(%d,%d) = %d (%c)\n",
+                          closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,
+                          closure->promoCharIn,closure->promoCharIn);
+    }
+#endif
+                if( (int) piece < (int) WhiteWazir &&
+                     (closure->rf > BOARD_HEIGHT-4 || closure->rt > BOARD_HEIGHT-4) ) {
+                    if( (piece == WhitePawn || piece == WhiteQueen) && closure->rt > BOARD_HEIGHT-2 ||
+                         piece == WhiteKnight && closure->rt > BOARD_HEIGHT-3) /* promotion mandatory */
+                             closure->kind = c == '=' ? IllegalMove : WhitePromotionKnight;
+                    else /* promotion optional, default is promote */
+                             closure->kind = c == '=' ? NormalMove  : WhitePromotionQueen;
+                   
+                } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ?
+                                            NormalMove : IllegalMove;
+            } else {
+                if( (int) piece < (int) BlackWazir && (closure->rf < 3 || closure->rt < 3) ) {
+                    if( (piece == BlackPawn || piece == BlackQueen) && closure->rt < 1 ||
+                         piece == BlackKnight && closure->rt < 2 ) /* promotion obligatory */
+                             closure->kind = c == '=' ? IllegalMove : BlackPromotionKnight;
+                    else /* promotion optional, default is promote */
+                             closure->kind = c == '=' ? NormalMove  : BlackPromotionQueen;
+
+                } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ?
+                                            NormalMove : IllegalMove;
+            }
+        }
+    } else
+    if (closure->promoCharIn != NULLCHAR && closure->promoCharIn != 'x') {
+       if (closure->kind == WhitePromotionQueen
+           || closure->kind == BlackPromotionQueen) {
+           closure->kind = 
+             PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0,
+                                 closure->promoCharIn);
+       } else {
+           closure->kind = IllegalMove;
+       }
+    }
+#if 0
+    if (appData.debugMode) {
+        fprintf(debugFP, "Disambiguate C:   %d(%d,%d)-(%d,%d) = %d (%c)\n",
+                          closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,
+                          closure->promoCharIn,closure->promoCharIn);
+    }
+#endif
+    /* [HGM] returns 'q' for optional promotion, 'n' for mandatory */
+    if(closure->promoCharIn != '=')
+        closure->promoChar = ToLower(closure->promoCharIn);
+    else closure->promoChar = '=';
+    if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;
+    if (closure->count > 1) {
+       closure->kind = AmbiguousMove;
+    }
+    if (illegal) {
+       /* Note: If more than one illegal move matches, but no legal
+          moves, we return IllegalMove, not AmbiguousMove.  Caller
+          can look at closure->count to detect this.
+       */
+       closure->kind = IllegalMove;
+    }
+    if(closure->kind == IllegalMove)
+    /* [HGM] might be a variant we don't understand, pass on promotion info */
+        closure->promoChar = ToLower(closure->promoCharIn);
+    if (appData.debugMode) {
+        fprintf(debugFP, "Disambiguate out: %d(%d,%d)-(%d,%d) = %d (%c)\n",
+        closure->piece,closure->ff,closure->rf,closure->ft,closure->rt,closure->promoChar,
+       closure->promoChar >= ' ' ? closure->promoChar:'-');
+    }
+}
+
+
+typedef struct {
+    /* Input */
+    ChessSquare piece;
+    int rf, ff, rt, ft;
+    /* Output */
+    ChessMove kind;
+    int rank;
+    int file;
+    int either;
+} CoordsToAlgebraicClosure;
+
+extern void CoordsToAlgebraicCallback P((Board board, int flags,
+                                        ChessMove kind, int rf, int ff,
+                                        int rt, int ft, VOIDSTAR closure));
+
+void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure)
+     Board board;
+     int flags;
+     ChessMove kind;
+     int rf, ff, rt, ft;
+     VOIDSTAR closure;
+{
+    register CoordsToAlgebraicClosure *cl =
+      (CoordsToAlgebraicClosure *) closure;
+
+    if (rt == cl->rt && ft == cl->ft &&
+        (board[rf][ff] == cl->piece
+         || PieceToChar(board[rf][ff]) == '~' &&
+            (ChessSquare) (DEMOTED board[rf][ff]) == cl->piece)
+                                     ) {
+       if (rf == cl->rf) {
+           if (ff == cl->ff) {
+               cl->kind = kind; /* this is the move we want */
+           } else {
+               cl->file++; /* need file to rule out this move */
+           }
+       } else {
+           if (ff == cl->ff) {
+               cl->rank++; /* need rank to rule out this move */
+           } else {
+               cl->either++; /* rank or file will rule out this move */
+           }
+       }           
+    }
+}
+
+/* Convert coordinates to normal algebraic notation.
+   promoChar must be NULLCHAR or 'x' if not a promotion.
+*/
+ChessMove CoordsToAlgebraic(board, flags, epfile,
+                           rf, ff, rt, ft, promoChar, out)
+     Board board;
+     int flags, epfile;
+     int rf, ff, rt, ft;
+     int promoChar;
+     char out[MOVE_LEN];
+{
+    ChessSquare piece;
+    ChessMove kind;
+    char *outp = out, c;
+    CoordsToAlgebraicClosure cl;
+    
+    if (rf == DROP_RANK) {
+       /* Bughouse piece drop */
+       *outp++ = ToUpper(PieceToChar((ChessSquare) ff));
+       *outp++ = '@';
+        *outp++ = ft + AAA;
+        if(rt+ONE <= '9')
+           *outp++ = rt + ONE;
+        else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
+       *outp = NULLCHAR;
+       return (flags & F_WHITE_ON_MOVE) ? WhiteDrop : BlackDrop;
+    }
+
+    if (promoChar == 'x') promoChar = NULLCHAR;
+    piece = board[rf][ff];
+    if(PieceToChar(piece)=='~') piece = (ChessSquare)(DEMOTED piece);
+
+  if (appData.debugMode)
+          fprintf(debugFP, "CoordsToAlgebraic, piece=%d (%d,%d)-(%d,%d) %c\n", (int)piece,ff,rf,ft,rt,promoChar >= ' ' ? promoChar : '-');
+    switch (piece) {
+      case WhitePawn:
+      case BlackPawn:
+        kind = LegalityTest(board, flags, epfile, initialRights, rf, ff, rt, ft, promoChar);
+       if (kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {
+           /* Keep short notation if move is illegal only because it
+               leaves the player in check, but still return IllegalMove */
+            kind = LegalityTest(board, flags|F_IGNORE_CHECK, epfile, initialRights,
+                              rf, ff, rt, ft, promoChar);
+           if (kind == IllegalMove) break;
+           kind = IllegalMove;
+       }
+       /* Pawn move */
+        *outp++ = ff + AAA;
+        if (ff == ft && board[rt][ft] == EmptySquare) { /* [HGM] Xiangqi has straight noncapts! */
+           /* Non-capture; use style "e5" */
+            if(rt+ONE <= '9')
+               *outp++ = rt + ONE;
+            else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
+       } else {
+           /* Capture; use style "exd5" */
+            if(gameInfo.variant != VariantXiangqi || board[rt][ft] != EmptySquare )
+            *outp++ = 'x';  /* [HGM] Xiangqi has sideway noncaptures across river! */
+            *outp++ = ft + AAA;
+            if(rt+ONE <= '9')
+               *outp++ = rt + ONE;
+            else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
+       }
+       /* Use promotion suffix style "=Q" */
+       *outp = NULLCHAR;
+  if (appData.debugMode)
+          fprintf(debugFP, "movetype=%d, promochar=%d=%c\n", (int)kind, promoChar, promoChar >= ' ' ? promoChar : '-');
+        if (promoChar != NULLCHAR) {
+            if(gameInfo.variant == VariantShogi) {
+                /* [HGM] ... but not in Shogi! */
+                *outp++ = promoChar == '=' ? '=' : '+';
+            } else {
+                *outp++ = '=';
+                *outp++ = ToUpper(promoChar);
+            }
+            *outp = NULLCHAR;
+       }
+        return kind;
+
+       
+      case WhiteKing:
+      case BlackKing:
+        /* Fabien moved code: FRC castling first (if KxR), wild castling second */
+       /* Code added by Tord:  FRC castling. */
+       if((piece == WhiteKing && board[rt][ft] == WhiteRook) ||
+          (piece == BlackKing && board[rt][ft] == BlackRook)) {
+         if(ft > ff) strcpy(out, "O-O"); else strcpy(out, "O-O-O");
+            return LegalityTest(board, flags, epfile, initialRights,
+                               rf, ff, rt, ft, promoChar);
+       }
+       /* End of code added by Tord */
+       /* Test for castling or ICS wild castling */
+       /* Use style "O-O" (oh-oh) for PGN compatibility */
+       else if (rf == rt &&
+           rf == ((piece == WhiteKing) ? 0 : BOARD_HEIGHT-1) &&
+            ((ff == BOARD_WIDTH>>1 && (ft == BOARD_LEFT+2 || ft == BOARD_RGHT-2)) ||
+             (ff == (BOARD_WIDTH-1)>>1 && (ft == BOARD_LEFT+1 || ft == BOARD_RGHT-3)))) {
+            if(ft==BOARD_LEFT+1 || ft==BOARD_RGHT-2)
+               strcpy(out, "O-O");
+            else
+               strcpy(out, "O-O-O");
+
+           /* This notation is always unambiguous, unless there are
+              kings on both the d and e files, with "wild castling"
+              possible for the king on the d file and normal castling
+              possible for the other.  ICS rules for wild 9
+              effectively make castling illegal for either king in
+              this situation.  So I am not going to worry about it;
+              I'll just generate an ambiguous O-O in this case.
+           */
+            return LegalityTest(board, flags, epfile, initialRights,
+                               rf, ff, rt, ft, promoChar);
+       }
+
+       /* else fall through */
+      default:
+       /* Piece move */
+       cl.rf = rf;
+       cl.ff = ff;
+       cl.rt = rt;
+       cl.ft = ft;
+       cl.piece = piece;
+       cl.kind = IllegalMove;
+       cl.rank = cl.file = cl.either = 0;
+        GenLegal(board, flags, epfile, initialRights,
+                CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
+
+       if (cl.kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {
+           /* Generate pretty moves for moving into check, but
+              still return IllegalMove.
+           */
+            GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights,
+                    CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
+           if (cl.kind == IllegalMove) break;
+           cl.kind = IllegalMove;
+       }
+
+       /* Style is "Nf3" or "Nxf7" if this is unambiguous,
+          else "Ngf3" or "Ngxf7",
+          else "N1f3" or "N5xf7",
+          else "Ng1f3" or "Ng5xf7".
+       */
+        c = PieceToChar(piece) ;
+        if( c == '~' || c == '+') {
+           /* [HGM] print nonexistent piece as its demoted version */
+           piece = (ChessSquare) (DEMOTED piece);
+        }
+        if(c=='+') *outp++ = c;
+        *outp++ = ToUpper(PieceToChar(piece));
+
+       if (cl.file || (cl.either && !cl.rank)) {
+            *outp++ = ff + AAA;
+       }
+       if (cl.rank) {
+            if(rf+ONE <= '9')
+                *outp++ = rf + ONE;
+            else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }
+       }
+
+       if(board[rt][ft] != EmptySquare)
+         *outp++ = 'x';
+
+        *outp++ = ft + AAA;
+        if(rt+ONE <= '9')
+           *outp++ = rt + ONE;
+        else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
+       *outp = NULLCHAR;
+        if (gameInfo.variant == VariantShogi) {
+            /* [HGM] in Shogi non-pawns can promote */
+            if(flags & F_WHITE_ON_MOVE) {
+                if( (int) cl.piece < (int) WhiteWazir &&
+                     (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) {
+                    if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||
+                         piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */
+                             cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight;
+                    else cl.kind =  WhitePromotionQueen; /* promotion optional */
+                   
+                } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?
+                                            NormalMove : IllegalMove;
+            } else {
+                if( (int) cl.piece < (int) BlackWazir && (rf < 3 || rt < 3) ) {
+                    if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||
+                         piece == BlackKnight && rt < 2 ) /* promotion obligatory */
+                             cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight;
+                    else cl.kind =  BlackPromotionQueen; /* promotion optional */
+                } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?
+                                            NormalMove : IllegalMove;
+            }
+            if(cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {
+                /* for optional promotions append '+' or '=' */
+                if(promoChar == '=') {
+                    *outp++ = '=';
+                    cl.kind = NormalMove;
+                } else *outp++ = '+';
+                *outp = NULLCHAR;
+            } else if(cl.kind == IllegalMove) {
+                /* Illegal move specifies any given promotion */
+                if(promoChar != NULLCHAR && promoChar != 'x') {
+                    *outp++ = '=';
+                    *outp++ = ToUpper(promoChar);
+                    *outp = NULLCHAR;
+                }
+            }
+        }
+        return cl.kind;
+       
+      /* [HGM] Always long notation for fairies we don't know */
+      case WhiteFalcon:
+      case BlackFalcon:
+      case WhiteLance:
+      case BlackLance:
+      case WhiteGrasshopper:
+      case BlackGrasshopper:
+      case EmptySquare:
+       /* Moving a nonexistent piece */
+       break;
+    }
+    
+    /* Not a legal move, even ignoring check.
+       If there was a piece on the from square, 
+       use style "Ng1g3" or "Ng1xe8";
+       if there was a pawn or nothing (!),
+       use style "g1g3" or "g1xe8".  Use "x"
+       if a piece was on the to square, even
+       a piece of the same color.
+    */
+    outp = out;
+    if (piece != EmptySquare && piece != WhitePawn && piece != BlackPawn) {
+       *outp++ = ToUpper(PieceToChar(piece));
+    }
+    *outp++ = ff + AAA;
+    if(rf+ONE <= '9')
+       *outp++ = rf + ONE;
+    else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }
+    if (board[rt][ft] != EmptySquare) *outp++ = 'x';
+    *outp++ = ft + AAA;
+    if(rt+ONE <= '9')
+       *outp++ = rt + ONE;
+    else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
+    /* Use promotion suffix style "=Q" */
+    if (promoChar != NULLCHAR && promoChar != 'x') {
+       *outp++ = '=';
+       *outp++ = ToUpper(promoChar);
+    }
+    *outp = NULLCHAR;
+
+    return IllegalMove;
+}
+
+