-/*\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 */
-// [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
+
-/*\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;
+}
+
+