Added internal wrapping ability.
[xboard.git] / backend.c
old mode 100644 (file)
new mode 100755 (executable)
index 7dfb130..5b8dcfa
--- a/backend.c
+++ b/backend.c
-/*\r
- * backend.c -- Common back end for X and Windows NT versions of\r
- * XBoard $Id: backend.c,v 2.6 2003/11/28 09:37:36 mann Exp $\r
- *\r
- * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.\r
- * Enhancements Copyright 1992-2001 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
- * See the file ChangeLog for a revision history.  */\r
-\r
-/* [AS] Also useful here for debugging */\r
-#ifdef WIN32\r
-#include <windows.h>\r
-\r
-#define DoSleep( n ) if( (n) != 0 ) Sleep( (n) );\r
-\r
-#else\r
-\r
-#define DoSleep( n ) if( (n) >= 0) sleep(n)\r
-\r
-#endif\r
-\r
-#include "config.h"\r
-\r
-#include <assert.h>\r
-#include <stdio.h>\r
-#include <ctype.h>\r
-#include <errno.h>\r
-#include <sys/types.h>\r
-#include <sys/stat.h>\r
-#include <math.h>\r
-\r
-#if STDC_HEADERS\r
-# include <stdlib.h>\r
-# include <string.h>\r
-#else /* not STDC_HEADERS */\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
-#endif /* not STDC_HEADERS */\r
-\r
-#if HAVE_SYS_FCNTL_H\r
-# include <sys/fcntl.h>\r
-#else /* not HAVE_SYS_FCNTL_H */\r
-# if HAVE_FCNTL_H\r
-#  include <fcntl.h>\r
-# endif /* HAVE_FCNTL_H */\r
-#endif /* not HAVE_SYS_FCNTL_H */\r
-\r
-#if TIME_WITH_SYS_TIME\r
-# include <sys/time.h>\r
-# include <time.h>\r
-#else\r
-# if HAVE_SYS_TIME_H\r
-#  include <sys/time.h>\r
-# else\r
-#  include <time.h>\r
-# endif\r
-#endif\r
-\r
-#if defined(_amigados) && !defined(__GNUC__)\r
-struct timezone {\r
-    int tz_minuteswest;\r
-    int tz_dsttime;\r
-};\r
-extern int gettimeofday(struct timeval *, struct timezone *);\r
-#endif\r
-\r
-#if HAVE_UNISTD_H\r
-# include <unistd.h>\r
-#endif\r
-\r
-#include "common.h"\r
-#include "frontend.h"\r
-#include "backend.h"\r
-#include "parser.h"\r
-#include "moves.h"\r
-#if ZIPPY\r
-# include "zippy.h"\r
-#endif\r
-#include "backendz.h"\r
-#include "gettext.h" \r
\r
-#ifdef ENABLE_NLS \r
-# define _(s) gettext (s) \r
-# define N_(s) gettext_noop (s) \r
-#else \r
-# define _(s) (s) \r
-# define N_(s) s \r
-#endif \r
-\r
-\r
-/* A point in time */\r
-typedef struct {\r
-    long sec;  /* Assuming this is >= 32 bits */\r
-    int ms;    /* Assuming this is >= 16 bits */\r
-} TimeMark;\r
-\r
-int establish P((void));\r
-void read_from_player P((InputSourceRef isr, VOIDSTAR closure,\r
-                        char *buf, int count, int error));\r
-void read_from_ics P((InputSourceRef isr, VOIDSTAR closure,\r
-                     char *buf, int count, int error));\r
-void SendToICS P((char *s));\r
-void SendToICSDelayed P((char *s, long msdelay));\r
-void SendMoveToICS P((ChessMove moveType, int fromX, int fromY,\r
-                     int toX, int toY));\r
-void InitPosition P((int redraw));\r
-void HandleMachineMove P((char *message, ChessProgramState *cps));\r
-int AutoPlayOneMove P((void));\r
-int LoadGameOneMove P((ChessMove readAhead));\r
-int LoadGameFromFile P((char *filename, int n, char *title, int useList));\r
-int LoadPositionFromFile P((char *filename, int n, char *title));\r
-int SavePositionToFile P((char *filename));\r
-void ApplyMove P((int fromX, int fromY, int toX, int toY, int promoChar,\r
-                 Board board));\r
-void MakeMove P((int fromX, int fromY, int toX, int toY, int promoChar));\r
-void ShowMove P((int fromX, int fromY, int toX, int toY));\r
-int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,\r
-                  /*char*/int promoChar));\r
-void BackwardInner P((int target));\r
-void ForwardInner P((int target));\r
-void GameEnds P((ChessMove result, char *resultDetails, int whosays));\r
-void EditPositionDone P((void));\r
-void PrintOpponents P((FILE *fp));\r
-void PrintPosition P((FILE *fp, int move));\r
-void StartChessProgram P((ChessProgramState *cps));\r
-void SendToProgram P((char *message, ChessProgramState *cps));\r
-void SendMoveToProgram P((int moveNum, ChessProgramState *cps));\r
-void ReceiveFromProgram P((InputSourceRef isr, VOIDSTAR closure,\r
-                          char *buf, int count, int error));\r
-void SendTimeControl P((ChessProgramState *cps,\r
-                       int mps, long tc, int inc, int sd, int st));\r
-char *TimeControlTagValue P((void));\r
-void Attention P((ChessProgramState *cps));\r
-void FeedMovesToProgram P((ChessProgramState *cps, int upto));\r
-void ResurrectChessProgram P((void));\r
-void DisplayComment P((int moveNumber, char *text));\r
-void DisplayMove P((int moveNumber));\r
-void DisplayAnalysis P((void));\r
-\r
-void ParseGameHistory P((char *game));\r
-void ParseBoard12 P((char *string));\r
-void StartClocks P((void));\r
-void SwitchClocks P((void));\r
-void StopClocks P((void));\r
-void ResetClocks P((void));\r
-char *PGNDate P((void));\r
-void SetGameInfo P((void));\r
-Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));\r
-int RegisterMove P((void));\r
-void MakeRegisteredMove P((void));\r
-void TruncateGame P((void));\r
-int looking_at P((char *, int *, char *));\r
-void CopyPlayerNameIntoFileName P((char **, char *));\r
-char *SavePart P((char *));\r
-int SaveGameOldStyle P((FILE *));\r
-int SaveGamePGN P((FILE *));\r
-void GetTimeMark P((TimeMark *));\r
-long SubtractTimeMarks P((TimeMark *, TimeMark *));\r
-int CheckFlags P((void));\r
-long NextTickLength P((long));\r
-void CheckTimeControl P((void));\r
-void show_bytes P((FILE *, char *, int));\r
-int string_to_rating P((char *str));\r
-void ParseFeatures P((char* args, ChessProgramState *cps));\r
-void InitBackEnd3 P((void));\r
-void FeatureDone P((ChessProgramState* cps, int val));\r
-void InitChessProgram P((ChessProgramState *cps, int setup));\r
-\r
-#ifdef WIN32\r
-       extern void ConsoleCreate();\r
-#endif\r
-\r
-ChessProgramState *WhitePlayer();\r
-void InsertIntoMemo P((int which, char *text)); // [HGM] kibitz: in engineo.c\r
-int VerifyDisplayMode P(());\r
-\r
-char *GetInfoFromComment( int, char * ); // [HGM] PV time: returns stripped comment\r
-void InitEngineUCI( const char * iniDir, ChessProgramState * cps ); // [HGM] moved here from winboard.c\r
-char *ProbeBook P((int moveNr, char *book)); // [HGM] book: returns a book move\r
-char *SendMoveToBookUser P((int nr, ChessProgramState *cps, int initial)); // [HGM] book\r
-extern char installDir[MSG_SIZ];\r
-\r
-extern int tinyLayout, smallLayout;\r
-ChessProgramStats programStats;\r
-static int exiting = 0; /* [HGM] moved to top */\r
-static int setboardSpoiledMachineBlack = 0, errorExitFlag = 0;\r
-extern int startedFromPositionFile;\r
-int startedFromPositionFile = FALSE; Board filePosition;       /* [HGM] loadPos */\r
-char endingGame = 0;    /* [HGM] crash: flag to prevent recursion of GameEnds() */\r
-int whiteNPS, blackNPS; /* [HGM] nps: for easily making clocks aware of NPS     */\r
-VariantClass currentlyInitializedVariant; /* [HGM] variantswitch */\r
-int lastIndex = 0;      /* [HGM] autoinc: last game/position used in match mode */\r
-int opponentKibitzes;\r
-\r
-/* States for ics_getting_history */\r
-#define H_FALSE 0\r
-#define H_REQUESTED 1\r
-#define H_GOT_REQ_HEADER 2\r
-#define H_GOT_UNREQ_HEADER 3\r
-#define H_GETTING_MOVES 4\r
-#define H_GOT_UNWANTED_HEADER 5\r
-\r
-/* whosays values for GameEnds */\r
-#define GE_ICS 0\r
-#define GE_ENGINE 1\r
-#define GE_PLAYER 2\r
-#define GE_FILE 3\r
-#define GE_XBOARD 4\r
-#define GE_ENGINE1 5\r
-#define GE_ENGINE2 6\r
-\r
-/* Maximum number of games in a cmail message */\r
-#define CMAIL_MAX_GAMES 20\r
-\r
-/* Different types of move when calling RegisterMove */\r
-#define CMAIL_MOVE   0\r
-#define CMAIL_RESIGN 1\r
-#define CMAIL_DRAW   2\r
-#define CMAIL_ACCEPT 3\r
-\r
-/* Different types of result to remember for each game */\r
-#define CMAIL_NOT_RESULT 0\r
-#define CMAIL_OLD_RESULT 1\r
-#define CMAIL_NEW_RESULT 2\r
-\r
-/* Telnet protocol constants */\r
-#define TN_WILL 0373\r
-#define TN_WONT 0374\r
-#define TN_DO   0375\r
-#define TN_DONT 0376\r
-#define TN_IAC  0377\r
-#define TN_ECHO 0001\r
-#define TN_SGA  0003\r
-#define TN_PORT 23\r
-\r
-/* [AS] */\r
-static char * safeStrCpy( char * dst, const char * src, size_t count )\r
-{\r
-    assert( dst != NULL );\r
-    assert( src != NULL );\r
-    assert( count > 0 );\r
-\r
-    strncpy( dst, src, count );\r
-    dst[ count-1 ] = '\0';\r
-    return dst;\r
-}\r
-\r
-static char * safeStrCat( char * dst, const char * src, size_t count )\r
-{\r
-    size_t  dst_len;\r
-\r
-    assert( dst != NULL );\r
-    assert( src != NULL );\r
-    assert( count > 0 );\r
-\r
-    dst_len = strlen(dst);\r
-\r
-    assert( count > dst_len ); /* Buffer size must be greater than current length */\r
-\r
-    safeStrCpy( dst + dst_len, src, count - dst_len );\r
-\r
-    return dst;\r
-}\r
-\r
-/* Some compiler can't cast u64 to double\r
- * This function do the job for us:\r
-\r
- * We use the highest bit for cast, this only\r
- * works if the highest bit is not\r
- * in use (This should not happen)\r
- *\r
- * We used this for all compiler\r
- */\r
-double\r
-u64ToDouble(u64 value)\r
-{\r
-  double r;\r
-  u64 tmp = value & u64Const(0x7fffffffffffffff);\r
-  r = (double)(s64)tmp;\r
-  if (value & u64Const(0x8000000000000000))\r
-       r +=  9.2233720368547758080e18; /* 2^63 */\r
- return r;\r
-}\r
-\r
-/* Fake up flags for now, as we aren't keeping track of castling\r
-   availability yet. [HGM] Change of logic: the flag now only\r
-   indicates the type of castlings allowed by the rule of the game.\r
-   The actual rights themselves are maintained in the array\r
-   castlingRights, as part of the game history, and are not probed\r
-   by this function.\r
- */\r
-int\r
-PosFlags(index)\r
-{\r
-  int flags = F_ALL_CASTLE_OK;\r
-  if ((index % 2) == 0) flags |= F_WHITE_ON_MOVE;\r
-  switch (gameInfo.variant) {\r
-  case VariantSuicide:\r
-    flags &= ~F_ALL_CASTLE_OK;\r
-  case VariantGiveaway:                // [HGM] moved this case label one down: seems Giveaway does have castling on ICC!\r
-    flags |= F_IGNORE_CHECK;\r
-    break;\r
-  case VariantAtomic:\r
-    flags |= F_IGNORE_CHECK | F_ATOMIC_CAPTURE;\r
-    break;\r
-  case VariantKriegspiel:\r
-    flags |= F_KRIEGSPIEL_CAPTURE;\r
-    break;\r
-  case VariantCapaRandom: \r
-  case VariantFischeRandom:\r
-    flags |= F_FRC_TYPE_CASTLING; /* [HGM] enable this through flag */\r
-  case VariantNoCastle:\r
-  case VariantShatranj:\r
-  case VariantCourier:\r
-    flags &= ~F_ALL_CASTLE_OK;\r
-    break;\r
-  default:\r
-    break;\r
-  }\r
-  return flags;\r
-}\r
-\r
-FILE *gameFileFP, *debugFP;\r
-\r
-/* \r
-    [AS] Note: sometimes, the sscanf() function is used to parse the input\r
-    into a fixed-size buffer. Because of this, we must be prepared to\r
-    receive strings as long as the size of the input buffer, which is currently\r
-    set to 4K for Windows and 8K for the rest.\r
-    So, we must either allocate sufficiently large buffers here, or\r
-    reduce the size of the input buffer in the input reading part.\r
-*/\r
-\r
-char cmailMove[CMAIL_MAX_GAMES][MOVE_LEN], cmailMsg[MSG_SIZ];\r
-char bookOutput[MSG_SIZ*10], thinkOutput[MSG_SIZ*10], lastHint[MSG_SIZ];\r
-char thinkOutput1[MSG_SIZ*10];\r
-\r
-ChessProgramState first, second;\r
-\r
-/* premove variables */\r
-int premoveToX = 0;\r
-int premoveToY = 0;\r
-int premoveFromX = 0;\r
-int premoveFromY = 0;\r
-int premovePromoChar = 0;\r
-int gotPremove = 0;\r
-Boolean alarmSounded;\r
-/* end premove variables */\r
-\r
-char *ics_prefix = "$";\r
-int ics_type = ICS_GENERIC;\r
-\r
-int currentMove = 0, forwardMostMove = 0, backwardMostMove = 0;\r
-int pauseExamForwardMostMove = 0;\r
-int nCmailGames = 0, nCmailResults = 0, nCmailMovesRegistered = 0;\r
-int cmailMoveRegistered[CMAIL_MAX_GAMES], cmailResult[CMAIL_MAX_GAMES];\r
-int cmailMsgLoaded = FALSE, cmailMailedMove = FALSE;\r
-int cmailOldMove = -1, firstMove = TRUE, flipView = FALSE;\r
-int blackPlaysFirst = FALSE, startedFromSetupPosition = FALSE;\r
-int searchTime = 0, pausing = FALSE, pauseExamInvalid = FALSE;\r
-int whiteFlag = FALSE, blackFlag = FALSE;\r
-int userOfferedDraw = FALSE;\r
-int ics_user_moved = 0, ics_gamenum = -1, ics_getting_history = H_FALSE;\r
-int matchMode = FALSE, hintRequested = FALSE, bookRequested = FALSE;\r
-int cmailMoveType[CMAIL_MAX_GAMES];\r
-long ics_clock_paused = 0;\r
-ProcRef icsPR = NoProc, cmailPR = NoProc;\r
-InputSourceRef telnetISR = NULL, fromUserISR = NULL, cmailISR = NULL;\r
-GameMode gameMode = BeginningOfGame;\r
-char moveList[MAX_MOVES][MOVE_LEN], parseList[MAX_MOVES][MOVE_LEN * 2];\r
-char *commentList[MAX_MOVES], *cmailCommentList[CMAIL_MAX_GAMES];\r
-ChessProgramStats_Move pvInfoList[MAX_MOVES]; /* [AS] Info about engine thinking */\r
-int hiddenThinkOutputState = 0; /* [AS] */\r
-int adjudicateLossThreshold = 0; /* [AS] Automatic adjudication */\r
-int adjudicateLossPlies = 6;\r
-char white_holding[64], black_holding[64];\r
-TimeMark lastNodeCountTime;\r
-long lastNodeCount=0;\r
-int have_sent_ICS_logon = 0;\r
-int movesPerSession;\r
-long whiteTimeRemaining, blackTimeRemaining, timeControl, timeIncrement;\r
-long timeControl_2; /* [AS] Allow separate time controls */\r
-char *fullTimeControlString = NULL; /* [HGM] secondary TC: merge of MPS, TC and inc */\r
-long timeRemaining[2][MAX_MOVES];\r
-int matchGame = 0;\r
-TimeMark programStartTime;\r
-char ics_handle[MSG_SIZ];\r
-int have_set_title = 0;\r
-\r
-/* animateTraining preserves the state of appData.animate\r
- * when Training mode is activated. This allows the\r
- * response to be animated when appData.animate == TRUE and\r
- * appData.animateDragging == TRUE.\r
- */\r
-Boolean animateTraining;\r
-\r
-GameInfo gameInfo;\r
-\r
-AppData appData;\r
-\r
-Board boards[MAX_MOVES];\r
-/* [HGM] Following 7 needed for accurate legality tests: */\r
-char  epStatus[MAX_MOVES];\r
-char  castlingRights[MAX_MOVES][BOARD_SIZE]; // stores files for pieces with castling rights or -1\r
-char  castlingRank[BOARD_SIZE]; // and corresponding ranks\r
-char  initialRights[BOARD_SIZE], FENcastlingRights[BOARD_SIZE], fileRights[BOARD_SIZE];\r
-int   nrCastlingRights; // For TwoKings, or to implement castling-unknown status\r
-int   initialRulePlies, FENrulePlies;\r
-char  FENepStatus;\r
-FILE  *serverMoves = NULL; // next two for broadcasting (/serverMoves option)\r
-int loadFlag = 0; \r
-int shuffleOpenings;\r
-\r
-ChessSquare  FIDEArray[2][BOARD_SIZE] = {\r
-    { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen,\r
-       WhiteKing, WhiteBishop, WhiteKnight, WhiteRook },\r
-    { BlackRook, BlackKnight, BlackBishop, BlackQueen,\r
-       BlackKing, BlackBishop, BlackKnight, BlackRook }\r
-};\r
-\r
-ChessSquare twoKingsArray[2][BOARD_SIZE] = {\r
-    { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen,\r
-       WhiteKing, WhiteKing, WhiteKnight, WhiteRook },\r
-    { BlackRook, BlackKnight, BlackBishop, BlackQueen,\r
-        BlackKing, BlackKing, BlackKnight, BlackRook }\r
-};\r
-\r
-ChessSquare  KnightmateArray[2][BOARD_SIZE] = {\r
-    { WhiteRook, WhiteMan, WhiteBishop, WhiteQueen,\r
-        WhiteUnicorn, WhiteBishop, WhiteMan, WhiteRook },\r
-    { BlackRook, BlackMan, BlackBishop, BlackQueen,\r
-        BlackUnicorn, BlackBishop, BlackMan, BlackRook }\r
-};\r
-\r
-ChessSquare fairyArray[2][BOARD_SIZE] = { /* [HGM] Queen side differs from King side */\r
-    { WhiteCannon, WhiteNightrider, WhiteAlfil, WhiteQueen,\r
-        WhiteKing, WhiteBishop, WhiteKnight, WhiteRook },\r
-    { BlackCannon, BlackNightrider, BlackAlfil, BlackQueen,\r
-       BlackKing, BlackBishop, BlackKnight, BlackRook }\r
-};\r
-\r
-ChessSquare ShatranjArray[2][BOARD_SIZE] = { /* [HGM] (movGen knows about Shatranj Q and P) */\r
-    { WhiteRook, WhiteKnight, WhiteAlfil, WhiteKing,\r
-        WhiteFerz, WhiteAlfil, WhiteKnight, WhiteRook },\r
-    { BlackRook, BlackKnight, BlackAlfil, BlackKing,\r
-        BlackFerz, BlackAlfil, BlackKnight, BlackRook }\r
-};\r
-\r
-\r
-#if (BOARD_SIZE>=10)\r
-ChessSquare ShogiArray[2][BOARD_SIZE] = {\r
-    { WhiteQueen, WhiteKnight, WhiteFerz, WhiteWazir,\r
-        WhiteKing, WhiteWazir, WhiteFerz, WhiteKnight, WhiteQueen },\r
-    { BlackQueen, BlackKnight, BlackFerz, BlackWazir,\r
-        BlackKing, BlackWazir, BlackFerz, BlackKnight, BlackQueen }\r
-};\r
-\r
-ChessSquare XiangqiArray[2][BOARD_SIZE] = {\r
-    { WhiteRook, WhiteKnight, WhiteAlfil, WhiteFerz,\r
-        WhiteWazir, WhiteFerz, WhiteAlfil, WhiteKnight, WhiteRook },\r
-    { BlackRook, BlackKnight, BlackAlfil, BlackFerz,\r
-        BlackWazir, BlackFerz, BlackAlfil, BlackKnight, BlackRook }\r
-};\r
-\r
-ChessSquare CapablancaArray[2][BOARD_SIZE] = {\r
-    { WhiteRook, WhiteKnight, WhiteAngel, WhiteBishop, WhiteQueen, \r
-        WhiteKing, WhiteBishop, WhiteMarshall, WhiteKnight, WhiteRook },\r
-    { BlackRook, BlackKnight, BlackAngel, BlackBishop, BlackQueen, \r
-        BlackKing, BlackBishop, BlackMarshall, BlackKnight, BlackRook }\r
-};\r
-\r
-ChessSquare GreatArray[2][BOARD_SIZE] = {\r
-    { WhiteDragon, WhiteKnight, WhiteAlfil, WhiteGrasshopper, WhiteKing, \r
-        WhiteSilver, WhiteCardinal, WhiteAlfil, WhiteKnight, WhiteDragon },\r
-    { BlackDragon, BlackKnight, BlackAlfil, BlackGrasshopper, BlackKing, \r
-        BlackSilver, BlackCardinal, BlackAlfil, BlackKnight, BlackDragon },\r
-};\r
-\r
-ChessSquare JanusArray[2][BOARD_SIZE] = {\r
-    { WhiteRook, WhiteAngel, WhiteKnight, WhiteBishop, WhiteKing, \r
-        WhiteQueen, WhiteBishop, WhiteKnight, WhiteAngel, WhiteRook },\r
-    { BlackRook, BlackAngel, BlackKnight, BlackBishop, BlackKing, \r
-        BlackQueen, BlackBishop, BlackKnight, BlackAngel, BlackRook }\r
-};\r
-\r
-#ifdef GOTHIC\r
-ChessSquare GothicArray[2][BOARD_SIZE] = {\r
-    { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen, WhiteMarshall, \r
-        WhiteKing, WhiteAngel, WhiteBishop, WhiteKnight, WhiteRook },\r
-    { BlackRook, BlackKnight, BlackBishop, BlackQueen, BlackMarshall, \r
-        BlackKing, BlackAngel, BlackBishop, BlackKnight, BlackRook }\r
-};\r
-#else // !GOTHIC\r
-#define GothicArray CapablancaArray\r
-#endif // !GOTHIC\r
-\r
-#ifdef FALCON\r
-ChessSquare FalconArray[2][BOARD_SIZE] = {\r
-    { WhiteRook, WhiteKnight, WhiteBishop, WhiteLance, WhiteQueen, \r
-        WhiteKing, WhiteLance, WhiteBishop, WhiteKnight, WhiteRook },\r
-    { BlackRook, BlackKnight, BlackBishop, BlackLance, BlackQueen, \r
-        BlackKing, BlackLance, BlackBishop, BlackKnight, BlackRook }\r
-};\r
-#else // !FALCON\r
-#define FalconArray CapablancaArray\r
-#endif // !FALCON\r
-\r
-#else // !(BOARD_SIZE>=10)\r
-#define XiangqiPosition FIDEArray\r
-#define CapablancaArray FIDEArray\r
-#define GothicArray FIDEArray\r
-#define GreatArray FIDEArray\r
-#endif // !(BOARD_SIZE>=10)\r
-\r
-#if (BOARD_SIZE>=12)\r
-ChessSquare CourierArray[2][BOARD_SIZE] = {\r
-    { WhiteRook, WhiteKnight, WhiteAlfil, WhiteBishop, WhiteMan, WhiteKing,\r
-        WhiteFerz, WhiteWazir, WhiteBishop, WhiteAlfil, WhiteKnight, WhiteRook },\r
-    { BlackRook, BlackKnight, BlackAlfil, BlackBishop, BlackMan, BlackKing,\r
-        BlackFerz, BlackWazir, BlackBishop, BlackAlfil, BlackKnight, BlackRook }\r
-};\r
-#else // !(BOARD_SIZE>=12)\r
-#define CourierArray CapablancaArray\r
-#endif // !(BOARD_SIZE>=12)\r
-\r
-\r
-Board initialPosition;\r
-\r
-\r
-/* Convert str to a rating. Checks for special cases of "----",\r
-\r
-   "++++", etc. Also strips ()'s */\r
-int\r
-string_to_rating(str)\r
-  char *str;\r
-{\r
-  while(*str && !isdigit(*str)) ++str;\r
-  if (!*str)\r
-    return 0;  /* One of the special "no rating" cases */\r
-  else\r
-    return atoi(str);\r
-}\r
-\r
-void\r
-ClearProgramStats()\r
-{\r
-    /* Init programStats */\r
-    programStats.movelist[0] = 0;\r
-    programStats.depth = 0;\r
-    programStats.nr_moves = 0;\r
-    programStats.moves_left = 0;\r
-    programStats.nodes = 0;\r
-    programStats.time = -1;        // [HGM] PGNtime: make invalid to recognize engine output\r
-    programStats.score = 0;\r
-    programStats.got_only_move = 0;\r
-    programStats.got_fail = 0;\r
-    programStats.line_is_book = 0;\r
-}\r
-\r
-void\r
-InitBackEnd1()\r
-{\r
-    int matched, min, sec;\r
-\r
-    ShowThinkingEvent(); // [HGM] thinking: make sure post/nopost state is set according to options\r
-\r
-    GetTimeMark(&programStartTime);\r
-\r
-    ClearProgramStats();\r
-    programStats.ok_to_send = 1;\r
-    programStats.seen_stat = 0;\r
-\r
-    /*\r
-     * Initialize game list\r
-     */\r
-    ListNew(&gameList);\r
-\r
-\r
-    /*\r
-     * Internet chess server status\r
-     */\r
-    if (appData.icsActive) {\r
-       appData.matchMode = FALSE;\r
-       appData.matchGames = 0;\r
-#if ZIPPY      \r
-       appData.noChessProgram = !appData.zippyPlay;\r
-#else\r
-       appData.zippyPlay = FALSE;\r
-       appData.zippyTalk = FALSE;\r
-       appData.noChessProgram = TRUE;\r
-#endif\r
-       if (*appData.icsHelper != NULLCHAR) {\r
-           appData.useTelnet = TRUE;\r
-           appData.telnetProgram = appData.icsHelper;\r
-       }\r
-    } else {\r
-       appData.zippyTalk = appData.zippyPlay = FALSE;\r
-    }\r
-\r
-    /* [AS] Initialize pv info list [HGM] and game state */\r
-    {\r
-        int i, j;\r
-\r
-        for( i=0; i<MAX_MOVES; i++ ) {\r
-            pvInfoList[i].depth = -1;\r
-            epStatus[i]=EP_NONE;\r
-            for( j=0; j<BOARD_SIZE; j++ ) castlingRights[i][j] = -1;\r
-        }\r
-    }\r
-\r
-    /*\r
-     * Parse timeControl resource\r
-     */\r
-    if (!ParseTimeControl(appData.timeControl, appData.timeIncrement,\r
-                         appData.movesPerSession)) {\r
-       char buf[MSG_SIZ];\r
-       sprintf(buf, _("bad timeControl option %s"), appData.timeControl);\r
-       DisplayFatalError(buf, 0, 2);\r
-    }\r
-\r
-    /*\r
-     * Parse searchTime resource\r
-     */\r
-    if (*appData.searchTime != NULLCHAR) {\r
-       matched = sscanf(appData.searchTime, "%d:%d", &min, &sec);\r
-       if (matched == 1) {\r
-           searchTime = min * 60;\r
-       } else if (matched == 2) {\r
-           searchTime = min * 60 + sec;\r
-       } else {\r
-           char buf[MSG_SIZ];\r
-           sprintf(buf, _("bad searchTime option %s"), appData.searchTime);\r
-           DisplayFatalError(buf, 0, 2);\r
-       }\r
-    }\r
-\r
-    /* [AS] Adjudication threshold */\r
-    adjudicateLossThreshold = appData.adjudicateLossThreshold;\r
-    \r
-    first.which = "first";\r
-    second.which = "second";\r
-    first.maybeThinking = second.maybeThinking = FALSE;\r
-    first.pr = second.pr = NoProc;\r
-    first.isr = second.isr = NULL;\r
-    first.sendTime = second.sendTime = 2;\r
-    first.sendDrawOffers = 1;\r
-    if (appData.firstPlaysBlack) {\r
-       first.twoMachinesColor = "black\n";\r
-       second.twoMachinesColor = "white\n";\r
-    } else {\r
-       first.twoMachinesColor = "white\n";\r
-       second.twoMachinesColor = "black\n";\r
-    }\r
-    first.program = appData.firstChessProgram;\r
-    second.program = appData.secondChessProgram;\r
-    first.host = appData.firstHost;\r
-    second.host = appData.secondHost;\r
-    first.dir = appData.firstDirectory;\r
-    second.dir = appData.secondDirectory;\r
-    first.other = &second;\r
-    second.other = &first;\r
-    first.initString = appData.initString;\r
-    second.initString = appData.secondInitString;\r
-    first.computerString = appData.firstComputerString;\r
-    second.computerString = appData.secondComputerString;\r
-    first.useSigint = second.useSigint = TRUE;\r
-    first.useSigterm = second.useSigterm = TRUE;\r
-    first.reuse = appData.reuseFirst;\r
-    second.reuse = appData.reuseSecond;\r
-    first.nps = appData.firstNPS;   // [HGM] nps: copy nodes per second\r
-    second.nps = appData.secondNPS;\r
-    first.useSetboard = second.useSetboard = FALSE;\r
-    first.useSAN = second.useSAN = FALSE;\r
-    first.usePing = second.usePing = FALSE;\r
-    first.lastPing = second.lastPing = 0;\r
-    first.lastPong = second.lastPong = 0;\r
-    first.usePlayother = second.usePlayother = FALSE;\r
-    first.useColors = second.useColors = TRUE;\r
-    first.useUsermove = second.useUsermove = FALSE;\r
-    first.sendICS = second.sendICS = FALSE;\r
-    first.sendName = second.sendName = appData.icsActive;\r
-    first.sdKludge = second.sdKludge = FALSE;\r
-    first.stKludge = second.stKludge = FALSE;\r
-    TidyProgramName(first.program, first.host, first.tidy);\r
-    TidyProgramName(second.program, second.host, second.tidy);\r
-    first.matchWins = second.matchWins = 0;\r
-    strcpy(first.variants, appData.variant);\r
-    strcpy(second.variants, appData.variant);\r
-    first.analysisSupport = second.analysisSupport = 2; /* detect */\r
-    first.analyzing = second.analyzing = FALSE;\r
-    first.initDone = second.initDone = FALSE;\r
-\r
-    /* New features added by Tord: */\r
-    first.useFEN960 = FALSE; second.useFEN960 = FALSE;\r
-    first.useOOCastle = TRUE; second.useOOCastle = TRUE;\r
-    /* End of new features added by Tord. */\r
-\r
-    /* [HGM] time odds: set factor for each machine */\r
-    first.timeOdds  = appData.firstTimeOdds;\r
-    second.timeOdds = appData.secondTimeOdds;\r
-    { int norm = 1;\r
-        if(appData.timeOddsMode) {\r
-            norm = first.timeOdds;\r
-            if(norm > second.timeOdds) norm = second.timeOdds;\r
-        }\r
-        first.timeOdds /= norm;\r
-        second.timeOdds /= norm;\r
-    }\r
-\r
-    /* [HGM] secondary TC: how to handle sessions that do not fit in 'level'*/\r
-    first.accumulateTC = appData.firstAccumulateTC;\r
-    second.accumulateTC = appData.secondAccumulateTC;\r
-    first.maxNrOfSessions = second.maxNrOfSessions = 1;\r
-\r
-    /* [HGM] debug */\r
-    first.debug = second.debug = FALSE;\r
-    first.supportsNPS = second.supportsNPS = UNKNOWN;\r
-\r
-    /* [HGM] options */\r
-    first.optionSettings  = appData.firstOptions;\r
-    second.optionSettings = appData.secondOptions;\r
-\r
-    first.scoreIsAbsolute = appData.firstScoreIsAbsolute; /* [AS] */\r
-    second.scoreIsAbsolute = appData.secondScoreIsAbsolute; /* [AS] */\r
-    first.isUCI = appData.firstIsUCI; /* [AS] */\r
-    second.isUCI = appData.secondIsUCI; /* [AS] */\r
-    first.hasOwnBookUCI = appData.firstHasOwnBookUCI; /* [AS] */\r
-    second.hasOwnBookUCI = appData.secondHasOwnBookUCI; /* [AS] */\r
-\r
-    if (appData.firstProtocolVersion > PROTOVER ||\r
-       appData.firstProtocolVersion < 1) {\r
-      char buf[MSG_SIZ];\r
-      sprintf(buf, _("protocol version %d not supported"),\r
-             appData.firstProtocolVersion);\r
-      DisplayFatalError(buf, 0, 2);\r
-    } else {\r
-      first.protocolVersion = appData.firstProtocolVersion;\r
-    }\r
-\r
-    if (appData.secondProtocolVersion > PROTOVER ||\r
-       appData.secondProtocolVersion < 1) {\r
-      char buf[MSG_SIZ];\r
-      sprintf(buf, _("protocol version %d not supported"),\r
-             appData.secondProtocolVersion);\r
-      DisplayFatalError(buf, 0, 2);\r
-    } else {\r
-      second.protocolVersion = appData.secondProtocolVersion;\r
-    }\r
-\r
-    if (appData.icsActive) {\r
-        appData.clockMode = TRUE;  /* changes dynamically in ICS mode */\r
-    } else if (*appData.searchTime != NULLCHAR || appData.noChessProgram) {\r
-       appData.clockMode = FALSE;\r
-       first.sendTime = second.sendTime = 0;\r
-    }\r
-    \r
-#if ZIPPY\r
-    /* Override some settings from environment variables, for backward\r
-       compatibility.  Unfortunately it's not feasible to have the env\r
-       vars just set defaults, at least in xboard.  Ugh.\r
-    */\r
-    if (appData.icsActive && (appData.zippyPlay || appData.zippyTalk)) {\r
-      ZippyInit();\r
-    }\r
-#endif\r
-    \r
-    if (appData.noChessProgram) {\r
-       programVersion = (char*) malloc(5 + strlen(PRODUCT) + strlen(VERSION)\r
-                                       + strlen(PATCHLEVEL));\r
-       sprintf(programVersion, "%s %s.%s", PRODUCT, VERSION, PATCHLEVEL);\r
-    } else {\r
-#if 0\r
-       char *p, *q;\r
-       q = first.program;\r
-       while (*q != ' ' && *q != NULLCHAR) q++;\r
-       p = q;\r
-       while (p > first.program && *(p-1) != '/' && *(p-1) != '\\') p--; /* [HGM] bckslash added */\r
-       programVersion = (char*) malloc(8 + strlen(PRODUCT) + strlen(VERSION)\r
-                                       + strlen(PATCHLEVEL) + (q - p));\r
-       sprintf(programVersion, "%s %s.%s + ", PRODUCT, VERSION, PATCHLEVEL);\r
-       strncat(programVersion, p, q - p);\r
-#else\r
-       /* [HGM] tidy: use tidy name, in stead of full pathname (which was probably a bug due to / vs \ ) */\r
-       programVersion = (char*) malloc(8 + strlen(PRODUCT) + strlen(VERSION)\r
-                                       + strlen(PATCHLEVEL) + strlen(first.tidy));\r
-       sprintf(programVersion, "%s %s.%s + %s", PRODUCT, VERSION, PATCHLEVEL, first.tidy);\r
-#endif\r
-    }\r
-\r
-    if (!appData.icsActive) {\r
-      char buf[MSG_SIZ];\r
-      /* Check for variants that are supported only in ICS mode,\r
-         or not at all.  Some that are accepted here nevertheless\r
-         have bugs; see comments below.\r
-      */\r
-      VariantClass variant = StringToVariant(appData.variant);\r
-      switch (variant) {\r
-      case VariantBughouse:     /* need four players and two boards */\r
-      case VariantKriegspiel:   /* need to hide pieces and move details */\r
-      /* case VariantFischeRandom: (Fabien: moved below) */\r
-       sprintf(buf, _("Variant %s supported only in ICS mode"), appData.variant);\r
-       DisplayFatalError(buf, 0, 2);\r
-       return;\r
-\r
-      case VariantUnknown:\r
-      case VariantLoadable:\r
-      case Variant29:\r
-      case Variant30:\r
-      case Variant31:\r
-      case Variant32:\r
-      case Variant33:\r
-      case Variant34:\r
-      case Variant35:\r
-      case Variant36:\r
-      default:\r
-       sprintf(buf, _("Unknown variant name %s"), appData.variant);\r
-       DisplayFatalError(buf, 0, 2);\r
-       return;\r
-\r
-      case VariantXiangqi:    /* [HGM] repetition rules not implemented */\r
-      case VariantFairy:      /* [HGM] TestLegality definitely off! */\r
-      case VariantGothic:     /* [HGM] should work */\r
-      case VariantCapablanca: /* [HGM] should work */\r
-      case VariantCourier:    /* [HGM] initial forced moves not implemented */\r
-      case VariantShogi:      /* [HGM] drops not tested for legality */\r
-      case VariantKnightmate: /* [HGM] should work */\r
-      case VariantCylinder:   /* [HGM] untested */\r
-      case VariantFalcon:     /* [HGM] untested */\r
-      case VariantCrazyhouse: /* holdings not shown, ([HGM] fixed that!)\r
-                                offboard interposition not understood */\r
-      case VariantNormal:     /* definitely works! */\r
-      case VariantWildCastle: /* pieces not automatically shuffled */\r
-      case VariantNoCastle:   /* pieces not automatically shuffled */\r
-      case VariantFischeRandom: /* [HGM] works and shuffles pieces */\r
-      case VariantLosers:     /* should work except for win condition,\r
-                                and doesn't know captures are mandatory */\r
-      case VariantSuicide:    /* should work except for win condition,\r
-                                and doesn't know captures are mandatory */\r
-      case VariantGiveaway:   /* should work except for win condition,\r
-                                and doesn't know captures are mandatory */\r
-      case VariantTwoKings:   /* should work */\r
-      case VariantAtomic:     /* should work except for win condition */\r
-      case Variant3Check:     /* should work except for win condition */\r
-      case VariantShatranj:   /* should work except for all win conditions */\r
-      case VariantBerolina:   /* might work if TestLegality is off */\r
-      case VariantCapaRandom: /* should work */\r
-      case VariantJanus:      /* should work */\r
-      case VariantSuper:      /* experimental */\r
-      case VariantGreat:      /* experimental, requires legality testing to be off */\r
-       break;\r
-      }\r
-    }\r
-\r
-    InitEngineUCI( installDir, &first );  // [HGM] moved here from winboard.c, to make available in xboard\r
-    InitEngineUCI( installDir, &second );\r
-}\r
-\r
-int NextIntegerFromString( char ** str, long * value )\r
-{\r
-    int result = -1;\r
-    char * s = *str;\r
-\r
-    while( *s == ' ' || *s == '\t' ) {\r
-        s++;\r
-    }\r
-\r
-    *value = 0;\r
-\r
-    if( *s >= '0' && *s <= '9' ) {\r
-        while( *s >= '0' && *s <= '9' ) {\r
-            *value = *value * 10 + (*s - '0');\r
-            s++;\r
-        }\r
-\r
-        result = 0;\r
-    }\r
-\r
-    *str = s;\r
-\r
-    return result;\r
-}\r
-\r
-int NextTimeControlFromString( char ** str, long * value )\r
-{\r
-    long temp;\r
-    int result = NextIntegerFromString( str, &temp );\r
-\r
-    if( result == 0 ) {\r
-        *value = temp * 60; /* Minutes */\r
-        if( **str == ':' ) {\r
-            (*str)++;\r
-            result = NextIntegerFromString( str, &temp );\r
-            *value += temp; /* Seconds */\r
-        }\r
-    }\r
-\r
-    return result;\r
-}\r
-\r
-int NextSessionFromString( char ** str, int *moves, long * tc, long *inc)\r
-{   /* [HGM] routine added to read '+moves/time' for secondary time control */\r
-    int result = -1; long temp, temp2;\r
-\r
-    if(**str != '+') return -1; // old params remain in force!\r
-    (*str)++;\r
-    if( NextTimeControlFromString( str, &temp ) ) return -1;\r
-\r
-    if(**str != '/') {\r
-        /* time only: incremental or sudden-death time control */\r
-        if(**str == '+') { /* increment follows; read it */\r
-            (*str)++;\r
-            if(result = NextIntegerFromString( str, &temp2)) return -1;\r
-            *inc = temp2 * 1000;\r
-        } else *inc = 0;\r
-        *moves = 0; *tc = temp * 1000; \r
-        return 0;\r
-    } else if(temp % 60 != 0) return -1;     /* moves was given as min:sec */\r
-\r
-    (*str)++; /* classical time control */\r
-    result = NextTimeControlFromString( str, &temp2);\r
-    if(result == 0) {\r
-        *moves = temp/60;\r
-        *tc    = temp2 * 1000;\r
-        *inc   = 0;\r
-    }\r
-    return result;\r
-}\r
-\r
-int GetTimeQuota(int movenr)\r
-{   /* [HGM] get time to add from the multi-session time-control string */\r
-    int moves=1; /* kludge to force reading of first session */\r
-    long time, increment;\r
-    char *s = fullTimeControlString;\r
-\r
-    if(appData.debugMode) fprintf(debugFP, "TC string = '%s'\n", fullTimeControlString);\r
-    do {\r
-        if(moves) NextSessionFromString(&s, &moves, &time, &increment);\r
-        if(appData.debugMode) fprintf(debugFP, "mps=%d tc=%d inc=%d\n", moves, (int) time, (int) increment);\r
-        if(movenr == -1) return time;    /* last move before new session     */\r
-        if(!moves) return increment;     /* current session is incremental   */\r
-        if(movenr >= 0) movenr -= moves; /* we already finished this session */\r
-    } while(movenr >= -1);               /* try again for next session       */\r
-\r
-    return 0; // no new time quota on this move\r
-}\r
-\r
-int\r
-ParseTimeControl(tc, ti, mps)\r
-     char *tc;\r
-     int ti;\r
-     int mps;\r
-{\r
-#if 0\r
-    int matched, min, sec;\r
-\r
-    matched = sscanf(tc, "%d:%d", &min, &sec);\r
-    if (matched == 1) {\r
-       timeControl = min * 60 * 1000;\r
-    } else if (matched == 2) {\r
-       timeControl = (min * 60 + sec) * 1000;\r
-    } else {\r
-       return FALSE;\r
-    }\r
-#else\r
-    long tc1;\r
-    long tc2;\r
-    char buf[MSG_SIZ];\r
-\r
-    if(ti >= 0 && !strchr(tc, '+') && !strchr(tc, '/') ) mps = 0;\r
-    if(ti > 0) {\r
-        if(mps)\r
-             sprintf(buf, "+%d/%s+%d", mps, tc, ti);\r
-        else sprintf(buf, "+%s+%d", tc, ti);\r
-    } else {\r
-        if(mps)\r
-             sprintf(buf, "+%d/%s", mps, tc);\r
-        else sprintf(buf, "+%s", tc);\r
-    }\r
-    fullTimeControlString = StrSave(buf);\r
-\r
-    if( NextTimeControlFromString( &tc, &tc1 ) != 0 ) {\r
-        return FALSE;\r
-    }\r
-\r
-    if( *tc == '/' ) {\r
-        /* Parse second time control */\r
-        tc++;\r
-\r
-        if( NextTimeControlFromString( &tc, &tc2 ) != 0 ) {\r
-            return FALSE;\r
-        }\r
-\r
-        if( tc2 == 0 ) {\r
-            return FALSE;\r
-        }\r
-\r
-        timeControl_2 = tc2 * 1000;\r
-    }\r
-    else {\r
-        timeControl_2 = 0;\r
-    }\r
-\r
-    if( tc1 == 0 ) {\r
-        return FALSE;\r
-    }\r
-\r
-    timeControl = tc1 * 1000;\r
-#endif\r
-\r
-    if (ti >= 0) {\r
-       timeIncrement = ti * 1000;  /* convert to ms */\r
-       movesPerSession = 0;\r
-    } else {\r
-       timeIncrement = 0;\r
-       movesPerSession = mps;\r
-    }\r
-    return TRUE;\r
-}\r
-\r
-void\r
-InitBackEnd2()\r
-{\r
-    if (appData.debugMode) {\r
-       fprintf(debugFP, "%s\n", programVersion);\r
-    }\r
-\r
-    if (appData.matchGames > 0) {\r
-       appData.matchMode = TRUE;\r
-    } else if (appData.matchMode) {\r
-       appData.matchGames = 1;\r
-    }\r
-    if(appData.matchMode && appData.sameColorGames > 0) /* [HGM] alternate: overrule matchGames */\r
-       appData.matchGames = appData.sameColorGames;\r
-    if(appData.rewindIndex > 1) { /* [HGM] autoinc: rewind implies auto-increment and overrules given index */\r
-       if(appData.loadPositionIndex >= 0) appData.loadPositionIndex = -1;\r
-       if(appData.loadGameIndex >= 0) appData.loadGameIndex = -1;\r
-    }\r
-    Reset(TRUE, FALSE);\r
-    if (appData.noChessProgram || first.protocolVersion == 1) {\r
-      InitBackEnd3();\r
-    } else {\r
-      /* kludge: allow timeout for initial "feature" commands */\r
-      FreezeUI();\r
-      DisplayMessage("", _("Starting chess program"));\r
-      ScheduleDelayedEvent(InitBackEnd3, FEATURE_TIMEOUT);\r
-    }\r
-}\r
-\r
-void\r
-InitBackEnd3 P((void))\r
-{\r
-    GameMode initialMode;\r
-    char buf[MSG_SIZ];\r
-    int err;\r
-\r
-    InitChessProgram(&first, startedFromSetupPosition);\r
-\r
-\r
-    if (appData.icsActive) {\r
-#ifdef WIN32\r
-        /* [DM] Make a console window if needed [HGM] merged ifs */\r
-        ConsoleCreate(); \r
-#endif\r
-       err = establish();\r
-       if (err != 0) {\r
-           if (*appData.icsCommPort != NULLCHAR) {\r
-               sprintf(buf, _("Could not open comm port %s"),  \r
-                       appData.icsCommPort);\r
-           } else {\r
-               sprintf(buf, _("Could not connect to host %s, port %s"),  \r
-                       appData.icsHost, appData.icsPort);\r
-           }\r
-           DisplayFatalError(buf, err, 1);\r
-           return;\r
-       }\r
-       SetICSMode();\r
-       telnetISR =\r
-         AddInputSource(icsPR, FALSE, read_from_ics, &telnetISR);\r
-       fromUserISR =\r
-         AddInputSource(NoProc, FALSE, read_from_player, &fromUserISR);\r
-    } else if (appData.noChessProgram) {\r
-       SetNCPMode();\r
-    } else {\r
-       SetGNUMode();\r
-    }\r
-\r
-    if (*appData.cmailGameName != NULLCHAR) {\r
-       SetCmailMode();\r
-       OpenLoopback(&cmailPR);\r
-       cmailISR =\r
-         AddInputSource(cmailPR, FALSE, CmailSigHandlerCallBack, &cmailISR);\r
-    }\r
-    \r
-    ThawUI();\r
-    DisplayMessage("", "");\r
-    if (StrCaseCmp(appData.initialMode, "") == 0) {\r
-      initialMode = BeginningOfGame;\r
-    } else if (StrCaseCmp(appData.initialMode, "TwoMachines") == 0) {\r
-      initialMode = TwoMachinesPlay;\r
-    } else if (StrCaseCmp(appData.initialMode, "AnalyzeFile") == 0) {\r
-      initialMode = AnalyzeFile; \r
-    } else if (StrCaseCmp(appData.initialMode, "Analysis") == 0) {\r
-      initialMode = AnalyzeMode;\r
-    } else if (StrCaseCmp(appData.initialMode, "MachineWhite") == 0) {\r
-      initialMode = MachinePlaysWhite;\r
-    } else if (StrCaseCmp(appData.initialMode, "MachineBlack") == 0) {\r
-      initialMode = MachinePlaysBlack;\r
-    } else if (StrCaseCmp(appData.initialMode, "EditGame") == 0) {\r
-      initialMode = EditGame;\r
-    } else if (StrCaseCmp(appData.initialMode, "EditPosition") == 0) {\r
-      initialMode = EditPosition;\r
-    } else if (StrCaseCmp(appData.initialMode, "Training") == 0) {\r
-      initialMode = Training;\r
-    } else {\r
-      sprintf(buf, _("Unknown initialMode %s"), appData.initialMode);\r
-      DisplayFatalError(buf, 0, 2);\r
-      return;\r
-    }\r
-\r
-    if (appData.matchMode) {\r
-       /* Set up machine vs. machine match */\r
-       if (appData.noChessProgram) {\r
-           DisplayFatalError(_("Can't have a match with no chess programs"),\r
-                             0, 2);\r
-           return;\r
-       }\r
-       matchMode = TRUE;\r
-       matchGame = 1;\r
-       if (*appData.loadGameFile != NULLCHAR) {\r
-           int index = appData.loadGameIndex; // [HGM] autoinc\r
-           if(index<0) lastIndex = index = 1;\r
-           if (!LoadGameFromFile(appData.loadGameFile,\r
-                                 index,\r
-                                 appData.loadGameFile, FALSE)) {\r
-               DisplayFatalError(_("Bad game file"), 0, 1);\r
-               return;\r
-           }\r
-       } else if (*appData.loadPositionFile != NULLCHAR) {\r
-           int index = appData.loadPositionIndex; // [HGM] autoinc\r
-           if(index<0) lastIndex = index = 1;\r
-           if (!LoadPositionFromFile(appData.loadPositionFile,\r
-                                     index,\r
-                                     appData.loadPositionFile)) {\r
-               DisplayFatalError(_("Bad position file"), 0, 1);\r
-               return;\r
-           }\r
-       }\r
-       TwoMachinesEvent();\r
-    } else if (*appData.cmailGameName != NULLCHAR) {\r
-       /* Set up cmail mode */\r
-       ReloadCmailMsgEvent(TRUE);\r
-    } else {\r
-       /* Set up other modes */\r
-       if (initialMode == AnalyzeFile) {\r
-         if (*appData.loadGameFile == NULLCHAR) {\r
-           DisplayFatalError(_("AnalyzeFile mode requires a game file"), 0, 1);\r
-           return;\r
-         }\r
-       }\r
-       if (*appData.loadGameFile != NULLCHAR) {\r
-           (void) LoadGameFromFile(appData.loadGameFile,\r
-                                   appData.loadGameIndex,\r
-                                   appData.loadGameFile, TRUE);\r
-       } else if (*appData.loadPositionFile != NULLCHAR) {\r
-           (void) LoadPositionFromFile(appData.loadPositionFile,\r
-                                       appData.loadPositionIndex,\r
-                                       appData.loadPositionFile);\r
-            /* [HGM] try to make self-starting even after FEN load */\r
-            /* to allow automatic setup of fairy variants with wtm */\r
-            if(initialMode == BeginningOfGame && !blackPlaysFirst) {\r
-                gameMode = BeginningOfGame;\r
-                setboardSpoiledMachineBlack = 1;\r
-            }\r
-            /* [HGM] loadPos: make that every new game uses the setup */\r
-            /* from file as long as we do not switch variant          */\r
-            if(!blackPlaysFirst) { int i;\r
-                startedFromPositionFile = TRUE;\r
-                CopyBoard(filePosition, boards[0]);\r
-                for(i=0; i<BOARD_SIZE; i++) fileRights[i] = castlingRights[0][i];\r
-            }\r
-       }\r
-       if (initialMode == AnalyzeMode) {\r
-         if (appData.noChessProgram) {\r
-           DisplayFatalError(_("Analysis mode requires a chess engine"), 0, 2);\r
-           return;\r
-         }\r
-         if (appData.icsActive) {\r
-           DisplayFatalError(_("Analysis mode does not work with ICS mode"),0,2);\r
-           return;\r
-         }\r
-         AnalyzeModeEvent();\r
-       } else if (initialMode == AnalyzeFile) {\r
-         appData.showThinking = TRUE; // [HGM] thinking: moved out of ShowThinkingEvent\r
-         ShowThinkingEvent();\r
-         AnalyzeFileEvent();\r
-         AnalysisPeriodicEvent(1);\r
-       } else if (initialMode == MachinePlaysWhite) {\r
-         if (appData.noChessProgram) {\r
-           DisplayFatalError(_("MachineWhite mode requires a chess engine"),\r
-                             0, 2);\r
-           return;\r
-         }\r
-         if (appData.icsActive) {\r
-           DisplayFatalError(_("MachineWhite mode does not work with ICS mode"),\r
-                             0, 2);\r
-           return;\r
-         }\r
-         MachineWhiteEvent();\r
-       } else if (initialMode == MachinePlaysBlack) {\r
-         if (appData.noChessProgram) {\r
-           DisplayFatalError(_("MachineBlack mode requires a chess engine"),\r
-                             0, 2);\r
-           return;\r
-         }\r
-         if (appData.icsActive) {\r
-           DisplayFatalError(_("MachineBlack mode does not work with ICS mode"),\r
-                             0, 2);\r
-           return;\r
-         }\r
-         MachineBlackEvent();\r
-       } else if (initialMode == TwoMachinesPlay) {\r
-         if (appData.noChessProgram) {\r
-           DisplayFatalError(_("TwoMachines mode requires a chess engine"),\r
-                             0, 2);\r
-           return;\r
-         }\r
-         if (appData.icsActive) {\r
-           DisplayFatalError(_("TwoMachines mode does not work with ICS mode"),\r
-                             0, 2);\r
-           return;\r
-         }\r
-         TwoMachinesEvent();\r
-       } else if (initialMode == EditGame) {\r
-         EditGameEvent();\r
-       } else if (initialMode == EditPosition) {\r
-         EditPositionEvent();\r
-       } else if (initialMode == Training) {\r
-         if (*appData.loadGameFile == NULLCHAR) {\r
-           DisplayFatalError(_("Training mode requires a game file"), 0, 2);\r
-           return;\r
-         }\r
-         TrainingEvent();\r
-       }\r
-    }\r
-}\r
-\r
-/*\r
- * Establish will establish a contact to a remote host.port.\r
- * Sets icsPR to a ProcRef for a process (or pseudo-process)\r
- *  used to talk to the host.\r
- * Returns 0 if okay, error code if not.\r
- */\r
-int\r
-establish()\r
-{\r
-    char buf[MSG_SIZ];\r
-\r
-    if (*appData.icsCommPort != NULLCHAR) {\r
-       /* Talk to the host through a serial comm port */\r
-       return OpenCommPort(appData.icsCommPort, &icsPR);\r
-\r
-    } else if (*appData.gateway != NULLCHAR) {\r
-       if (*appData.remoteShell == NULLCHAR) {\r
-           /* Use the rcmd protocol to run telnet program on a gateway host */\r
-           sprintf(buf, "%s %s %s",\r
-                   appData.telnetProgram, appData.icsHost, appData.icsPort);\r
-           return OpenRcmd(appData.gateway, appData.remoteUser, buf, &icsPR);\r
-\r
-       } else {\r
-           /* Use the rsh program to run telnet program on a gateway host */\r
-           if (*appData.remoteUser == NULLCHAR) {\r
-               sprintf(buf, "%s %s %s %s %s", appData.remoteShell,\r
-                       appData.gateway, appData.telnetProgram,\r
-                       appData.icsHost, appData.icsPort);\r
-           } else {\r
-               sprintf(buf, "%s %s -l %s %s %s %s",\r
-                       appData.remoteShell, appData.gateway, \r
-                       appData.remoteUser, appData.telnetProgram,\r
-                       appData.icsHost, appData.icsPort);\r
-           }\r
-           return StartChildProcess(buf, "", &icsPR);\r
-\r
-       }\r
-    } else if (appData.useTelnet) {\r
-       return OpenTelnet(appData.icsHost, appData.icsPort, &icsPR);\r
-\r
-    } else {\r
-       /* TCP socket interface differs somewhat between\r
-          Unix and NT; handle details in the front end.\r
-          */\r
-       return OpenTCP(appData.icsHost, appData.icsPort, &icsPR);\r
-    }\r
-}\r
-\r
-void\r
-show_bytes(fp, buf, count)\r
-     FILE *fp;\r
-     char *buf;\r
-     int count;\r
-{\r
-    while (count--) {\r
-       if (*buf < 040 || *(unsigned char *) buf > 0177) {\r
-           fprintf(fp, "\\%03o", *buf & 0xff);\r
-       } else {\r
-           putc(*buf, fp);\r
-       }\r
-       buf++;\r
-    }\r
-    fflush(fp);\r
-}\r
-\r
-/* Returns an errno value */\r
-int\r
-OutputMaybeTelnet(pr, message, count, outError)\r
-     ProcRef pr;\r
-     char *message;\r
-     int count;\r
-     int *outError;\r
-{\r
-    char buf[8192], *p, *q, *buflim;\r
-    int left, newcount, outcount;\r
-\r
-    if (*appData.icsCommPort != NULLCHAR || appData.useTelnet ||\r
-       *appData.gateway != NULLCHAR) {\r
-       if (appData.debugMode) {\r
-           fprintf(debugFP, ">ICS: ");\r
-           show_bytes(debugFP, message, count);\r
-           fprintf(debugFP, "\n");\r
-       }\r
-       return OutputToProcess(pr, message, count, outError);\r
-    }\r
-\r
-    buflim = &buf[sizeof(buf)-1]; /* allow 1 byte for expanding last char */\r
-    p = message;\r
-    q = buf;\r
-    left = count;\r
-    newcount = 0;\r
-    while (left) {\r
-       if (q >= buflim) {\r
-           if (appData.debugMode) {\r
-               fprintf(debugFP, ">ICS: ");\r
-               show_bytes(debugFP, buf, newcount);\r
-               fprintf(debugFP, "\n");\r
-           }\r
-           outcount = OutputToProcess(pr, buf, newcount, outError);\r
-           if (outcount < newcount) return -1; /* to be sure */\r
-           q = buf;\r
-           newcount = 0;\r
-       }\r
-       if (*p == '\n') {\r
-           *q++ = '\r';\r
-           newcount++;\r
-       } else if (((unsigned char) *p) == TN_IAC) {\r
-           *q++ = (char) TN_IAC;\r
-           newcount ++;\r
-       }\r
-       *q++ = *p++;\r
-       newcount++;\r
-       left--;\r
-    }\r
-    if (appData.debugMode) {\r
-       fprintf(debugFP, ">ICS: ");\r
-       show_bytes(debugFP, buf, newcount);\r
-       fprintf(debugFP, "\n");\r
-    }\r
-    outcount = OutputToProcess(pr, buf, newcount, outError);\r
-    if (outcount < newcount) return -1; /* to be sure */\r
-    return count;\r
-}\r
-\r
-void\r
-read_from_player(isr, closure, message, count, error)\r
-     InputSourceRef isr;\r
-     VOIDSTAR closure;\r
-     char *message;\r
-     int count;\r
-     int error;\r
-{\r
-    int outError, outCount;\r
-    static int gotEof = 0;\r
-\r
-    /* Pass data read from player on to ICS */\r
-    if (count > 0) {\r
-       gotEof = 0;\r
-       outCount = OutputMaybeTelnet(icsPR, message, count, &outError);\r
-       if (outCount < count) {\r
-            DisplayFatalError(_("Error writing to ICS"), outError, 1);\r
-       }\r
-    } else if (count < 0) {\r
-       RemoveInputSource(isr);\r
-       DisplayFatalError(_("Error reading from keyboard"), error, 1);\r
-    } else if (gotEof++ > 0) {\r
-       RemoveInputSource(isr);\r
-       DisplayFatalError(_("Got end of file from keyboard"), 0, 0);\r
-    }\r
-}\r
-\r
-void\r
-SendToICS(s)\r
-     char *s;\r
-{\r
-    int count, outCount, outError;\r
-\r
-    if (icsPR == NULL) return;\r
-\r
-    count = strlen(s);\r
-    outCount = OutputMaybeTelnet(icsPR, s, count, &outError);\r
-    if (outCount < count) {\r
-       DisplayFatalError(_("Error writing to ICS"), outError, 1);\r
-    }\r
-}\r
-\r
-/* This is used for sending logon scripts to the ICS. Sending\r
-   without a delay causes problems when using timestamp on ICC\r
-   (at least on my machine). */\r
-void\r
-SendToICSDelayed(s,msdelay)\r
-     char *s;\r
-     long msdelay;\r
-{\r
-    int count, outCount, outError;\r
-\r
-    if (icsPR == NULL) return;\r
-\r
-    count = strlen(s);\r
-    if (appData.debugMode) {\r
-       fprintf(debugFP, ">ICS: ");\r
-       show_bytes(debugFP, s, count);\r
-       fprintf(debugFP, "\n");\r
-    }\r
-    outCount = OutputToProcessDelayed(icsPR, s, count, &outError,\r
-                                     msdelay);\r
-    if (outCount < count) {\r
-       DisplayFatalError(_("Error writing to ICS"), outError, 1);\r
-    }\r
-}\r
-\r
-\r
-/* Remove all highlighting escape sequences in s\r
-   Also deletes any suffix starting with '(' \r
-   */\r
-char *\r
-StripHighlightAndTitle(s)\r
-     char *s;\r
-{\r
-    static char retbuf[MSG_SIZ];\r
-    char *p = retbuf;\r
-\r
-    while (*s != NULLCHAR) {\r
-       while (*s == '\033') {\r
-           while (*s != NULLCHAR && !isalpha(*s)) s++;\r
-           if (*s != NULLCHAR) s++;\r
-       }\r
-       while (*s != NULLCHAR && *s != '\033') {\r
-           if (*s == '(' || *s == '[') {\r
-               *p = NULLCHAR;\r
-               return retbuf;\r
-           }\r
-           *p++ = *s++;\r
-       }\r
-    }\r
-    *p = NULLCHAR;\r
-    return retbuf;\r
-}\r
-\r
-/* Remove all highlighting escape sequences in s */\r
-char *\r
-StripHighlight(s)\r
-     char *s;\r
-{\r
-    static char retbuf[MSG_SIZ];\r
-    char *p = retbuf;\r
-\r
-    while (*s != NULLCHAR) {\r
-       while (*s == '\033') {\r
-           while (*s != NULLCHAR && !isalpha(*s)) s++;\r
-           if (*s != NULLCHAR) s++;\r
-       }\r
-       while (*s != NULLCHAR && *s != '\033') {\r
-           *p++ = *s++;\r
-       }\r
-    }\r
-    *p = NULLCHAR;\r
-    return retbuf;\r
-}\r
-\r
-char *variantNames[] = VARIANT_NAMES;\r
-char *\r
-VariantName(v)\r
-     VariantClass v;\r
-{\r
-    return variantNames[v];\r
-}\r
-\r
-\r
-/* Identify a variant from the strings the chess servers use or the\r
-   PGN Variant tag names we use. */\r
-VariantClass\r
-StringToVariant(e)\r
-     char *e;\r
-{\r
-    char *p;\r
-    int wnum = -1;\r
-    VariantClass v = VariantNormal;\r
-    int i, found = FALSE;\r
-    char buf[MSG_SIZ];\r
-\r
-    if (!e) return v;\r
-\r
-    /* [HGM] skip over optional board-size prefixes */\r
-    if( sscanf(e, "%dx%d_", &i, &i) == 2 ||\r
-        sscanf(e, "%dx%d+%d_", &i, &i, &i) == 3 ) {\r
-        while( *e++ != '_');\r
-    }\r
-\r
-    for (i=0; i<sizeof(variantNames)/sizeof(char*); i++) {\r
-      if (StrCaseStr(e, variantNames[i])) {\r
-       v = (VariantClass) i;\r
-       found = TRUE;\r
-       break;\r
-      }\r
-    }\r
-\r
-    if (!found) {\r
-      if ((StrCaseStr(e, "fischer") && StrCaseStr(e, "random"))\r
-         || StrCaseStr(e, "wild/fr") \r
-         || StrCaseStr(e, "frc") || StrCaseStr(e, "960")) {\r
-        v = VariantFischeRandom;\r
-      } else if ((i = 4, p = StrCaseStr(e, "wild")) ||\r
-                (i = 1, p = StrCaseStr(e, "w"))) {\r
-       p += i;\r
-       while (*p && (isspace(*p) || *p == '(' || *p == '/')) p++;\r
-       if (isdigit(*p)) {\r
-         wnum = atoi(p);\r
-       } else {\r
-         wnum = -1;\r
-       }\r
-       switch (wnum) {\r
-       case 0: /* FICS only, actually */\r
-       case 1:\r
-         /* Castling legal even if K starts on d-file */\r
-         v = VariantWildCastle;\r
-         break;\r
-       case 2:\r
-       case 3:\r
-       case 4:\r
-         /* Castling illegal even if K & R happen to start in\r
-            normal positions. */\r
-         v = VariantNoCastle;\r
-         break;\r
-       case 5:\r
-       case 7:\r
-       case 8:\r
-       case 10:\r
-       case 11:\r
-       case 12:\r
-       case 13:\r
-       case 14:\r
-       case 15:\r
-       case 18:\r
-       case 19:\r
-         /* Castling legal iff K & R start in normal positions */\r
-         v = VariantNormal;\r
-         break;\r
-       case 6:\r
-       case 20:\r
-       case 21:\r
-         /* Special wilds for position setup; unclear what to do here */\r
-         v = VariantLoadable;\r
-         break;\r
-       case 9:\r
-         /* Bizarre ICC game */\r
-         v = VariantTwoKings;\r
-         break;\r
-       case 16:\r
-         v = VariantKriegspiel;\r
-         break;\r
-       case 17:\r
-         v = VariantLosers;\r
-         break;\r
-       case 22:\r
-         v = VariantFischeRandom;\r
-         break;\r
-       case 23:\r
-         v = VariantCrazyhouse;\r
-         break;\r
-       case 24:\r
-         v = VariantBughouse;\r
-         break;\r
-       case 25:\r
-         v = Variant3Check;\r
-         break;\r
-       case 26:\r
-         /* Not quite the same as FICS suicide! */\r
-         v = VariantGiveaway;\r
-         break;\r
-       case 27:\r
-         v = VariantAtomic;\r
-         break;\r
-       case 28:\r
-         v = VariantShatranj;\r
-         break;\r
-\r
-       /* Temporary names for future ICC types.  The name *will* change in \r
-          the next xboard/WinBoard release after ICC defines it. */\r
-       case 29:\r
-         v = Variant29;\r
-         break;\r
-       case 30:\r
-         v = Variant30;\r
-         break;\r
-       case 31:\r
-         v = Variant31;\r
-         break;\r
-       case 32:\r
-         v = Variant32;\r
-         break;\r
-       case 33:\r
-         v = Variant33;\r
-         break;\r
-       case 34:\r
-         v = Variant34;\r
-         break;\r
-       case 35:\r
-         v = Variant35;\r
-         break;\r
-       case 36:\r
-         v = Variant36;\r
-         break;\r
-        case 37:\r
-          v = VariantShogi;\r
-         break;\r
-        case 38:\r
-          v = VariantXiangqi;\r
-         break;\r
-        case 39:\r
-          v = VariantCourier;\r
-         break;\r
-        case 40:\r
-          v = VariantGothic;\r
-         break;\r
-        case 41:\r
-          v = VariantCapablanca;\r
-         break;\r
-        case 42:\r
-          v = VariantKnightmate;\r
-         break;\r
-        case 43:\r
-          v = VariantFairy;\r
-          break;\r
-        case 44:\r
-          v = VariantCylinder;\r
-         break;\r
-        case 45:\r
-          v = VariantFalcon;\r
-         break;\r
-        case 46:\r
-          v = VariantCapaRandom;\r
-         break;\r
-        case 47:\r
-          v = VariantBerolina;\r
-         break;\r
-        case 48:\r
-          v = VariantJanus;\r
-         break;\r
-        case 49:\r
-          v = VariantSuper;\r
-         break;\r
-        case 50:\r
-          v = VariantGreat;\r
-         break;\r
-       case -1:\r
-         /* Found "wild" or "w" in the string but no number;\r
-            must assume it's normal chess. */\r
-         v = VariantNormal;\r
-         break;\r
-       default:\r
-         sprintf(buf, _("Unknown wild type %d"), wnum);\r
-         DisplayError(buf, 0);\r
-         v = VariantUnknown;\r
-         break;\r
-       }\r
-      }\r
-    }\r
-    if (appData.debugMode) {\r
-      fprintf(debugFP, _("recognized '%s' (%d) as variant %s\n"),\r
-             e, wnum, VariantName(v));\r
-    }\r
-    return v;\r
-}\r
-\r
-static int leftover_start = 0, leftover_len = 0;\r
-char star_match[STAR_MATCH_N][MSG_SIZ];\r
-\r
-/* Test whether pattern is present at &buf[*index]; if so, return TRUE,\r
-   advance *index beyond it, and set leftover_start to the new value of\r
-   *index; else return FALSE.  If pattern contains the character '*', it\r
-   matches any sequence of characters not containing '\r', '\n', or the\r
-   character following the '*' (if any), and the matched sequence(s) are\r
-   copied into star_match.\r
-   */\r
-int\r
-looking_at(buf, index, pattern)\r
-     char *buf;\r
-     int *index;\r
-     char *pattern;\r
-{\r
-    char *bufp = &buf[*index], *patternp = pattern;\r
-    int star_count = 0;\r
-    char *matchp = star_match[0];\r
-    \r
-    for (;;) {\r
-       if (*patternp == NULLCHAR) {\r
-           *index = leftover_start = bufp - buf;\r
-           *matchp = NULLCHAR;\r
-           return TRUE;\r
-       }\r
-       if (*bufp == NULLCHAR) return FALSE;\r
-       if (*patternp == '*') {\r
-           if (*bufp == *(patternp + 1)) {\r
-               *matchp = NULLCHAR;\r
-               matchp = star_match[++star_count];\r
-               patternp += 2;\r
-               bufp++;\r
-               continue;\r
-           } else if (*bufp == '\n' || *bufp == '\r') {\r
-               patternp++;\r
-               if (*patternp == NULLCHAR)\r
-                 continue;\r
-               else\r
-                 return FALSE;\r
-           } else {\r
-               *matchp++ = *bufp++;\r
-               continue;\r
-           }\r
-       }\r
-       if (*patternp != *bufp) return FALSE;\r
-       patternp++;\r
-       bufp++;\r
-    }\r
-}\r
-\r
-void\r
-SendToPlayer(data, length)\r
-     char *data;\r
-     int length;\r
-{\r
-    int error, outCount;\r
-    outCount = OutputToProcess(NoProc, data, length, &error);\r
-    if (outCount < length) {\r
-       DisplayFatalError(_("Error writing to display"), error, 1);\r
-    }\r
-}\r
-\r
-void\r
-PackHolding(packed, holding)\r
-     char packed[];\r
-     char *holding;\r
-{\r
-    char *p = holding;\r
-    char *q = packed;\r
-    int runlength = 0;\r
-    int curr = 9999;\r
-    do {\r
-       if (*p == curr) {\r
-           runlength++;\r
-       } else {\r
-           switch (runlength) {\r
-             case 0:\r
-               break;\r
-             case 1:\r
-               *q++ = curr;\r
-               break;\r
-             case 2:\r
-               *q++ = curr;\r
-               *q++ = curr;\r
-               break;\r
-             default:\r
-               sprintf(q, "%d", runlength);\r
-               while (*q) q++;\r
-               *q++ = curr;\r
-               break;\r
-           }\r
-           runlength = 1;\r
-           curr = *p;\r
-       }\r
-    } while (*p++);\r
-    *q = NULLCHAR;\r
-}\r
-\r
-/* Telnet protocol requests from the front end */\r
-void\r
-TelnetRequest(ddww, option)\r
-     unsigned char ddww, option;\r
-{\r
-    unsigned char msg[3];\r
-    int outCount, outError;\r
-\r
-    if (*appData.icsCommPort != NULLCHAR || appData.useTelnet) return;\r
-\r
-    if (appData.debugMode) {\r
-       char buf1[8], buf2[8], *ddwwStr, *optionStr;\r
-       switch (ddww) {\r
-         case TN_DO:\r
-           ddwwStr = "DO";\r
-           break;\r
-         case TN_DONT:\r
-           ddwwStr = "DONT";\r
-           break;\r
-         case TN_WILL:\r
-           ddwwStr = "WILL";\r
-           break;\r
-         case TN_WONT:\r
-           ddwwStr = "WONT";\r
-           break;\r
-         default:\r
-           ddwwStr = buf1;\r
-           sprintf(buf1, "%d", ddww);\r
-           break;\r
-       }\r
-       switch (option) {\r
-         case TN_ECHO:\r
-           optionStr = "ECHO";\r
-           break;\r
-         default:\r
-           optionStr = buf2;\r
-           sprintf(buf2, "%d", option);\r
-           break;\r
-       }\r
-       fprintf(debugFP, ">%s %s ", ddwwStr, optionStr);\r
-    }\r
-    msg[0] = TN_IAC;\r
-    msg[1] = ddww;\r
-    msg[2] = option;\r
-    outCount = OutputToProcess(icsPR, (char *)msg, 3, &outError);\r
-    if (outCount < 3) {\r
-       DisplayFatalError(_("Error writing to ICS"), outError, 1);\r
-    }\r
-}\r
-\r
-void\r
-DoEcho()\r
-{\r
-    if (!appData.icsActive) return;\r
-    TelnetRequest(TN_DO, TN_ECHO);\r
-}\r
-\r
-void\r
-DontEcho()\r
-{\r
-    if (!appData.icsActive) return;\r
-    TelnetRequest(TN_DONT, TN_ECHO);\r
-}\r
-\r
-void\r
-CopyHoldings(Board board, char *holdings, ChessSquare lowestPiece)\r
-{\r
-    /* put the holdings sent to us by the server on the board holdings area */\r
-    int i, j, holdingsColumn, holdingsStartRow, direction, countsColumn;\r
-    char p;\r
-    ChessSquare piece;\r
-\r
-    if(gameInfo.holdingsWidth < 2)  return;\r
-\r
-    if( (int)lowestPiece >= BlackPawn ) {\r
-        holdingsColumn = 0;\r
-        countsColumn = 1;\r
-        holdingsStartRow = BOARD_HEIGHT-1;\r
-        direction = -1;\r
-    } else {\r
-        holdingsColumn = BOARD_WIDTH-1;\r
-        countsColumn = BOARD_WIDTH-2;\r
-        holdingsStartRow = 0;\r
-        direction = 1;\r
-    }\r
-\r
-    for(i=0; i<BOARD_HEIGHT; i++) { /* clear holdings */\r
-        board[i][holdingsColumn] = EmptySquare;\r
-        board[i][countsColumn]   = (ChessSquare) 0;\r
-    }\r
-    while( (p=*holdings++) != NULLCHAR ) {\r
-        piece = CharToPiece( ToUpper(p) );\r
-        if(piece == EmptySquare) continue;\r
-        /*j = (int) piece - (int) WhitePawn;*/\r
-        j = PieceToNumber(piece);\r
-        if(j >= gameInfo.holdingsSize) continue; /* ignore pieces that do not fit */\r
-        if(j < 0) continue;               /* should not happen */\r
-        piece = (ChessSquare) ( (int)piece + (int)lowestPiece );\r
-        board[holdingsStartRow+j*direction][holdingsColumn] = piece;\r
-        board[holdingsStartRow+j*direction][countsColumn]++;\r
-    }\r
-\r
-}\r
-\r
-\r
-void\r
-VariantSwitch(Board board, VariantClass newVariant)\r
-{\r
-   int newHoldingsWidth, newWidth = 8, newHeight = 8, i, j;\r
-   int oldCurrentMove = currentMove, oldForwardMostMove = forwardMostMove, oldBackwardMostMove = backwardMostMove;\r
-   Board tempBoard; int saveCastling[BOARD_SIZE], saveEP;\r
-\r
-   startedFromPositionFile = FALSE;\r
-   if(gameInfo.variant == newVariant) return;\r
-\r
-   /* [HGM] This routine is called each time an assignment is made to\r
-    * gameInfo.variant during a game, to make sure the board sizes\r
-    * are set to match the new variant. If that means adding or deleting\r
-    * holdings, we shift the playing board accordingly\r
-    * This kludge is needed because in ICS observe mode, we get boards\r
-    * of an ongoing game without knowing the variant, and learn about the\r
-    * latter only later. This can be because of the move list we requested,\r
-    * in which case the game history is refilled from the beginning anyway,\r
-    * but also when receiving holdings of a crazyhouse game. In the latter\r
-    * case we want to add those holdings to the already received position.\r
-    */\r
-\r
-\r
-  if (appData.debugMode) {\r
-    fprintf(debugFP, "Switch board from %s to %s\n",\r
-               VariantName(gameInfo.variant), VariantName(newVariant));\r
-    setbuf(debugFP, NULL);\r
-  }\r
-    shuffleOpenings = 0;       /* [HGM] shuffle */\r
-    gameInfo.holdingsSize = 5; /* [HGM] prepare holdings */\r
-    switch(newVariant) {\r
-            case VariantShogi:\r
-              newWidth = 9;  newHeight = 9;\r
-              gameInfo.holdingsSize = 7;\r
-            case VariantBughouse:\r
-            case VariantCrazyhouse:\r
-              newHoldingsWidth = 2; break;\r
-            default:\r
-              newHoldingsWidth = gameInfo.holdingsSize = 0;\r
-    }\r
-\r
-    if(newWidth  != gameInfo.boardWidth  ||\r
-       newHeight != gameInfo.boardHeight ||\r
-       newHoldingsWidth != gameInfo.holdingsWidth ) {\r
-\r
-        /* shift position to new playing area, if needed */\r
-        if(newHoldingsWidth > gameInfo.holdingsWidth) {\r
-           for(i=0; i<BOARD_HEIGHT; i++) \r
-               for(j=BOARD_RGHT-1; j>=BOARD_LEFT; j--)\r
-                   board[i][j+newHoldingsWidth-gameInfo.holdingsWidth] =\r
-                                                     board[i][j];\r
-           for(i=0; i<newHeight; i++) {\r
-               board[i][0] = board[i][newWidth+2*newHoldingsWidth-1] = EmptySquare;\r
-               board[i][1] = board[i][newWidth+2*newHoldingsWidth-2] = (ChessSquare) 0;\r
-           }\r
-        } else if(newHoldingsWidth < gameInfo.holdingsWidth) {\r
-           for(i=0; i<BOARD_HEIGHT; i++)\r
-               for(j=BOARD_LEFT; j<BOARD_RGHT; j++)\r
-                   board[i][j+newHoldingsWidth-gameInfo.holdingsWidth] =\r
-                                                 board[i][j];\r
-        }\r
-\r
-        gameInfo.boardWidth  = newWidth;\r
-        gameInfo.boardHeight = newHeight;\r
-        gameInfo.holdingsWidth = newHoldingsWidth;\r
-        gameInfo.variant = newVariant;\r
-        InitDrawingSizes(-2, 0);\r
-\r
-        /* [HGM] The following should definitely be solved in a better way */\r
-#if 0\r
-        CopyBoard(board, tempBoard); /* save position in case it is board[0] */\r
-        for(i=0; i<BOARD_SIZE; i++) saveCastling[i] = castlingRights[0][i];\r
-        saveEP = epStatus[0];\r
-#endif\r
-        InitPosition(FALSE);          /* this sets up board[0], but also other stuff        */\r
-#if 0\r
-        epStatus[0] = saveEP;\r
-        for(i=0; i<BOARD_SIZE; i++) castlingRights[0][i] = saveCastling[i];\r
-        CopyBoard(tempBoard, board); /* restore position received from ICS   */\r
-#endif\r
-    } else { gameInfo.variant = newVariant; InitPosition(FALSE); }\r
-\r
-    forwardMostMove = oldForwardMostMove;\r
-    backwardMostMove = oldBackwardMostMove;\r
-    currentMove = oldCurrentMove; /* InitPos reset these, but we need still to redraw the position */\r
-}\r
-\r
-static int loggedOn = FALSE;\r
-\r
-/*-- Game start info cache: --*/\r
-int gs_gamenum;\r
-char gs_kind[MSG_SIZ];\r
-static char player1Name[128] = "";\r
-static char player2Name[128] = "";\r
-static int player1Rating = -1;\r
-static int player2Rating = -1;\r
-/*----------------------------*/\r
-\r
-ColorClass curColor = ColorNormal;\r
-int suppressKibitz = 0;\r
-\r
-void\r
-read_from_ics(isr, closure, data, count, error)\r
-     InputSourceRef isr;\r
-     VOIDSTAR closure;\r
-     char *data;\r
-     int count;\r
-     int error;\r
-{\r
-#define BUF_SIZE 8192\r
-#define STARTED_NONE 0\r
-#define STARTED_MOVES 1\r
-#define STARTED_BOARD 2\r
-#define STARTED_OBSERVE 3\r
-#define STARTED_HOLDINGS 4\r
-#define STARTED_CHATTER 5\r
-#define STARTED_COMMENT 6\r
-#define STARTED_MOVES_NOHIDE 7\r
-    \r
-    static int started = STARTED_NONE;\r
-    static char parse[20000];\r
-    static int parse_pos = 0;\r
-    static char buf[BUF_SIZE + 1];\r
-    static int firstTime = TRUE, intfSet = FALSE;\r
-    static ColorClass prevColor = ColorNormal;\r
-    static int savingComment = FALSE;\r
-    char str[500];\r
-    int i, oldi;\r
-    int buf_len;\r
-    int next_out;\r
-    int tkind;\r
-    int backup;    /* [DM] For zippy color lines */\r
-    char *p;\r
-\r
-    if (appData.debugMode) {\r
-      if (!error) {\r
-       fprintf(debugFP, "<ICS: ");\r
-       show_bytes(debugFP, data, count);\r
-       fprintf(debugFP, "\n");\r
-      }\r
-    }\r
-\r
-    if (appData.debugMode) { int f = forwardMostMove;\r
-        fprintf(debugFP, "ics input %d, castling = %d %d %d %d %d %d\n", f,\r
-                castlingRights[f][0],castlingRights[f][1],castlingRights[f][2],castlingRights[f][3],castlingRights[f][4],castlingRights[f][5]);\r
-    }\r
-    if (count > 0) {\r
-       /* If last read ended with a partial line that we couldn't parse,\r
-          prepend it to the new read and try again. */\r
-       if (leftover_len > 0) {\r
-           for (i=0; i<leftover_len; i++)\r
-             buf[i] = buf[leftover_start + i];\r
-       }\r
-\r
-       /* Copy in new characters, removing nulls and \r's */\r
-       buf_len = leftover_len;\r
-       for (i = 0; i < count; i++) {\r
-           if (data[i] != NULLCHAR && data[i] != '\r')\r
-             buf[buf_len++] = data[i];\r
-           if(buf_len >= 5 && buf[buf_len-5]=='\n' && buf[buf_len-4]=='\\' && \r
-                               buf[buf_len-3]==' '  && buf[buf_len-2]==' '  && buf[buf_len-1]==' ') \r
-               buf_len -= 5; // [HGM] ICS: join continuation line of Lasker 2.2.3 server with previous\r
-       }\r
-\r
-       buf[buf_len] = NULLCHAR;\r
-       next_out = leftover_len;\r
-       leftover_start = 0;\r
-       \r
-       i = 0;\r
-       while (i < buf_len) {\r
-           /* Deal with part of the TELNET option negotiation\r
-              protocol.  We refuse to do anything beyond the\r
-              defaults, except that we allow the WILL ECHO option,\r
-              which ICS uses to turn off password echoing when we are\r
-              directly connected to it.  We reject this option\r
-              if localLineEditing mode is on (always on in xboard)\r
-               and we are talking to port 23, which might be a real\r
-              telnet server that will try to keep WILL ECHO on permanently.\r
-             */\r
-           if (buf_len - i >= 3 && (unsigned char) buf[i] == TN_IAC) {\r
-               static int remoteEchoOption = FALSE; /* telnet ECHO option */\r
-               unsigned char option;\r
-               oldi = i;\r
-               switch ((unsigned char) buf[++i]) {\r
-                 case TN_WILL:\r
-                   if (appData.debugMode)\r
-                     fprintf(debugFP, "\n<WILL ");\r
-                   switch (option = (unsigned char) buf[++i]) {\r
-                     case TN_ECHO:\r
-                       if (appData.debugMode)\r
-                         fprintf(debugFP, "ECHO ");\r
-                       /* Reply only if this is a change, according\r
-                          to the protocol rules. */\r
-                       if (remoteEchoOption) break;\r
-                       if (appData.localLineEditing &&\r
-                           atoi(appData.icsPort) == TN_PORT) {\r
-                           TelnetRequest(TN_DONT, TN_ECHO);\r
-                       } else {\r
-                           EchoOff();\r
-                           TelnetRequest(TN_DO, TN_ECHO);\r
-                           remoteEchoOption = TRUE;\r
-                       }\r
-                       break;\r
-                     default:\r
-                       if (appData.debugMode)\r
-                         fprintf(debugFP, "%d ", option);\r
-                       /* Whatever this is, we don't want it. */\r
-                       TelnetRequest(TN_DONT, option);\r
-                       break;\r
-                   }\r
-                   break;\r
-                 case TN_WONT:\r
-                   if (appData.debugMode)\r
-                     fprintf(debugFP, "\n<WONT ");\r
-                   switch (option = (unsigned char) buf[++i]) {\r
-                     case TN_ECHO:\r
-                       if (appData.debugMode)\r
-                         fprintf(debugFP, "ECHO ");\r
-                       /* Reply only if this is a change, according\r
-                          to the protocol rules. */\r
-                       if (!remoteEchoOption) break;\r
-                       EchoOn();\r
-                       TelnetRequest(TN_DONT, TN_ECHO);\r
-                       remoteEchoOption = FALSE;\r
-                       break;\r
-                     default:\r
-                       if (appData.debugMode)\r
-                         fprintf(debugFP, "%d ", (unsigned char) option);\r
-                       /* Whatever this is, it must already be turned\r
-                          off, because we never agree to turn on\r
-                          anything non-default, so according to the\r
-                          protocol rules, we don't reply. */\r
-                       break;\r
-                   }\r
-                   break;\r
-                 case TN_DO:\r
-                   if (appData.debugMode)\r
-                     fprintf(debugFP, "\n<DO ");\r
-                   switch (option = (unsigned char) buf[++i]) {\r
-                     default:\r
-                       /* Whatever this is, we refuse to do it. */\r
-                       if (appData.debugMode)\r
-                         fprintf(debugFP, "%d ", option);\r
-                       TelnetRequest(TN_WONT, option);\r
-                       break;\r
-                   }\r
-                   break;\r
-                 case TN_DONT:\r
-                   if (appData.debugMode)\r
-                     fprintf(debugFP, "\n<DONT ");\r
-                   switch (option = (unsigned char) buf[++i]) {\r
-                     default:\r
-                       if (appData.debugMode)\r
-                         fprintf(debugFP, "%d ", option);\r
-                       /* Whatever this is, we are already not doing\r
-                          it, because we never agree to do anything\r
-                          non-default, so according to the protocol\r
-                          rules, we don't reply. */\r
-                       break;\r
-                   }\r
-                   break;\r
-                 case TN_IAC:\r
-                   if (appData.debugMode)\r
-                     fprintf(debugFP, "\n<IAC ");\r
-                   /* Doubled IAC; pass it through */\r
-                   i--;\r
-                   break;\r
-                 default:\r
-                   if (appData.debugMode)\r
-                     fprintf(debugFP, "\n<%d ", (unsigned char) buf[i]);\r
-                   /* Drop all other telnet commands on the floor */\r
-                   break;\r
-               }\r
-               if (oldi > next_out)\r
-                 SendToPlayer(&buf[next_out], oldi - next_out);\r
-               if (++i > next_out)\r
-                 next_out = i;\r
-               continue;\r
-           }\r
-               \r
-           /* OK, this at least will *usually* work */\r
-           if (!loggedOn && looking_at(buf, &i, "ics%")) {\r
-               loggedOn = TRUE;\r
-           }\r
-           \r
-           if (loggedOn && !intfSet) {\r
-               if (ics_type == ICS_ICC) {\r
-                 sprintf(str,\r
-                         "/set-quietly interface %s\n/set-quietly style 12\n",\r
-                         programVersion);\r
-\r
-               } else if (ics_type == ICS_CHESSNET) {\r
-                 sprintf(str, "/style 12\n");\r
-               } else {\r
-                 strcpy(str, "alias $ @\n$set interface ");\r
-                 strcat(str, programVersion);\r
-                 strcat(str, "\n$iset startpos 1\n$iset ms 1\n");\r
-#ifdef WIN32\r
-                 strcat(str, "$iset nohighlight 1\n");\r
-#endif\r
-                 strcat(str, "$iset lock 1\n$style 12\n");\r
-               }\r
-               SendToICS(str);\r
-               intfSet = TRUE;\r
-           }\r
-\r
-           if (started == STARTED_COMMENT) {\r
-               /* Accumulate characters in comment */\r
-               parse[parse_pos++] = buf[i];\r
-               if (buf[i] == '\n') {\r
-                   parse[parse_pos] = NULLCHAR;\r
-                   if(!suppressKibitz) // [HGM] kibitz\r
-                       AppendComment(forwardMostMove, StripHighlight(parse));\r
-                   else { // [HGM kibitz: divert memorized engine kibitz to engine-output window\r
-                       int nrDigit = 0, nrAlph = 0, i;\r
-                       if(parse_pos > MSG_SIZ - 30) // defuse unreasonably long input\r
-                       { parse_pos = MSG_SIZ-30; parse[parse_pos - 1] = '\n'; }\r
-                       parse[parse_pos] = NULLCHAR;\r
-                       // try to be smart: if it does not look like search info, it should go to\r
-                       // ICS interaction window after all, not to engine-output window.\r
-                       for(i=0; i<parse_pos; i++) { // count letters and digits\r
-                           nrDigit += (parse[i] >= '0' && parse[i] <= '9');\r
-                           nrAlph  += (parse[i] >= 'a' && parse[i] <= 'z');\r
-                           nrAlph  += (parse[i] >= 'A' && parse[i] <= 'Z');\r
-                       }\r
-                       if(nrAlph < 9*nrDigit) { // if more than 10% digit we assume search info\r
-                           OutputKibitz(suppressKibitz, parse);\r
-                       } else {\r
-                           char tmp[MSG_SIZ];\r
-                           sprintf(tmp, _("your opponent kibitzes: %s"), parse);\r
-                           SendToPlayer(tmp, strlen(tmp));\r
-                       }\r
-                   }\r
-                   started = STARTED_NONE;\r
-               } else {\r
-                   /* Don't match patterns against characters in chatter */\r
-                   i++;\r
-                   continue;\r
-               }\r
-           }\r
-           if (started == STARTED_CHATTER) {\r
-               if (buf[i] != '\n') {\r
-                   /* Don't match patterns against characters in chatter */\r
-                   i++;\r
-                   continue;\r
-               }\r
-               started = STARTED_NONE;\r
-           }\r
-\r
-            /* Kludge to deal with rcmd protocol */\r
-           if (firstTime && looking_at(buf, &i, "\001*")) {\r
-               DisplayFatalError(&buf[1], 0, 1);\r
-               continue;\r
-           } else {\r
-               firstTime = FALSE;\r
-           }\r
-\r
-           if (!loggedOn && looking_at(buf, &i, "chessclub.com")) {\r
-               ics_type = ICS_ICC;\r
-               ics_prefix = "/";\r
-               if (appData.debugMode)\r
-                 fprintf(debugFP, "ics_type %d\n", ics_type);\r
-               continue;\r
-           }\r
-           if (!loggedOn && looking_at(buf, &i, "freechess.org")) {\r
-               ics_type = ICS_FICS;\r
-               ics_prefix = "$";\r
-               if (appData.debugMode)\r
-                 fprintf(debugFP, "ics_type %d\n", ics_type);\r
-               continue;\r
-           }\r
-           if (!loggedOn && looking_at(buf, &i, "chess.net")) {\r
-               ics_type = ICS_CHESSNET;\r
-               ics_prefix = "/";\r
-               if (appData.debugMode)\r
-                 fprintf(debugFP, "ics_type %d\n", ics_type);\r
-               continue;\r
-           }\r
-\r
-           if (!loggedOn &&\r
-               (looking_at(buf, &i, "\"*\" is *a registered name") ||\r
-                looking_at(buf, &i, "Logging you in as \"*\"") ||\r
-                looking_at(buf, &i, "will be \"*\""))) {\r
-             strcpy(ics_handle, star_match[0]);\r
-             continue;\r
-           }\r
-\r
-           if (loggedOn && !have_set_title && ics_handle[0] != NULLCHAR) {\r
-             char buf[MSG_SIZ];\r
-             sprintf(buf, "%s@%s", ics_handle, appData.icsHost);\r
-             DisplayIcsInteractionTitle(buf);\r
-             have_set_title = TRUE;\r
-           }\r
-\r
-           /* skip finger notes */\r
-           if (started == STARTED_NONE &&\r
-               ((buf[i] == ' ' && isdigit(buf[i+1])) ||\r
-                (buf[i] == '1' && buf[i+1] == '0')) &&\r
-               buf[i+2] == ':' && buf[i+3] == ' ') {\r
-             started = STARTED_CHATTER;\r
-             i += 3;\r
-             continue;\r
-           }\r
-\r
-           /* skip formula vars */\r
-           if (started == STARTED_NONE &&\r
-               buf[i] == 'f' && isdigit(buf[i+1]) && buf[i+2] == ':') {\r
-             started = STARTED_CHATTER;\r
-             i += 3;\r
-             continue;\r
-           }\r
-\r
-           oldi = i;\r
-           // [HGM] kibitz: try to recognize opponent engine-score kibitzes, to divert them to engine-output window\r
-           if (appData.autoKibitz && started == STARTED_NONE && \r
-                !appData.icsEngineAnalyze &&                     // [HGM] [DM] ICS analyze\r
-               (gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack || gameMode == IcsObserving)) {\r
-               if(looking_at(buf, &i, "* kibitzes: ") &&\r
-                  (StrStr(star_match[0], gameInfo.white) == star_match[0] || \r
-                   StrStr(star_match[0], gameInfo.black) == star_match[0]   )) { // kibitz of self or opponent\r
-                       suppressKibitz = TRUE;\r
-                       if((StrStr(star_match[0], gameInfo.white) == star_match[0])\r
-                               && (gameMode == IcsPlayingWhite) ||\r
-                          (StrStr(star_match[0], gameInfo.black) == star_match[0])\r
-                               && (gameMode == IcsPlayingBlack)   ) // opponent kibitz\r
-                           started = STARTED_CHATTER; // own kibitz we simply discard\r
-                       else {\r
-                           started = STARTED_COMMENT; // make sure it will be collected in parse[]\r
-                           parse_pos = 0; parse[0] = NULLCHAR;\r
-                           savingComment = TRUE;\r
-                           suppressKibitz = gameMode != IcsObserving ? 2 :\r
-                               (StrStr(star_match[0], gameInfo.white) == NULL) + 1;\r
-                       } \r
-                       continue;\r
-               } else\r
-               if(looking_at(buf, &i, "kibitzed to")) { // suppress the acknowledgements of our own autoKibitz\r
-                   started = STARTED_CHATTER;\r
-                   suppressKibitz = TRUE;\r
-               }\r
-           } // [HGM] kibitz: end of patch\r
-\r
-           if (appData.zippyTalk || appData.zippyPlay) {\r
-                /* [DM] Backup address for color zippy lines */\r
-                backup = i;\r
-#if ZIPPY\r
-       #ifdef WIN32\r
-               if (loggedOn == TRUE)\r
-                       if (ZippyControl(buf, &backup) || ZippyConverse(buf, &backup) ||\r
-                          (appData.zippyPlay && ZippyMatch(buf, &backup)));\r
-       #else\r
-                if (ZippyControl(buf, &i) ||\r
-                    ZippyConverse(buf, &i) ||\r
-                    (appData.zippyPlay && ZippyMatch(buf, &i))) {\r
-                     loggedOn = TRUE;\r
-                      if (!appData.colorize) continue;\r
-               }\r
-       #endif\r
-#endif\r
-           } // [DM] 'else { ' deleted\r
-               if (/* Don't color "message" or "messages" output */\r
-                   (tkind = 5, looking_at(buf, &i, "*. * (*:*): ")) ||\r
-                   looking_at(buf, &i, "*. * at *:*: ") ||\r
-                   looking_at(buf, &i, "--* (*:*): ") ||\r
-                   /* Regular tells and says */\r
-                   (tkind = 1, looking_at(buf, &i, "* tells you: ")) ||\r
-                   looking_at(buf, &i, "* (your partner) tells you: ") ||\r
-                   looking_at(buf, &i, "* says: ") ||\r
-                   /* Message notifications (same color as tells) */\r
-                   looking_at(buf, &i, "* has left a message ") ||\r
-                   looking_at(buf, &i, "* just sent you a message:\n") ||\r
-                   /* Whispers and kibitzes */\r
-                   (tkind = 2, looking_at(buf, &i, "* whispers: ")) ||\r
-                   looking_at(buf, &i, "* kibitzes: ") ||\r
-                   /* Channel tells */\r
-                   (tkind = 3, looking_at(buf, &i, "*(*: "))) {\r
-\r
-                 if (tkind == 1 && strchr(star_match[0], ':')) {\r
-                     /* Avoid "tells you:" spoofs in channels */\r
-                    tkind = 3;\r
-                 }\r
-                 if (star_match[0][0] == NULLCHAR ||\r
-                     strchr(star_match[0], ' ') ||\r
-                     (tkind == 3 && strchr(star_match[1], ' '))) {\r
-                   /* Reject bogus matches */\r
-                   i = oldi;\r
-                 } else {\r
-                   if (appData.colorize) {\r
-                     if (oldi > next_out) {\r
-                       SendToPlayer(&buf[next_out], oldi - next_out);\r
-                       next_out = oldi;\r
-                     }\r
-                     switch (tkind) {\r
-                     case 1:\r
-                       Colorize(ColorTell, FALSE);\r
-                       curColor = ColorTell;\r
-                       break;\r
-                     case 2:\r
-                       Colorize(ColorKibitz, FALSE);\r
-                       curColor = ColorKibitz;\r
-                       break;\r
-                     case 3:\r
-                       p = strrchr(star_match[1], '(');\r
-                       if (p == NULL) {\r
-                         p = star_match[1];\r
-                       } else {\r
-                         p++;\r
-                       }\r
-                       if (atoi(p) == 1) {\r
-                         Colorize(ColorChannel1, FALSE);\r
-                         curColor = ColorChannel1;\r
-                       } else {\r
-                         Colorize(ColorChannel, FALSE);\r
-                         curColor = ColorChannel;\r
-                       }\r
-                       break;\r
-                     case 5:\r
-                       curColor = ColorNormal;\r
-                       break;\r
-                     }\r
-                   }\r
-                   if (started == STARTED_NONE && appData.autoComment &&\r
-                       (gameMode == IcsObserving ||\r
-                        gameMode == IcsPlayingWhite ||\r
-                        gameMode == IcsPlayingBlack)) {\r
-                     parse_pos = i - oldi;\r
-                     memcpy(parse, &buf[oldi], parse_pos);\r
-                     parse[parse_pos] = NULLCHAR;\r
-                     started = STARTED_COMMENT;\r
-                     savingComment = TRUE;\r
-                   } else {\r
-                     started = STARTED_CHATTER;\r
-                     savingComment = FALSE;\r
-                   }\r
-                   loggedOn = TRUE;\r
-                   continue;\r
-                 }\r
-               }\r
-\r
-               if (looking_at(buf, &i, "* s-shouts: ") ||\r
-                   looking_at(buf, &i, "* c-shouts: ")) {\r
-                   if (appData.colorize) {\r
-                       if (oldi > next_out) {\r
-                           SendToPlayer(&buf[next_out], oldi - next_out);\r
-                           next_out = oldi;\r
-                       }\r
-                       Colorize(ColorSShout, FALSE);\r
-                       curColor = ColorSShout;\r
-                   }\r
-                   loggedOn = TRUE;\r
-                   started = STARTED_CHATTER;\r
-                   continue;\r
-               }\r
-\r
-               if (looking_at(buf, &i, "--->")) {\r
-                   loggedOn = TRUE;\r
-                   continue;\r
-               }\r
-\r
-               if (looking_at(buf, &i, "* shouts: ") ||\r
-                   looking_at(buf, &i, "--> ")) {\r
-                   if (appData.colorize) {\r
-                       if (oldi > next_out) {\r
-                           SendToPlayer(&buf[next_out], oldi - next_out);\r
-                           next_out = oldi;\r
-                       }\r
-                       Colorize(ColorShout, FALSE);\r
-                       curColor = ColorShout;\r
-                   }\r
-                   loggedOn = TRUE;\r
-                   started = STARTED_CHATTER;\r
-                   continue;\r
-               }\r
-\r
-               if (looking_at( buf, &i, "Challenge:")) {\r
-                   if (appData.colorize) {\r
-                       if (oldi > next_out) {\r
-                           SendToPlayer(&buf[next_out], oldi - next_out);\r
-                           next_out = oldi;\r
-                       }\r
-                       Colorize(ColorChallenge, FALSE);\r
-                       curColor = ColorChallenge;\r
-                   }\r
-                   loggedOn = TRUE;\r
-                   continue;\r
-               }\r
-\r
-               if (looking_at(buf, &i, "* offers you") ||\r
-                   looking_at(buf, &i, "* offers to be") ||\r
-                   looking_at(buf, &i, "* would like to") ||\r
-                   looking_at(buf, &i, "* requests to") ||\r
-                   looking_at(buf, &i, "Your opponent offers") ||\r
-                   looking_at(buf, &i, "Your opponent requests")) {\r
-\r
-                   if (appData.colorize) {\r
-                       if (oldi > next_out) {\r
-                           SendToPlayer(&buf[next_out], oldi - next_out);\r
-                           next_out = oldi;\r
-                       }\r
-                       Colorize(ColorRequest, FALSE);\r
-                       curColor = ColorRequest;\r
-                   }\r
-                   continue;\r
-               }\r
-\r
-               if (looking_at(buf, &i, "* (*) seeking")) {\r
-                   if (appData.colorize) {\r
-                       if (oldi > next_out) {\r
-                           SendToPlayer(&buf[next_out], oldi - next_out);\r
-                           next_out = oldi;\r
-                       }\r
-                       Colorize(ColorSeek, FALSE);\r
-                       curColor = ColorSeek;\r
-                   }\r
-                   continue;\r
-           }\r
-\r
-           if (looking_at(buf, &i, "\\   ")) {\r
-               if (prevColor != ColorNormal) {\r
-                   if (oldi > next_out) {\r
-                       SendToPlayer(&buf[next_out], oldi - next_out);\r
-                       next_out = oldi;\r
-                   }\r
-                   Colorize(prevColor, TRUE);\r
-                   curColor = prevColor;\r
-               }\r
-               if (savingComment) {\r
-                   parse_pos = i - oldi;\r
-                   memcpy(parse, &buf[oldi], parse_pos);\r
-                   parse[parse_pos] = NULLCHAR;\r
-                   started = STARTED_COMMENT;\r
-               } else {\r
-                   started = STARTED_CHATTER;\r
-               }\r
-               continue;\r
-           }\r
-\r
-           if (looking_at(buf, &i, "Black Strength :") ||\r
-               looking_at(buf, &i, "<<< style 10 board >>>") ||\r
-               looking_at(buf, &i, "<10>") ||\r
-               looking_at(buf, &i, "#@#")) {\r
-               /* Wrong board style */\r
-               loggedOn = TRUE;\r
-               SendToICS(ics_prefix);\r
-               SendToICS("set style 12\n");\r
-               SendToICS(ics_prefix);\r
-               SendToICS("refresh\n");\r
-               continue;\r
-           }\r
-           \r
-           if (!have_sent_ICS_logon && looking_at(buf, &i, "login:")) {\r
-               ICSInitScript();\r
-               have_sent_ICS_logon = 1;\r
-               continue;\r
-           }\r
-             \r
-           if (ics_getting_history != H_GETTING_MOVES /*smpos kludge*/ && \r
-               (looking_at(buf, &i, "\n<12> ") ||\r
-                looking_at(buf, &i, "<12> "))) {\r
-               loggedOn = TRUE;\r
-               if (oldi > next_out) {\r
-                   SendToPlayer(&buf[next_out], oldi - next_out);\r
-               }\r
-               next_out = i;\r
-               started = STARTED_BOARD;\r
-               parse_pos = 0;\r
-               continue;\r
-           }\r
-\r
-           if ((started == STARTED_NONE && looking_at(buf, &i, "\n<b1> ")) ||\r
-               looking_at(buf, &i, "<b1> ")) {\r
-               if (oldi > next_out) {\r
-                   SendToPlayer(&buf[next_out], oldi - next_out);\r
-               }\r
-               next_out = i;\r
-               started = STARTED_HOLDINGS;\r
-               parse_pos = 0;\r
-               continue;\r
-           }\r
-\r
-           if (looking_at(buf, &i, "* *vs. * *--- *")) {\r
-               loggedOn = TRUE;\r
-               /* Header for a move list -- first line */\r
-\r
-               switch (ics_getting_history) {\r
-                 case H_FALSE:\r
-                   switch (gameMode) {\r
-                     case IcsIdle:\r
-                     case BeginningOfGame:\r
-                       /* User typed "moves" or "oldmoves" while we\r
-                          were idle.  Pretend we asked for these\r
-                          moves and soak them up so user can step\r
-                          through them and/or save them.\r
-                          */\r
-                       Reset(FALSE, TRUE);\r
-                       gameMode = IcsObserving;\r
-                       ModeHighlight();\r
-                       ics_gamenum = -1;\r
-                       ics_getting_history = H_GOT_UNREQ_HEADER;\r
-                       break;\r
-                     case EditGame: /*?*/\r
-                     case EditPosition: /*?*/\r
-                       /* Should above feature work in these modes too? */\r
-                       /* For now it doesn't */\r
-                       ics_getting_history = H_GOT_UNWANTED_HEADER;\r
-                       break;\r
-                     default:\r
-                       ics_getting_history = H_GOT_UNWANTED_HEADER;\r
-                       break;\r
-                   }\r
-                   break;\r
-                 case H_REQUESTED:\r
-                   /* Is this the right one? */\r
-                   if (gameInfo.white && gameInfo.black &&\r
-                       strcmp(gameInfo.white, star_match[0]) == 0 &&\r
-                       strcmp(gameInfo.black, star_match[2]) == 0) {\r
-                       /* All is well */\r
-                       ics_getting_history = H_GOT_REQ_HEADER;\r
-                   }\r
-                   break;\r
-                 case H_GOT_REQ_HEADER:\r
-                 case H_GOT_UNREQ_HEADER:\r
-                 case H_GOT_UNWANTED_HEADER:\r
-                 case H_GETTING_MOVES:\r
-                   /* Should not happen */\r
-                   DisplayError(_("Error gathering move list: two headers"), 0);\r
-                   ics_getting_history = H_FALSE;\r
-                   break;\r
-               }\r
-\r
-               /* Save player ratings into gameInfo if needed */\r
-               if ((ics_getting_history == H_GOT_REQ_HEADER ||\r
-                    ics_getting_history == H_GOT_UNREQ_HEADER) &&\r
-                   (gameInfo.whiteRating == -1 ||\r
-                    gameInfo.blackRating == -1)) {\r
-\r
-                   gameInfo.whiteRating = string_to_rating(star_match[1]);\r
-                   gameInfo.blackRating = string_to_rating(star_match[3]);\r
-                   if (appData.debugMode)\r
-                     fprintf(debugFP, _("Ratings from header: W %d, B %d\n"), \r
-                             gameInfo.whiteRating, gameInfo.blackRating);\r
-               }\r
-               continue;\r
-           }\r
-\r
-           if (looking_at(buf, &i,\r
-             "* * match, initial time: * minute*, increment: * second")) {\r
-               /* Header for a move list -- second line */\r
-               /* Initial board will follow if this is a wild game */\r
-               if (gameInfo.event != NULL) free(gameInfo.event);\r
-               sprintf(str, "ICS %s %s match", star_match[0], star_match[1]);\r
-               gameInfo.event = StrSave(str);\r
-                /* [HGM] we switched variant. Translate boards if needed. */\r
-                VariantSwitch(boards[currentMove], StringToVariant(gameInfo.event));\r
-               continue;\r
-           }\r
-\r
-           if (looking_at(buf, &i, "Move  ")) {\r
-               /* Beginning of a move list */\r
-               switch (ics_getting_history) {\r
-                 case H_FALSE:\r
-                   /* Normally should not happen */\r
-                   /* Maybe user hit reset while we were parsing */\r
-                   break;\r
-                 case H_REQUESTED:\r
-                   /* Happens if we are ignoring a move list that is not\r
-                    * the one we just requested.  Common if the user\r
-                    * tries to observe two games without turning off\r
-                    * getMoveList */\r
-                   break;\r
-                 case H_GETTING_MOVES:\r
-                   /* Should not happen */\r
-                   DisplayError(_("Error gathering move list: nested"), 0);\r
-                   ics_getting_history = H_FALSE;\r
-                   break;\r
-                 case H_GOT_REQ_HEADER:\r
-                   ics_getting_history = H_GETTING_MOVES;\r
-                   started = STARTED_MOVES;\r
-                   parse_pos = 0;\r
-                   if (oldi > next_out) {\r
-                       SendToPlayer(&buf[next_out], oldi - next_out);\r
-                   }\r
-                   break;\r
-                 case H_GOT_UNREQ_HEADER:\r
-                   ics_getting_history = H_GETTING_MOVES;\r
-                   started = STARTED_MOVES_NOHIDE;\r
-                   parse_pos = 0;\r
-                   break;\r
-                 case H_GOT_UNWANTED_HEADER:\r
-                   ics_getting_history = H_FALSE;\r
-                   break;\r
-               }\r
-               continue;\r
-           }                           \r
-           \r
-           if (looking_at(buf, &i, "% ") ||\r
-               ((started == STARTED_MOVES || started == STARTED_MOVES_NOHIDE)\r
-                && looking_at(buf, &i, "}*"))) { char *bookHit = NULL; // [HGM] book\r
-               savingComment = FALSE;\r
-               switch (started) {\r
-                 case STARTED_MOVES:\r
-                 case STARTED_MOVES_NOHIDE:\r
-                   memcpy(&parse[parse_pos], &buf[oldi], i - oldi);\r
-                   parse[parse_pos + i - oldi] = NULLCHAR;\r
-                   ParseGameHistory(parse);\r
-#if ZIPPY\r
-                   if (appData.zippyPlay && first.initDone) {\r
-                       FeedMovesToProgram(&first, forwardMostMove);\r
-                       if (gameMode == IcsPlayingWhite) {\r
-                           if (WhiteOnMove(forwardMostMove)) {\r
-                               if (first.sendTime) {\r
-                                 if (first.useColors) {\r
-                                   SendToProgram("black\n", &first); \r
-                                 }\r
-                                 SendTimeRemaining(&first, TRUE);\r
-                               }\r
-#if 0\r
-                               if (first.useColors) {\r
-                                 SendToProgram("white\ngo\n", &first);\r
-                               } else {\r
-                                 SendToProgram("go\n", &first);\r
-                               }\r
-#else\r
-                               if (first.useColors) {\r
-                                 SendToProgram("white\n", &first); // [HGM] book: made sending of "go\n" book dependent\r
-                               }\r
-                               bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE); // [HGM] book: probe book for initial pos\r
-#endif\r
-                               first.maybeThinking = TRUE;\r
-                           } else {\r
-                               if (first.usePlayother) {\r
-                                 if (first.sendTime) {\r
-                                   SendTimeRemaining(&first, TRUE);\r
-                                 }\r
-                                 SendToProgram("playother\n", &first);\r
-                                 firstMove = FALSE;\r
-                               } else {\r
-                                 firstMove = TRUE;\r
-                               }\r
-                           }\r
-                       } else if (gameMode == IcsPlayingBlack) {\r
-                           if (!WhiteOnMove(forwardMostMove)) {\r
-                               if (first.sendTime) {\r
-                                 if (first.useColors) {\r
-                                   SendToProgram("white\n", &first);\r
-                                 }\r
-                                 SendTimeRemaining(&first, FALSE);\r
-                               }\r
-#if 0\r
-                               if (first.useColors) {\r
-                                 SendToProgram("black\ngo\n", &first);\r
-                               } else {\r
-                                 SendToProgram("go\n", &first);\r
-                               }\r
-#else\r
-                               if (first.useColors) {\r
-                                 SendToProgram("black\n", &first);\r
-                               }\r
-                               bookHit = SendMoveToBookUser(forwardMostMove-1, &first, TRUE);\r
-#endif\r
-                               first.maybeThinking = TRUE;\r
-                           } else {\r
-                               if (first.usePlayother) {\r
-                                 if (first.sendTime) {\r
-                                   SendTimeRemaining(&first, FALSE);\r
-                                 }\r
-                                 SendToProgram("playother\n", &first);\r
-                                 firstMove = FALSE;\r
-                               } else {\r
-                                 firstMove = TRUE;\r
-                               }\r
-                           }\r
-                       }                       \r
-                   }\r
-#endif\r
-                   if (gameMode == IcsObserving && ics_gamenum == -1) {\r
-                       /* Moves came from oldmoves or moves command\r
-                          while we weren't doing anything else.\r
-                          */\r
-                       currentMove = forwardMostMove;\r
-                       ClearHighlights();/*!!could figure this out*/\r
-                       flipView = appData.flipView;\r
-                       DrawPosition(FALSE, boards[currentMove]);\r
-                       DisplayBothClocks();\r
-                       sprintf(str, "%s vs. %s",\r
-                               gameInfo.white, gameInfo.black);\r
-                       DisplayTitle(str);\r
-                       gameMode = IcsIdle;\r
-                   } else {\r
-                       /* Moves were history of an active game */\r
-                       if (gameInfo.resultDetails != NULL) {\r
-                           free(gameInfo.resultDetails);\r
-                           gameInfo.resultDetails = NULL;\r
-                       }\r
-                   }\r
-                   HistorySet(parseList, backwardMostMove,\r
-                              forwardMostMove, currentMove-1);\r
-                   DisplayMove(currentMove - 1);\r
-                   if (started == STARTED_MOVES) next_out = i;\r
-                   started = STARTED_NONE;\r
-                   ics_getting_history = H_FALSE;\r
-                   break;\r
-\r
-                 case STARTED_OBSERVE:\r
-                   started = STARTED_NONE;\r
-                   SendToICS(ics_prefix);\r
-                   SendToICS("refresh\n");\r
-                   break;\r
-\r
-                 default:\r
-                   break;\r
-               }\r
-               if(bookHit) { // [HGM] book: simulate book reply\r
-                   static char bookMove[MSG_SIZ]; // a bit generous?\r
-\r
-                   programStats.depth = programStats.nodes = programStats.time = \r
-                   programStats.score = programStats.got_only_move = 0;\r
-                   sprintf(programStats.movelist, "%s (xbook)", bookHit);\r
-\r
-                   strcpy(bookMove, "move ");\r
-                   strcat(bookMove, bookHit);\r
-                   HandleMachineMove(bookMove, &first);\r
-               }\r
-               continue;\r
-           }\r
-           \r
-           if ((started == STARTED_MOVES || started == STARTED_BOARD ||\r
-                started == STARTED_HOLDINGS ||\r
-                started == STARTED_MOVES_NOHIDE) && i >= leftover_len) {\r
-               /* Accumulate characters in move list or board */\r
-               parse[parse_pos++] = buf[i];\r
-           }\r
-           \r
-           /* Start of game messages.  Mostly we detect start of game\r
-              when the first board image arrives.  On some versions\r
-              of the ICS, though, we need to do a "refresh" after starting\r
-              to observe in order to get the current board right away. */\r
-           if (looking_at(buf, &i, "Adding game * to observation list")) {\r
-               started = STARTED_OBSERVE;\r
-               continue;\r
-           }\r
-\r
-           /* Handle auto-observe */\r
-           if (appData.autoObserve &&\r
-               (gameMode == IcsIdle || gameMode == BeginningOfGame) &&\r
-               looking_at(buf, &i, "Game notification: * (*) vs. * (*)")) {\r
-               char *player;\r
-               /* Choose the player that was highlighted, if any. */\r
-               if (star_match[0][0] == '\033' ||\r
-                   star_match[1][0] != '\033') {\r
-                   player = star_match[0];\r
-               } else {\r
-                   player = star_match[2];\r
-               }\r
-               sprintf(str, "%sobserve %s\n",\r
-                       ics_prefix, StripHighlightAndTitle(player));\r
-               SendToICS(str);\r
-\r
-               /* Save ratings from notify string */\r
-               strcpy(player1Name, star_match[0]);\r
-               player1Rating = string_to_rating(star_match[1]);\r
-               strcpy(player2Name, star_match[2]);\r
-               player2Rating = string_to_rating(star_match[3]);\r
-\r
-               if (appData.debugMode)\r
-                 fprintf(debugFP, \r
-                         "Ratings from 'Game notification:' %s %d, %s %d\n",\r
-                         player1Name, player1Rating,\r
-                         player2Name, player2Rating);\r
-\r
-               continue;\r
-           }\r
-\r
-           /* Deal with automatic examine mode after a game,\r
-              and with IcsObserving -> IcsExamining transition */\r
-           if (looking_at(buf, &i, "Entering examine mode for game *") ||\r
-               looking_at(buf, &i, "has made you an examiner of game *")) {\r
-\r
-               int gamenum = atoi(star_match[0]);\r
-               if ((gameMode == IcsIdle || gameMode == IcsObserving) &&\r
-                   gamenum == ics_gamenum) {\r
-                   /* We were already playing or observing this game;\r
-                      no need to refetch history */\r
-                   gameMode = IcsExamining;\r
-                   if (pausing) {\r
-                       pauseExamForwardMostMove = forwardMostMove;\r
-                   } else if (currentMove < forwardMostMove) {\r
-                       ForwardInner(forwardMostMove);\r
-                   }\r
-               } else {\r
-                   /* I don't think this case really can happen */\r
-                   SendToICS(ics_prefix);\r
-                   SendToICS("refresh\n");\r
-               }\r
-               continue;\r
-           }    \r
-           \r
-           /* Error messages */\r
-           if (ics_user_moved) {\r
-               if (looking_at(buf, &i, "Illegal move") ||\r
-                   looking_at(buf, &i, "Not a legal move") ||\r
-                   looking_at(buf, &i, "Your king is in check") ||\r
-                   looking_at(buf, &i, "It isn't your turn") ||\r
-                   looking_at(buf, &i, "It is not your move")) {\r
-                   /* Illegal move */\r
-                   ics_user_moved = 0;\r
-                   if (forwardMostMove > backwardMostMove) {\r
-                       currentMove = --forwardMostMove;\r
-                       DisplayMove(currentMove - 1); /* before DMError */\r
-                       DisplayMoveError(_("Illegal move (rejected by ICS)"));\r
-                       DrawPosition(FALSE, boards[currentMove]);\r
-                       SwitchClocks();\r
-                       DisplayBothClocks();\r
-                   }\r
-                   continue;\r
-               }\r
-           }\r
-\r
-           if (looking_at(buf, &i, "still have time") ||\r
-               looking_at(buf, &i, "not out of time") ||\r
-               looking_at(buf, &i, "either player is out of time") ||\r
-               looking_at(buf, &i, "has timeseal; checking")) {\r
-               /* We must have called his flag a little too soon */\r
-               whiteFlag = blackFlag = FALSE;\r
-               continue;\r
-           }\r
-\r
-           if (looking_at(buf, &i, "added * seconds to") ||\r
-               looking_at(buf, &i, "seconds were added to")) {\r
-               /* Update the clocks */\r
-               SendToICS(ics_prefix);\r
-               SendToICS("refresh\n");\r
-               continue;\r
-           }\r
-\r
-           if (!ics_clock_paused && looking_at(buf, &i, "clock paused")) {\r
-               ics_clock_paused = TRUE;\r
-               StopClocks();\r
-               continue;\r
-           }\r
-\r
-           if (ics_clock_paused && looking_at(buf, &i, "clock resumed")) {\r
-               ics_clock_paused = FALSE;\r
-               StartClocks();\r
-               continue;\r
-           }\r
-\r
-           /* Grab player ratings from the Creating: message.\r
-              Note we have to check for the special case when\r
-              the ICS inserts things like [white] or [black]. */\r
-           if (looking_at(buf, &i, "Creating: * (*)* * (*)") ||\r
-               looking_at(buf, &i, "Creating: * (*) [*] * (*)")) {\r
-               /* star_matches:\r
-                  0    player 1 name (not necessarily white)\r
-                  1    player 1 rating\r
-                  2    empty, white, or black (IGNORED)\r
-                  3    player 2 name (not necessarily black)\r
-                  4    player 2 rating\r
-                  \r
-                  The names/ratings are sorted out when the game\r
-                  actually starts (below).\r
-               */\r
-               strcpy(player1Name, StripHighlightAndTitle(star_match[0]));\r
-               player1Rating = string_to_rating(star_match[1]);\r
-               strcpy(player2Name, StripHighlightAndTitle(star_match[3]));\r
-               player2Rating = string_to_rating(star_match[4]);\r
-\r
-               if (appData.debugMode)\r
-                 fprintf(debugFP, \r
-                         "Ratings from 'Creating:' %s %d, %s %d\n",\r
-                         player1Name, player1Rating,\r
-                         player2Name, player2Rating);\r
-\r
-               continue;\r
-           }\r
-           \r
-           /* Improved generic start/end-of-game messages */\r
-           if ((tkind=0, looking_at(buf, &i, "{Game * (* vs. *) *}*")) ||\r
-               (tkind=1, looking_at(buf, &i, "{Game * (*(*) vs. *(*)) *}*"))){\r
-               /* If tkind == 0: */\r
-               /* star_match[0] is the game number */\r
-               /*           [1] is the white player's name */\r
-               /*           [2] is the black player's name */\r
-               /* For end-of-game: */\r
-               /*           [3] is the reason for the game end */\r
-               /*           [4] is a PGN end game-token, preceded by " " */\r
-               /* For start-of-game: */\r
-               /*           [3] begins with "Creating" or "Continuing" */\r
-               /*           [4] is " *" or empty (don't care). */\r
-               int gamenum = atoi(star_match[0]);\r
-               char *whitename, *blackname, *why, *endtoken;\r
-               ChessMove endtype = (ChessMove) 0;\r
-\r
-               if (tkind == 0) {\r
-                 whitename = star_match[1];\r
-                 blackname = star_match[2];\r
-                 why = star_match[3];\r
-                 endtoken = star_match[4];\r
-               } else {\r
-                 whitename = star_match[1];\r
-                 blackname = star_match[3];\r
-                 why = star_match[5];\r
-                 endtoken = star_match[6];\r
-               }\r
-\r
-                /* Game start messages */\r
-               if (strncmp(why, "Creating ", 9) == 0 ||\r
-                   strncmp(why, "Continuing ", 11) == 0) {\r
-                   gs_gamenum = gamenum;\r
-                   strcpy(gs_kind, strchr(why, ' ') + 1);\r
-#if ZIPPY\r
-                   if (appData.zippyPlay) {\r
-                       ZippyGameStart(whitename, blackname);\r
-                   }\r
-#endif /*ZIPPY*/\r
-                   continue;\r
-               }\r
-\r
-               /* Game end messages */\r
-               if (gameMode == IcsIdle || gameMode == BeginningOfGame ||\r
-                   ics_gamenum != gamenum) {\r
-                   continue;\r
-               }\r
-               while (endtoken[0] == ' ') endtoken++;\r
-               switch (endtoken[0]) {\r
-                 case '*':\r
-                 default:\r
-                   endtype = GameUnfinished;\r
-                   break;\r
-                 case '0':\r
-                   endtype = BlackWins;\r
-                   break;\r
-                 case '1':\r
-                   if (endtoken[1] == '/')\r
-                     endtype = GameIsDrawn;\r
-                   else\r
-                     endtype = WhiteWins;\r
-                   break;\r
-               }\r
-               GameEnds(endtype, why, GE_ICS);\r
-#if ZIPPY\r
-               if (appData.zippyPlay && first.initDone) {\r
-                   ZippyGameEnd(endtype, why);\r
-                   if (first.pr == NULL) {\r
-                     /* Start the next process early so that we'll\r
-                        be ready for the next challenge */\r
-                     StartChessProgram(&first);\r
-                   }\r
-                   /* Send "new" early, in case this command takes\r
-                      a long time to finish, so that we'll be ready\r
-                      for the next challenge. */\r
-                   gameInfo.variant = VariantNormal; // [HGM] variantswitch: suppress sending of 'variant'\r
-                   Reset(TRUE, TRUE);\r
-               }\r
-#endif /*ZIPPY*/\r
-               continue;\r
-           }\r
-\r
-           if (looking_at(buf, &i, "Removing game * from observation") ||\r
-               looking_at(buf, &i, "no longer observing game *") ||\r
-               looking_at(buf, &i, "Game * (*) has no examiners")) {\r
-               if (gameMode == IcsObserving &&\r
-                   atoi(star_match[0]) == ics_gamenum)\r
-                 {\r
-                      /* icsEngineAnalyze */\r
-                      if (appData.icsEngineAnalyze) {\r
-                            ExitAnalyzeMode();\r
-                            ModeHighlight();\r
-                      }\r
-                     StopClocks();\r
-                     gameMode = IcsIdle;\r
-                     ics_gamenum = -1;\r
-                     ics_user_moved = FALSE;\r
-                 }\r
-               continue;\r
-           }\r
-\r
-           if (looking_at(buf, &i, "no longer examining game *")) {\r
-               if (gameMode == IcsExamining &&\r
-                   atoi(star_match[0]) == ics_gamenum)\r
-                 {\r
-                     gameMode = IcsIdle;\r
-                     ics_gamenum = -1;\r
-                     ics_user_moved = FALSE;\r
-                 }\r
-               continue;\r
-           }\r
-\r
-           /* Advance leftover_start past any newlines we find,\r
-              so only partial lines can get reparsed */\r
-           if (looking_at(buf, &i, "\n")) {\r
-               prevColor = curColor;\r
-               if (curColor != ColorNormal) {\r
-                   if (oldi > next_out) {\r
-                       SendToPlayer(&buf[next_out], oldi - next_out);\r
-                       next_out = oldi;\r
-                   }\r
-                   Colorize(ColorNormal, FALSE);\r
-                   curColor = ColorNormal;\r
-               }\r
-               if (started == STARTED_BOARD) {\r
-                   started = STARTED_NONE;\r
-                   parse[parse_pos] = NULLCHAR;\r
-                   ParseBoard12(parse);\r
-                   ics_user_moved = 0;\r
-\r
-                   /* Send premove here */\r
-                   if (appData.premove) {\r
-                     char str[MSG_SIZ];\r
-                     if (currentMove == 0 &&\r
-                         gameMode == IcsPlayingWhite &&\r
-                         appData.premoveWhite) {\r
-                       sprintf(str, "%s%s\n", ics_prefix,\r
-                               appData.premoveWhiteText);\r
-                       if (appData.debugMode)\r
-                         fprintf(debugFP, "Sending premove:\n");\r
-                       SendToICS(str);\r
-                     } else if (currentMove == 1 &&\r
-                                gameMode == IcsPlayingBlack &&\r
-                                appData.premoveBlack) {\r
-                       sprintf(str, "%s%s\n", ics_prefix,\r
-                               appData.premoveBlackText);\r
-                       if (appData.debugMode)\r
-                         fprintf(debugFP, "Sending premove:\n");\r
-                       SendToICS(str);\r
-                     } else if (gotPremove) {\r
-                       gotPremove = 0;\r
-                       ClearPremoveHighlights();\r
-                       if (appData.debugMode)\r
-                         fprintf(debugFP, "Sending premove:\n");\r
-                          UserMoveEvent(premoveFromX, premoveFromY, \r
-                                       premoveToX, premoveToY, \r
-                                        premovePromoChar);\r
-                     }\r
-                   }\r
-\r
-                   /* Usually suppress following prompt */\r
-                   if (!(forwardMostMove == 0 && gameMode == IcsExamining)) {\r
-                       if (looking_at(buf, &i, "*% ")) {\r
-                           savingComment = FALSE;\r
-                       }\r
-                   }\r
-                   next_out = i;\r
-               } else if (started == STARTED_HOLDINGS) {\r
-                   int gamenum;\r
-                   char new_piece[MSG_SIZ];\r
-                   started = STARTED_NONE;\r
-                   parse[parse_pos] = NULLCHAR;\r
-                   if (appData.debugMode)\r
-                      fprintf(debugFP, "Parsing holdings: %s, currentMove = %d\n",\r
-                                                        parse, currentMove);\r
-                   if (sscanf(parse, " game %d", &gamenum) == 1 &&\r
-                       gamenum == ics_gamenum) {\r
-                       if (gameInfo.variant == VariantNormal) {\r
-                          /* [HGM] We seem to switch variant during a game!\r
-                           * Presumably no holdings were displayed, so we have\r
-                           * to move the position two files to the right to\r
-                           * create room for them!\r
-                           */\r
-                          VariantSwitch(boards[currentMove], VariantCrazyhouse); /* temp guess */\r
-                         /* Get a move list just to see the header, which\r
-                            will tell us whether this is really bug or zh */\r
-                         if (ics_getting_history == H_FALSE) {\r
-                           ics_getting_history = H_REQUESTED;\r
-                           sprintf(str, "%smoves %d\n", ics_prefix, gamenum);\r
-                           SendToICS(str);\r
-                         }\r
-                       }\r
-                       new_piece[0] = NULLCHAR;\r
-                       sscanf(parse, "game %d white [%s black [%s <- %s",\r
-                              &gamenum, white_holding, black_holding,\r
-                              new_piece);\r
-                        white_holding[strlen(white_holding)-1] = NULLCHAR;\r
-                        black_holding[strlen(black_holding)-1] = NULLCHAR;\r
-                        /* [HGM] copy holdings to board holdings area */\r
-                        CopyHoldings(boards[currentMove], white_holding, WhitePawn);\r
-                        CopyHoldings(boards[currentMove], black_holding, BlackPawn);\r
-#if ZIPPY\r
-                       if (appData.zippyPlay && first.initDone) {\r
-                           ZippyHoldings(white_holding, black_holding,\r
-                                         new_piece);\r
-                       }\r
-#endif /*ZIPPY*/\r
-                       if (tinyLayout || smallLayout) {\r
-                           char wh[16], bh[16];\r
-                           PackHolding(wh, white_holding);\r
-                           PackHolding(bh, black_holding);\r
-                           sprintf(str, "[%s-%s] %s-%s", wh, bh,\r
-                                   gameInfo.white, gameInfo.black);\r
-                       } else {\r
-                           sprintf(str, "%s [%s] vs. %s [%s]",\r
-                                   gameInfo.white, white_holding,\r
-                                   gameInfo.black, black_holding);\r
-                       }\r
-\r
-                        DrawPosition(FALSE, boards[currentMove]);\r
-                       DisplayTitle(str);\r
-                   }\r
-                   /* Suppress following prompt */\r
-                   if (looking_at(buf, &i, "*% ")) {\r
-                       savingComment = FALSE;\r
-                   }\r
-                   next_out = i;\r
-               }\r
-               continue;\r
-           }\r
-\r
-           i++;                /* skip unparsed character and loop back */\r
-       }\r
-       \r
-       if (started != STARTED_MOVES && started != STARTED_BOARD && !suppressKibitz && // [HGM] kibitz suppress printing in ICS interaction window\r
-           started != STARTED_HOLDINGS && i > next_out) {\r
-           SendToPlayer(&buf[next_out], i - next_out);\r
-           next_out = i;\r
-       }\r
-       suppressKibitz = FALSE; // [HGM] kibitz: has done its duty in if-statement above\r
-       \r
-       leftover_len = buf_len - leftover_start;\r
-       /* if buffer ends with something we couldn't parse,\r
-          reparse it after appending the next read */\r
-       \r
-    } else if (count == 0) {\r
-       RemoveInputSource(isr);\r
-        DisplayFatalError(_("Connection closed by ICS"), 0, 0);\r
-    } else {\r
-       DisplayFatalError(_("Error reading from ICS"), error, 1);\r
-    }\r
-}\r
-\r
-\r
-/* Board style 12 looks like this:\r
-   \r
-   <12> r-b---k- pp----pp ---bP--- ---p---- q------- ------P- P--Q--BP -----R-K W -1 0 0 0 0 0 0 paf MaxII 0 2 12 21 25 234 174 24 Q/d7-a4 (0:06) Qxa4 0 0\r
-   \r
- * The "<12> " is stripped before it gets to this routine.  The two\r
- * trailing 0's (flip state and clock ticking) are later addition, and\r
- * some chess servers may not have them, or may have only the first.\r
- * Additional trailing fields may be added in the future.  \r
- */\r
-\r
-#define PATTERN "%c%d%d%d%d%d%d%d%s%s%d%d%d%d%d%d%d%d%s%s%s%d%d"\r
-\r
-#define RELATION_OBSERVING_PLAYED    0\r
-#define RELATION_OBSERVING_STATIC   -2   /* examined, oldmoves, or smoves */\r
-#define RELATION_PLAYING_MYMOVE      1\r
-#define RELATION_PLAYING_NOTMYMOVE  -1\r
-#define RELATION_EXAMINING           2\r
-#define RELATION_ISOLATED_BOARD     -3\r
-#define RELATION_STARTING_POSITION  -4   /* FICS only */\r
-\r
-void\r
-ParseBoard12(string)\r
-     char *string;\r
-{ \r
-    GameMode newGameMode;\r
-    int gamenum, newGame, newMove, relation, basetime, increment, ics_flip = 0, i;\r
-    int j, k, n, moveNum, white_stren, black_stren, white_time, black_time, takeback;\r
-    int double_push, castle_ws, castle_wl, castle_bs, castle_bl, irrev_count;\r
-    char to_play, board_chars[200];\r
-    char move_str[500], str[500], elapsed_time[500];\r
-    char black[32], white[32];\r
-    Board board;\r
-    int prevMove = currentMove;\r
-    int ticking = 2;\r
-    ChessMove moveType;\r
-    int fromX, fromY, toX, toY;\r
-    char promoChar;\r
-    int ranks=1, files=0; /* [HGM] ICS80: allow variable board size */\r
-    char *bookHit = NULL; // [HGM] book\r
-\r
-    fromX = fromY = toX = toY = -1;\r
-    \r
-    newGame = FALSE;\r
-\r
-    if (appData.debugMode)\r
-      fprintf(debugFP, _("Parsing board: %s\n"), string);\r
-\r
-    move_str[0] = NULLCHAR;\r
-    elapsed_time[0] = NULLCHAR;\r
-    {   /* [HGM] figure out how many ranks and files the board has, for ICS extension used by Capablanca server */\r
-        int  i = 0, j;\r
-        while(i < 199 && (string[i] != ' ' || string[i+2] != ' ')) {\r
-           if(string[i] == ' ') { ranks++; files = 0; }\r
-            else files++;\r
-           i++;\r
-       }\r
-       for(j = 0; j <i; j++) board_chars[j] = string[j];\r
-        board_chars[i] = '\0';\r
-       string += i + 1;\r
-    }\r
-    n = sscanf(string, PATTERN, &to_play, &double_push,\r
-              &castle_ws, &castle_wl, &castle_bs, &castle_bl, &irrev_count,\r
-              &gamenum, white, black, &relation, &basetime, &increment,\r
-              &white_stren, &black_stren, &white_time, &black_time,\r
-              &moveNum, str, elapsed_time, move_str, &ics_flip,\r
-              &ticking);\r
-\r
-    if (n < 21) {\r
-       sprintf(str, _("Failed to parse board string:\n\"%s\""), string);\r
-       DisplayError(str, 0);\r
-       return;\r
-    }\r
-\r
-    /* Convert the move number to internal form */\r
-    moveNum = (moveNum - 1) * 2;\r
-    if (to_play == 'B') moveNum++;\r
-    if (moveNum >= MAX_MOVES) {\r
-      DisplayFatalError(_("Game too long; increase MAX_MOVES and recompile"),\r
-                       0, 1);\r
-      return;\r
-    }\r
-    \r
-    switch (relation) {\r
-      case RELATION_OBSERVING_PLAYED:\r
-      case RELATION_OBSERVING_STATIC:\r
-       if (gamenum == -1) {\r
-           /* Old ICC buglet */\r
-           relation = RELATION_OBSERVING_STATIC;\r
-       }\r
-       newGameMode = IcsObserving;\r
-       break;\r
-      case RELATION_PLAYING_MYMOVE:\r
-      case RELATION_PLAYING_NOTMYMOVE:\r
-       newGameMode =\r
-         ((relation == RELATION_PLAYING_MYMOVE) == (to_play == 'W')) ?\r
-           IcsPlayingWhite : IcsPlayingBlack;\r
-       break;\r
-      case RELATION_EXAMINING:\r
-       newGameMode = IcsExamining;\r
-       break;\r
-      case RELATION_ISOLATED_BOARD:\r
-      default:\r
-       /* Just display this board.  If user was doing something else,\r
-          we will forget about it until the next board comes. */ \r
-       newGameMode = IcsIdle;\r
-       break;\r
-      case RELATION_STARTING_POSITION:\r
-       newGameMode = gameMode;\r
-       break;\r
-    }\r
-    \r
-    /* Modify behavior for initial board display on move listing\r
-       of wild games.\r
-       */\r
-    switch (ics_getting_history) {\r
-      case H_FALSE:\r
-      case H_REQUESTED:\r
-       break;\r
-      case H_GOT_REQ_HEADER:\r
-      case H_GOT_UNREQ_HEADER:\r
-       /* This is the initial position of the current game */\r
-       gamenum = ics_gamenum;\r
-       moveNum = 0;            /* old ICS bug workaround */\r
-       if (to_play == 'B') {\r
-         startedFromSetupPosition = TRUE;\r
-         blackPlaysFirst = TRUE;\r
-         moveNum = 1;\r
-         if (forwardMostMove == 0) forwardMostMove = 1;\r
-         if (backwardMostMove == 0) backwardMostMove = 1;\r
-         if (currentMove == 0) currentMove = 1;\r
-       }\r
-       newGameMode = gameMode;\r
-       relation = RELATION_STARTING_POSITION; /* ICC needs this */\r
-       break;\r
-      case H_GOT_UNWANTED_HEADER:\r
-       /* This is an initial board that we don't want */\r
-       return;\r
-      case H_GETTING_MOVES:\r
-       /* Should not happen */\r
-       DisplayError(_("Error gathering move list: extra board"), 0);\r
-       ics_getting_history = H_FALSE;\r
-       return;\r
-    }\r
-    \r
-    /* Take action if this is the first board of a new game, or of a\r
-       different game than is currently being displayed.  */\r
-    if (gamenum != ics_gamenum || newGameMode != gameMode ||\r
-       relation == RELATION_ISOLATED_BOARD) {\r
-       \r
-       /* Forget the old game and get the history (if any) of the new one */\r
-       if (gameMode != BeginningOfGame) {\r
-         Reset(FALSE, TRUE);\r
-       }\r
-       newGame = TRUE;\r
-       if (appData.autoRaiseBoard) BoardToTop();\r
-       prevMove = -3;\r
-       if (gamenum == -1) {\r
-           newGameMode = IcsIdle;\r
-       } else if (moveNum > 0 && newGameMode != IcsIdle &&\r
-                  appData.getMoveList) {\r
-           /* Need to get game history */\r
-           ics_getting_history = H_REQUESTED;\r
-           sprintf(str, "%smoves %d\n", ics_prefix, gamenum);\r
-           SendToICS(str);\r
-       }\r
-       \r
-       /* Initially flip the board to have black on the bottom if playing\r
-          black or if the ICS flip flag is set, but let the user change\r
-          it with the Flip View button. */\r
-       flipView = appData.autoFlipView ? \r
-         (newGameMode == IcsPlayingBlack) || ics_flip :\r
-         appData.flipView;\r
-       \r
-       /* Done with values from previous mode; copy in new ones */\r
-       gameMode = newGameMode;\r
-       ModeHighlight();\r
-       ics_gamenum = gamenum;\r
-       if (gamenum == gs_gamenum) {\r
-           int klen = strlen(gs_kind);\r
-           if (gs_kind[klen - 1] == '.') gs_kind[klen - 1] = NULLCHAR;\r
-           sprintf(str, "ICS %s", gs_kind);\r
-           gameInfo.event = StrSave(str);\r
-       } else {\r
-           gameInfo.event = StrSave("ICS game");\r
-       }\r
-       gameInfo.site = StrSave(appData.icsHost);\r
-       gameInfo.date = PGNDate();\r
-       gameInfo.round = StrSave("-");\r
-       gameInfo.white = StrSave(white);\r
-       gameInfo.black = StrSave(black);\r
-       timeControl = basetime * 60 * 1000;\r
-        timeControl_2 = 0;\r
-       timeIncrement = increment * 1000;\r
-       movesPerSession = 0;\r
-       gameInfo.timeControl = TimeControlTagValue();\r
-        VariantSwitch(board, StringToVariant(gameInfo.event) );\r
-  if (appData.debugMode) {\r
-    fprintf(debugFP, "ParseBoard says variant = '%s'\n", gameInfo.event);\r
-    fprintf(debugFP, "recognized as %s\n", VariantName(gameInfo.variant));\r
-    setbuf(debugFP, NULL);\r
-  }\r
-\r
-        gameInfo.outOfBook = NULL;\r
-       \r
-       /* Do we have the ratings? */\r
-       if (strcmp(player1Name, white) == 0 &&\r
-           strcmp(player2Name, black) == 0) {\r
-           if (appData.debugMode)\r
-             fprintf(debugFP, "Remembered ratings: W %d, B %d\n",\r
-                     player1Rating, player2Rating);\r
-           gameInfo.whiteRating = player1Rating;\r
-           gameInfo.blackRating = player2Rating;\r
-       } else if (strcmp(player2Name, white) == 0 &&\r
-                  strcmp(player1Name, black) == 0) {\r
-           if (appData.debugMode)\r
-             fprintf(debugFP, "Remembered ratings: W %d, B %d\n",\r
-                     player2Rating, player1Rating);\r
-           gameInfo.whiteRating = player2Rating;\r
-           gameInfo.blackRating = player1Rating;\r
-       }\r
-       player1Name[0] = player2Name[0] = NULLCHAR;\r
-\r
-       /* Silence shouts if requested */\r
-       if (appData.quietPlay &&\r
-           (gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack)) {\r
-           SendToICS(ics_prefix);\r
-           SendToICS("set shout 0\n");\r
-       }\r
-    }\r
-    \r
-    /* Deal with midgame name changes */\r
-    if (!newGame) {\r
-       if (!gameInfo.white || strcmp(gameInfo.white, white) != 0) {\r
-           if (gameInfo.white) free(gameInfo.white);\r
-           gameInfo.white = StrSave(white);\r
-       }\r
-       if (!gameInfo.black || strcmp(gameInfo.black, black) != 0) {\r
-           if (gameInfo.black) free(gameInfo.black);\r
-           gameInfo.black = StrSave(black);\r
-       }\r
-    }\r
-    \r
-    /* Throw away game result if anything actually changes in examine mode */\r
-    if (gameMode == IcsExamining && !newGame) {\r
-       gameInfo.result = GameUnfinished;\r
-       if (gameInfo.resultDetails != NULL) {\r
-           free(gameInfo.resultDetails);\r
-           gameInfo.resultDetails = NULL;\r
-       }\r
-    }\r
-    \r
-    /* In pausing && IcsExamining mode, we ignore boards coming\r
-       in if they are in a different variation than we are. */\r
-    if (pauseExamInvalid) return;\r
-    if (pausing && gameMode == IcsExamining) {\r
-       if (moveNum <= pauseExamForwardMostMove) {\r
-           pauseExamInvalid = TRUE;\r
-           forwardMostMove = pauseExamForwardMostMove;\r
-           return;\r
-       }\r
-    }\r
-    \r
-  if (appData.debugMode) {\r
-    fprintf(debugFP, "load %dx%d board\n", files, ranks);\r
-  }\r
-    /* Parse the board */\r
-    for (k = 0; k < ranks; k++) {\r
-      for (j = 0; j < files; j++)\r
-        board[k][j+gameInfo.holdingsWidth] = CharToPiece(board_chars[(ranks-1-k)*(files+1) + j]);\r
-      if(gameInfo.holdingsWidth > 1) {\r
-           board[k][0] = board[k][BOARD_WIDTH-1] = EmptySquare;\r
-           board[k][1] = board[k][BOARD_WIDTH-2] = (ChessSquare) 0;;\r
-      }\r
-    }\r
-    CopyBoard(boards[moveNum], board);\r
-    if (moveNum == 0) {\r
-       startedFromSetupPosition =\r
-         !CompareBoards(board, initialPosition);\r
-        if(startedFromSetupPosition)\r
-            initialRulePlies = irrev_count; /* [HGM] 50-move counter offset */\r
-    }\r
-\r
-    /* [HGM] Set castling rights. Take the outermost Rooks,\r
-       to make it also work for FRC opening positions. Note that board12\r
-       is really defective for later FRC positions, as it has no way to\r
-       indicate which Rook can castle if they are on the same side of King.\r
-       For the initial position we grant rights to the outermost Rooks,\r
-       and remember thos rights, and we then copy them on positions\r
-       later in an FRC game. This means WB might not recognize castlings with\r
-       Rooks that have moved back to their original position as illegal,\r
-       but in ICS mode that is not its job anyway.\r
-    */\r
-    if(moveNum == 0 || gameInfo.variant != VariantFischeRandom)\r
-    { int i, j; ChessSquare wKing = WhiteKing, bKing = BlackKing;\r
-\r
-        for(i=BOARD_LEFT, j= -1; i<BOARD_RGHT; i++)\r
-            if(board[0][i] == WhiteRook) j = i;\r
-        initialRights[0] = castlingRights[moveNum][0] = (castle_ws == 0 && gameInfo.variant != VariantFischeRandom ? -1 : j);\r
-        for(i=BOARD_RGHT-1, j= -1; i>=BOARD_LEFT; i--)\r
-            if(board[0][i] == WhiteRook) j = i;\r
-        initialRights[1] = castlingRights[moveNum][1] = (castle_wl == 0 && gameInfo.variant != VariantFischeRandom ? -1 : j);\r
-        for(i=BOARD_LEFT, j= -1; i<BOARD_RGHT; i++)\r
-            if(board[BOARD_HEIGHT-1][i] == BlackRook) j = i;\r
-        initialRights[3] = castlingRights[moveNum][3] = (castle_bs == 0 && gameInfo.variant != VariantFischeRandom ? -1 : j);\r
-        for(i=BOARD_RGHT-1, j= -1; i>=BOARD_LEFT; i--)\r
-            if(board[BOARD_HEIGHT-1][i] == BlackRook) j = i;\r
-        initialRights[4] = castlingRights[moveNum][4] = (castle_bl == 0 && gameInfo.variant != VariantFischeRandom ? -1 : j);\r
-\r
-       if(gameInfo.variant == VariantKnightmate) { wKing = WhiteUnicorn; bKing = BlackUnicorn; }\r
-        for(k=BOARD_LEFT; k<BOARD_RGHT; k++)\r
-            if(board[0][k] == wKing) initialRights[2] = castlingRights[moveNum][2] = k;\r
-        for(k=BOARD_LEFT; k<BOARD_RGHT; k++)\r
-            if(board[BOARD_HEIGHT-1][k] == bKing)\r
-                initialRights[5] = castlingRights[moveNum][5] = k;\r
-    } else { int r;\r
-        r = castlingRights[moveNum][0] = initialRights[0];\r
-        if(board[0][r] != WhiteRook) castlingRights[moveNum][0] = -1;\r
-        r = castlingRights[moveNum][1] = initialRights[1];\r
-        if(board[0][r] != WhiteRook) castlingRights[moveNum][1] = -1;\r
-        r = castlingRights[moveNum][3] = initialRights[3];\r
-        if(board[BOARD_HEIGHT-1][r] != BlackRook) castlingRights[moveNum][3] = -1;\r
-        r = castlingRights[moveNum][4] = initialRights[4];\r
-        if(board[BOARD_HEIGHT-1][r] != BlackRook) castlingRights[moveNum][4] = -1;\r
-        /* wildcastle kludge: always assume King has rights */\r
-        r = castlingRights[moveNum][2] = initialRights[2];\r
-        r = castlingRights[moveNum][5] = initialRights[5];\r
-    }\r
-    /* [HGM] e.p. rights. Assume that ICS sends file number here? */\r
-    epStatus[moveNum] = double_push == -1 ? EP_NONE : double_push + BOARD_LEFT;\r
-\r
-    \r
-    if (ics_getting_history == H_GOT_REQ_HEADER ||\r
-       ics_getting_history == H_GOT_UNREQ_HEADER) {\r
-       /* This was an initial position from a move list, not\r
-          the current position */\r
-       return;\r
-    }\r
-    \r
-    /* Update currentMove and known move number limits */\r
-    newMove = newGame || moveNum > forwardMostMove;\r
-\r
-    /* [DM] If we found takebacks during icsEngineAnalyze try send to engine */\r
-    if (!newGame && appData.icsEngineAnalyze && moveNum < forwardMostMove) {\r
-        takeback = forwardMostMove - moveNum;\r
-        for (i = 0; i < takeback; i++) {\r
-             if (appData.debugMode) fprintf(debugFP, "take back move\n");\r
-             SendToProgram("undo\n", &first);\r
-        }\r
-    }\r
-\r
-    if (newGame) {\r
-       forwardMostMove = backwardMostMove = currentMove = moveNum;\r
-       if (gameMode == IcsExamining && moveNum == 0) {\r
-         /* Workaround for ICS limitation: we are not told the wild\r
-            type when starting to examine a game.  But if we ask for\r
-            the move list, the move list header will tell us */\r
-           ics_getting_history = H_REQUESTED;\r
-           sprintf(str, "%smoves %d\n", ics_prefix, gamenum);\r
-           SendToICS(str);\r
-       }\r
-    } else if (moveNum == forwardMostMove + 1 || moveNum == forwardMostMove\r
-              || (moveNum < forwardMostMove && moveNum >= backwardMostMove)) {\r
-       forwardMostMove = moveNum;\r
-       if (!pausing || currentMove > forwardMostMove)\r
-         currentMove = forwardMostMove;\r
-    } else {\r
-       /* New part of history that is not contiguous with old part */ \r
-       if (pausing && gameMode == IcsExamining) {\r
-           pauseExamInvalid = TRUE;\r
-           forwardMostMove = pauseExamForwardMostMove;\r
-           return;\r
-       }\r
-       forwardMostMove = backwardMostMove = currentMove = moveNum;\r
-       if (gameMode == IcsExamining && moveNum > 0 && appData.getMoveList) {\r
-           ics_getting_history = H_REQUESTED;\r
-           sprintf(str, "%smoves %d\n", ics_prefix, gamenum);\r
-           SendToICS(str);\r
-       }\r
-    }\r
-    \r
-    /* Update the clocks */\r
-    if (strchr(elapsed_time, '.')) {\r
-      /* Time is in ms */\r
-      timeRemaining[0][moveNum] = whiteTimeRemaining = white_time;\r
-      timeRemaining[1][moveNum] = blackTimeRemaining = black_time;\r
-    } else {\r
-      /* Time is in seconds */\r
-      timeRemaining[0][moveNum] = whiteTimeRemaining = white_time * 1000;\r
-      timeRemaining[1][moveNum] = blackTimeRemaining = black_time * 1000;\r
-    }\r
-      \r
-\r
-#if ZIPPY\r
-    if (appData.zippyPlay && newGame &&\r
-       gameMode != IcsObserving && gameMode != IcsIdle &&\r
-       gameMode != IcsExamining)\r
-      ZippyFirstBoard(moveNum, basetime, increment);\r
-#endif\r
-    \r
-    /* Put the move on the move list, first converting\r
-       to canonical algebraic form. */\r
-    if (moveNum > 0) {\r
-  if (appData.debugMode) {\r
-    if (appData.debugMode) { int f = forwardMostMove;\r
-        fprintf(debugFP, "parseboard %d, castling = %d %d %d %d %d %d\n", f,\r
-                castlingRights[f][0],castlingRights[f][1],castlingRights[f][2],castlingRights[f][3],castlingRights[f][4],castlingRights[f][5]);\r
-    }\r
-    fprintf(debugFP, "accepted move %s from ICS, parse it.\n", move_str);\r
-    fprintf(debugFP, "moveNum = %d\n", moveNum);\r
-    fprintf(debugFP, "board = %d-%d x %d\n", BOARD_LEFT, BOARD_RGHT, BOARD_HEIGHT);\r
-    setbuf(debugFP, NULL);\r
-  }\r
-       if (moveNum <= backwardMostMove) {\r
-           /* We don't know what the board looked like before\r
-              this move.  Punt. */\r
-           strcpy(parseList[moveNum - 1], move_str);\r
-           strcat(parseList[moveNum - 1], " ");\r
-           strcat(parseList[moveNum - 1], elapsed_time);\r
-           moveList[moveNum - 1][0] = NULLCHAR;\r
-       } else if (strcmp(move_str, "none") == 0) {\r
-           // [HGM] long SAN: swapped order; test for 'none' before parsing move\r
-           /* Again, we don't know what the board looked like;\r
-              this is really the start of the game. */\r
-           parseList[moveNum - 1][0] = NULLCHAR;\r
-           moveList[moveNum - 1][0] = NULLCHAR;\r
-           backwardMostMove = moveNum;\r
-           startedFromSetupPosition = TRUE;\r
-           fromX = fromY = toX = toY = -1;\r
-       } else {\r
-         // [HGM] long SAN: if legality-testing is off, disambiguation might not work or give wrong move. \r
-         //                 So we parse the long-algebraic move string in stead of the SAN move\r
-         int valid; char buf[MSG_SIZ], *prom;\r
-\r
-         // str looks something like "Q/a1-a2"; kill the slash\r
-         if(str[1] == '/') \r
-               sprintf(buf, "%c%s", str[0], str+2);\r
-         else  strcpy(buf, str); // might be castling\r
-         if((prom = strstr(move_str, "=")) && !strstr(buf, "=")) \r
-               strcat(buf, prom); // long move lacks promo specification!\r
-         if(!appData.testLegality) {\r
-               if(appData.debugMode) \r
-                       fprintf(debugFP, "replaced ICS move '%s' by '%s'\n", move_str, buf);\r
-               strcpy(move_str, buf);\r
-          }\r
-         valid = ParseOneMove(move_str, moveNum - 1, &moveType,\r
-                               &fromX, &fromY, &toX, &toY, &promoChar)\r
-              || ParseOneMove(buf, moveNum - 1, &moveType,\r
-                               &fromX, &fromY, &toX, &toY, &promoChar);\r
-         // end of long SAN patch\r
-         if (valid) {\r
-           (void) CoordsToAlgebraic(boards[moveNum - 1],\r
-                                    PosFlags(moveNum - 1), EP_UNKNOWN,\r
-                                    fromY, fromX, toY, toX, promoChar,\r
-                                    parseList[moveNum-1]);\r
-            switch (MateTest(boards[moveNum], PosFlags(moveNum), EP_UNKNOWN,\r
-                             castlingRights[moveNum]) ) {\r
-             case MT_NONE:\r
-             case MT_STALEMATE:\r
-             default:\r
-               break;\r
-             case MT_CHECK:\r
-                if(gameInfo.variant != VariantShogi)\r
-                    strcat(parseList[moveNum - 1], "+");\r
-               break;\r
-             case MT_CHECKMATE:\r
-               strcat(parseList[moveNum - 1], "#");\r
-               break;\r
-           }\r
-           strcat(parseList[moveNum - 1], " ");\r
-           strcat(parseList[moveNum - 1], elapsed_time);\r
-           /* currentMoveString is set as a side-effect of ParseOneMove */\r
-           strcpy(moveList[moveNum - 1], currentMoveString);\r
-           strcat(moveList[moveNum - 1], "\n");\r
-         } else {\r
-           /* Move from ICS was illegal!?  Punt. */\r
-  if (appData.debugMode) {\r
-    fprintf(debugFP, "Illegal move from ICS '%s'\n", move_str);\r
-    fprintf(debugFP, "board L=%d, R=%d, H=%d, holdings=%d\n", BOARD_LEFT, BOARD_RGHT, BOARD_HEIGHT, gameInfo.holdingsWidth);\r
-  }\r
-#if 0\r
-           if (appData.testLegality && appData.debugMode) {\r
-               sprintf(str, "Illegal move \"%s\" from ICS", move_str);\r
-               DisplayError(str, 0);\r
-           }\r
-#endif\r
-           strcpy(parseList[moveNum - 1], move_str);\r
-           strcat(parseList[moveNum - 1], " ");\r
-           strcat(parseList[moveNum - 1], elapsed_time);\r
-           moveList[moveNum - 1][0] = NULLCHAR;\r
-           fromX = fromY = toX = toY = -1;\r
-         }\r
-       }\r
-  if (appData.debugMode) {\r
-    fprintf(debugFP, "Move parsed to '%s'\n", parseList[moveNum - 1]);\r
-    setbuf(debugFP, NULL);\r
-  }\r
-\r
-#if ZIPPY\r
-       /* Send move to chess program (BEFORE animating it). */\r
-       if (appData.zippyPlay && !newGame && newMove && \r
-          (!appData.getMoveList || backwardMostMove == 0) && first.initDone) {\r
-\r
-           if ((gameMode == IcsPlayingWhite && WhiteOnMove(moveNum)) ||\r
-               (gameMode == IcsPlayingBlack && !WhiteOnMove(moveNum))) {\r
-               if (moveList[moveNum - 1][0] == NULLCHAR) {\r
-                   sprintf(str, _("Couldn't parse move \"%s\" from ICS"),\r
-                           move_str);\r
-                   DisplayError(str, 0);\r
-               } else {\r
-                   if (first.sendTime) {\r
-                       SendTimeRemaining(&first, gameMode == IcsPlayingWhite);\r
-                   }\r
-                   bookHit = SendMoveToBookUser(moveNum - 1, &first, FALSE); // [HGM] book\r
-                   if (firstMove && !bookHit) {\r
-                       firstMove = FALSE;\r
-                       if (first.useColors) {\r
-                         SendToProgram(gameMode == IcsPlayingWhite ?\r
-                                       "white\ngo\n" :\r
-                                       "black\ngo\n", &first);\r
-                       } else {\r
-                         SendToProgram("go\n", &first);\r
-                       }\r
-                       first.maybeThinking = TRUE;\r
-                   }\r
-               }\r
-           } else if (gameMode == IcsObserving || gameMode == IcsExamining) {\r
-             if (moveList[moveNum - 1][0] == NULLCHAR) {\r
-               sprintf(str, _("Couldn't parse move \"%s\" from ICS"), move_str);\r
-               DisplayError(str, 0);\r
-             } else {\r
-               if(gameInfo.variant == currentlyInitializedVariant) // [HGM] refrain sending moves engine can't understand!\r
-               SendMoveToProgram(moveNum - 1, &first);\r
-             }\r
-           }\r
-       }\r
-#endif\r
-    }\r
-\r
-    if (moveNum > 0 && !gotPremove) {\r
-       /* If move comes from a remote source, animate it.  If it\r
-          isn't remote, it will have already been animated. */\r
-       if (!pausing && !ics_user_moved && prevMove == moveNum - 1) {\r
-           AnimateMove(boards[moveNum - 1], fromX, fromY, toX, toY);\r
-       }\r
-       if (!pausing && appData.highlightLastMove) {\r
-           SetHighlights(fromX, fromY, toX, toY);\r
-       }\r
-    }\r
-    \r
-    /* Start the clocks */\r
-    whiteFlag = blackFlag = FALSE;\r
-    appData.clockMode = !(basetime == 0 && increment == 0);\r
-    if (ticking == 0) {\r
-      ics_clock_paused = TRUE;\r
-      StopClocks();\r
-    } else if (ticking == 1) {\r
-      ics_clock_paused = FALSE;\r
-    }\r
-    if (gameMode == IcsIdle ||\r
-       relation == RELATION_OBSERVING_STATIC ||\r
-       relation == RELATION_EXAMINING ||\r
-       ics_clock_paused)\r
-      DisplayBothClocks();\r
-    else\r
-      StartClocks();\r
-    \r
-    /* Display opponents and material strengths */\r
-    if (gameInfo.variant != VariantBughouse &&\r
-       gameInfo.variant != VariantCrazyhouse) {\r
-       if (tinyLayout || smallLayout) {\r
-           if(gameInfo.variant == VariantNormal)\r
-               sprintf(str, "%s(%d) %s(%d) {%d %d}", \r
-                   gameInfo.white, white_stren, gameInfo.black, black_stren,\r
-                   basetime, increment);\r
-           else\r
-               sprintf(str, "%s(%d) %s(%d) {%d %d w%d}", \r
-                   gameInfo.white, white_stren, gameInfo.black, black_stren,\r
-                   basetime, increment, (int) gameInfo.variant);\r
-       } else {\r
-           if(gameInfo.variant == VariantNormal)\r
-               sprintf(str, "%s (%d) vs. %s (%d) {%d %d}", \r
-                   gameInfo.white, white_stren, gameInfo.black, black_stren,\r
-                   basetime, increment);\r
-           else\r
-               sprintf(str, "%s (%d) vs. %s (%d) {%d %d %s}", \r
-                   gameInfo.white, white_stren, gameInfo.black, black_stren,\r
-                   basetime, increment, VariantName(gameInfo.variant));\r
-       }\r
-       DisplayTitle(str);\r
-  if (appData.debugMode) {\r
-    fprintf(debugFP, "Display title '%s, gameInfo.variant = %d'\n", str, gameInfo.variant);\r
-  }\r
-    }\r
-\r
-   \r
-    /* Display the board */\r
-    if (!pausing) {\r
-      \r
-      if (appData.premove)\r
-         if (!gotPremove || \r
-            ((gameMode == IcsPlayingWhite) && (WhiteOnMove(currentMove))) ||\r
-            ((gameMode == IcsPlayingBlack) && (!WhiteOnMove(currentMove))))\r
-             ClearPremoveHighlights();\r
-\r
-      DrawPosition(FALSE, boards[currentMove]);\r
-      DisplayMove(moveNum - 1);\r
-      if (appData.ringBellAfterMoves && !ics_user_moved)\r
-       RingBell();\r
-    }\r
-\r
-    HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove-1);\r
-#if ZIPPY\r
-    if(bookHit) { // [HGM] book: simulate book reply\r
-       static char bookMove[MSG_SIZ]; // a bit generous?\r
-\r
-       programStats.depth = programStats.nodes = programStats.time = \r
-       programStats.score = programStats.got_only_move = 0;\r
-       sprintf(programStats.movelist, "%s (xbook)", bookHit);\r
-\r
-       strcpy(bookMove, "move ");\r
-       strcat(bookMove, bookHit);\r
-       HandleMachineMove(bookMove, &first);\r
-    }\r
-#endif\r
-}\r
-\r
-void\r
-GetMoveListEvent()\r
-{\r
-    char buf[MSG_SIZ];\r
-    if (appData.icsActive && gameMode != IcsIdle && ics_gamenum > 0) {\r
-       ics_getting_history = H_REQUESTED;\r
-       sprintf(buf, "%smoves %d\n", ics_prefix, ics_gamenum);\r
-       SendToICS(buf);\r
-    }\r
-}\r
-\r
-void\r
-AnalysisPeriodicEvent(force)\r
-     int force;\r
-{\r
-    if (((programStats.ok_to_send == 0 || programStats.line_is_book)\r
-        && !force) || !appData.periodicUpdates)\r
-      return;\r
-\r
-    /* Send . command to Crafty to collect stats */\r
-    SendToProgram(".\n", &first);\r
-\r
-    /* Don't send another until we get a response (this makes\r
-       us stop sending to old Crafty's which don't understand\r
-       the "." command (sending illegal cmds resets node count & time,\r
-       which looks bad)) */\r
-    programStats.ok_to_send = 0;\r
-}\r
-\r
-void\r
-SendMoveToProgram(moveNum, cps)\r
-     int moveNum;\r
-     ChessProgramState *cps;\r
-{\r
-    char buf[MSG_SIZ];\r
-\r
-    if (cps->useUsermove) {\r
-      SendToProgram("usermove ", cps);\r
-    }\r
-    if (cps->useSAN) {\r
-      char *space;\r
-      if ((space = strchr(parseList[moveNum], ' ')) != NULL) {\r
-       int len = space - parseList[moveNum];\r
-       memcpy(buf, parseList[moveNum], len);\r
-       buf[len++] = '\n';\r
-       buf[len] = NULLCHAR;\r
-      } else {\r
-       sprintf(buf, "%s\n", parseList[moveNum]);\r
-      }\r
-      SendToProgram(buf, cps);\r
-    } else {\r
-      if(cps->alphaRank) { /* [HGM] shogi: temporarily convert to shogi coordinates before sending */\r
-       AlphaRank(moveList[moveNum], 4);\r
-       SendToProgram(moveList[moveNum], cps);\r
-       AlphaRank(moveList[moveNum], 4); // and back\r
-      } else\r
-      /* Added by Tord: Send castle moves in "O-O" in FRC games if required by\r
-       * the engine. It would be nice to have a better way to identify castle \r
-       * moves here. */\r
-      if((gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom)\r
-                                                                        && cps->useOOCastle) {\r
-        int fromX = moveList[moveNum][0] - AAA; \r
-        int fromY = moveList[moveNum][1] - ONE;\r
-        int toX = moveList[moveNum][2] - AAA; \r
-        int toY = moveList[moveNum][3] - ONE;\r
-        if((boards[moveNum][fromY][fromX] == WhiteKing \r
-            && boards[moveNum][toY][toX] == WhiteRook)\r
-           || (boards[moveNum][fromY][fromX] == BlackKing \r
-               && boards[moveNum][toY][toX] == BlackRook)) {\r
-         if(toX > fromX) SendToProgram("O-O\n", cps);\r
-         else SendToProgram("O-O-O\n", cps);\r
-       }\r
-       else SendToProgram(moveList[moveNum], cps);\r
-      }\r
-      else SendToProgram(moveList[moveNum], cps);\r
-      /* End of additions by Tord */\r
-    }\r
-\r
-    /* [HGM] setting up the opening has brought engine in force mode! */\r
-    /*       Send 'go' if we are in a mode where machine should play. */\r
-    if( (moveNum == 0 && setboardSpoiledMachineBlack && cps == &first) &&\r
-        (gameMode == TwoMachinesPlay   ||\r
-#ifdef ZIPPY\r
-         gameMode == IcsPlayingBlack     || gameMode == IcsPlayingWhite ||\r
-#endif\r
-         gameMode == MachinePlaysBlack || gameMode == MachinePlaysWhite) ) {\r
-        SendToProgram("go\n", cps);\r
-  if (appData.debugMode) {\r
-    fprintf(debugFP, "(extra)\n");\r
-  }\r
-    }\r
-    setboardSpoiledMachineBlack = 0;\r
-}\r
-\r
-void\r
-SendMoveToICS(moveType, fromX, fromY, toX, toY)\r
-     ChessMove moveType;\r
-     int fromX, fromY, toX, toY;\r
-{\r
-    char user_move[MSG_SIZ];\r
-\r
-    switch (moveType) {\r
-      default:\r
-       sprintf(user_move, _("say Internal error; bad moveType %d (%d,%d-%d,%d)"),\r
-               (int)moveType, fromX, fromY, toX, toY);\r
-       DisplayError(user_move + strlen("say "), 0);\r
-       break;\r
-      case WhiteKingSideCastle:\r
-      case BlackKingSideCastle:\r
-      case WhiteQueenSideCastleWild:\r
-      case BlackQueenSideCastleWild:\r
-      /* PUSH Fabien */\r
-      case WhiteHSideCastleFR:\r
-      case BlackHSideCastleFR:\r
-      /* POP Fabien */\r
-       sprintf(user_move, "o-o\n");\r
-       break;\r
-      case WhiteQueenSideCastle:\r
-      case BlackQueenSideCastle:\r
-      case WhiteKingSideCastleWild:\r
-      case BlackKingSideCastleWild:\r
-      /* PUSH Fabien */\r
-      case WhiteASideCastleFR:\r
-      case BlackASideCastleFR:\r
-      /* POP Fabien */\r
-       sprintf(user_move, "o-o-o\n");\r
-       break;\r
-      case WhitePromotionQueen:\r
-      case BlackPromotionQueen:\r
-      case WhitePromotionRook:\r
-      case BlackPromotionRook:\r
-      case WhitePromotionBishop:\r
-      case BlackPromotionBishop:\r
-      case WhitePromotionKnight:\r
-      case BlackPromotionKnight:\r
-      case WhitePromotionKing:\r
-      case BlackPromotionKing:\r
-      case WhitePromotionChancellor:\r
-      case BlackPromotionChancellor:\r
-      case WhitePromotionArchbishop:\r
-      case BlackPromotionArchbishop:\r
-        if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier)\r
-            sprintf(user_move, "%c%c%c%c=%c\n",\r
-                AAA + fromX, ONE + fromY, AAA + toX, ONE + toY,\r
-               PieceToChar(WhiteFerz));\r
-        else if(gameInfo.variant == VariantGreat)\r
-            sprintf(user_move, "%c%c%c%c=%c\n",\r
-                AAA + fromX, ONE + fromY, AAA + toX, ONE + toY,\r
-               PieceToChar(WhiteMan));\r
-        else\r
-            sprintf(user_move, "%c%c%c%c=%c\n",\r
-                AAA + fromX, ONE + fromY, AAA + toX, ONE + toY,\r
-               PieceToChar(PromoPiece(moveType)));\r
-       break;\r
-      case WhiteDrop:\r
-      case BlackDrop:\r
-       sprintf(user_move, "%c@%c%c\n",\r
-               ToUpper(PieceToChar((ChessSquare) fromX)),\r
-                AAA + toX, ONE + toY);\r
-       break;\r
-      case NormalMove:\r
-      case WhiteCapturesEnPassant:\r
-      case BlackCapturesEnPassant:\r
-      case IllegalMove:  /* could be a variant we don't quite understand */\r
-       sprintf(user_move, "%c%c%c%c\n",\r
-                AAA + fromX, ONE + fromY, AAA + toX, ONE + toY);\r
-       break;\r
-    }\r
-    SendToICS(user_move);\r
-}\r
-\r
-void\r
-CoordsToComputerAlgebraic(rf, ff, rt, ft, promoChar, move)\r
-     int rf, ff, rt, ft;\r
-     char promoChar;\r
-     char move[7];\r
-{\r
-    if (rf == DROP_RANK) {\r
-       sprintf(move, "%c@%c%c\n",\r
-                ToUpper(PieceToChar((ChessSquare) ff)), AAA + ft, ONE + rt);\r
-    } else {\r
-       if (promoChar == 'x' || promoChar == NULLCHAR) {\r
-           sprintf(move, "%c%c%c%c\n",\r
-                    AAA + ff, ONE + rf, AAA + ft, ONE + rt);\r
-       } else {\r
-           sprintf(move, "%c%c%c%c%c\n",\r
-                    AAA + ff, ONE + rf, AAA + ft, ONE + rt, promoChar);\r
-       }\r
-    }\r
-}\r
-\r
-void\r
-ProcessICSInitScript(f)\r
-     FILE *f;\r
-{\r
-    char buf[MSG_SIZ];\r
-\r
-    while (fgets(buf, MSG_SIZ, f)) {\r
-       SendToICSDelayed(buf,(long)appData.msLoginDelay);\r
-    }\r
-\r
-    fclose(f);\r
-}\r
-\r
-\r
-/* [HGM] Shogi move preprocessor: swap digits for letters, vice versa */\r
-void\r
-AlphaRank(char *move, int n)\r
-{\r
-    char *p = move, c; int x, y;\r
-\r
-    if (appData.debugMode) {\r
-        fprintf(debugFP, "alphaRank(%s,%d)\n", move, n);\r
-    }\r
-\r
-    if(move[1]=='*' && \r
-       move[2]>='0' && move[2]<='9' &&\r
-       move[3]>='a' && move[3]<='x'    ) {\r
-        move[1] = '@';\r
-        move[2] = BOARD_RGHT  -1 - (move[2]-'1') + AAA;\r
-        move[3] = BOARD_HEIGHT-1 - (move[3]-'a') + ONE;\r
-    } else\r
-    if(move[0]>='0' && move[0]<='9' &&\r
-       move[1]>='a' && move[1]<='x' &&\r
-       move[2]>='0' && move[2]<='9' &&\r
-       move[3]>='a' && move[3]<='x'    ) {\r
-        /* input move, Shogi -> normal */\r
-        move[0] = BOARD_RGHT  -1 - (move[0]-'1') + AAA;\r
-        move[1] = BOARD_HEIGHT-1 - (move[1]-'a') + ONE;\r
-        move[2] = BOARD_RGHT  -1 - (move[2]-'1') + AAA;\r
-        move[3] = BOARD_HEIGHT-1 - (move[3]-'a') + ONE;\r
-    } else\r
-    if(move[1]=='@' &&\r
-       move[3]>='0' && move[3]<='9' &&\r
-       move[2]>='a' && move[2]<='x'    ) {\r
-        move[1] = '*';\r
-        move[2] = BOARD_RGHT - 1 - (move[2]-AAA) + '1';\r
-        move[3] = BOARD_HEIGHT-1 - (move[3]-ONE) + 'a';\r
-    } else\r
-    if(\r
-       move[0]>='a' && move[0]<='x' &&\r
-       move[3]>='0' && move[3]<='9' &&\r
-       move[2]>='a' && move[2]<='x'    ) {\r
-         /* output move, normal -> Shogi */\r
-        move[0] = BOARD_RGHT - 1 - (move[0]-AAA) + '1';\r
-        move[1] = BOARD_HEIGHT-1 - (move[1]-ONE) + 'a';\r
-        move[2] = BOARD_RGHT - 1 - (move[2]-AAA) + '1';\r
-        move[3] = BOARD_HEIGHT-1 - (move[3]-ONE) + 'a';\r
-        if(move[4] == PieceToChar(BlackQueen)) move[4] = '+';\r
-    }\r
-    if (appData.debugMode) {\r
-        fprintf(debugFP, "   out = '%s'\n", move);\r
-    }\r
-}\r
-\r
-/* Parser for moves from gnuchess, ICS, or user typein box */\r
-Boolean\r
-ParseOneMove(move, moveNum, moveType, fromX, fromY, toX, toY, promoChar)\r
-     char *move;\r
-     int moveNum;\r
-     ChessMove *moveType;\r
-     int *fromX, *fromY, *toX, *toY;\r
-     char *promoChar;\r
-{       \r
-    if (appData.debugMode) {\r
-        fprintf(debugFP, "move to parse: %s\n", move);\r
-    }\r
-    *moveType = yylexstr(moveNum, move);\r
-\r
-    switch (*moveType) {\r
-      case WhitePromotionChancellor:\r
-      case BlackPromotionChancellor:\r
-      case WhitePromotionArchbishop:\r
-      case BlackPromotionArchbishop:\r
-      case WhitePromotionQueen:\r
-      case BlackPromotionQueen:\r
-      case WhitePromotionRook:\r
-      case BlackPromotionRook:\r
-      case WhitePromotionBishop:\r
-      case BlackPromotionBishop:\r
-      case WhitePromotionKnight:\r
-      case BlackPromotionKnight:\r
-      case WhitePromotionKing:\r
-      case BlackPromotionKing:\r
-      case NormalMove:\r
-      case WhiteCapturesEnPassant:\r
-      case BlackCapturesEnPassant:\r
-      case WhiteKingSideCastle:\r
-      case WhiteQueenSideCastle:\r
-      case BlackKingSideCastle:\r
-      case BlackQueenSideCastle:\r
-      case WhiteKingSideCastleWild:\r
-      case WhiteQueenSideCastleWild:\r
-      case BlackKingSideCastleWild:\r
-      case BlackQueenSideCastleWild:\r
-      /* Code added by Tord: */\r
-      case WhiteHSideCastleFR:\r
-      case WhiteASideCastleFR:\r
-      case BlackHSideCastleFR:\r
-      case BlackASideCastleFR:\r
-      /* End of code added by Tord */\r
-      case IllegalMove:                /* bug or odd chess variant */\r
-        *fromX = currentMoveString[0] - AAA;\r
-        *fromY = currentMoveString[1] - ONE;\r
-        *toX = currentMoveString[2] - AAA;\r
-        *toY = currentMoveString[3] - ONE;\r
-       *promoChar = currentMoveString[4];\r
-        if (*fromX < BOARD_LEFT || *fromX >= BOARD_RGHT || *fromY < 0 || *fromY >= BOARD_HEIGHT ||\r
-            *toX < BOARD_LEFT || *toX >= BOARD_RGHT || *toY < 0 || *toY >= BOARD_HEIGHT) {\r
-    if (appData.debugMode) {\r
-        fprintf(debugFP, "Off-board move (%d,%d)-(%d,%d)%c, type = %d\n", *fromX, *fromY, *toX, *toY, *promoChar, *moveType);\r
-    }\r
-           *fromX = *fromY = *toX = *toY = 0;\r
-           return FALSE;\r
-       }\r
-       if (appData.testLegality) {\r
-         return (*moveType != IllegalMove);\r
-       } else {\r
-         return !(fromX == fromY && toX == toY);\r
-       }\r
-\r
-      case WhiteDrop:\r
-      case BlackDrop:\r
-       *fromX = *moveType == WhiteDrop ?\r
-         (int) CharToPiece(ToUpper(currentMoveString[0])) :\r
-         (int) CharToPiece(ToLower(currentMoveString[0]));\r
-       *fromY = DROP_RANK;\r
-        *toX = currentMoveString[2] - AAA;\r
-        *toY = currentMoveString[3] - ONE;\r
-       *promoChar = NULLCHAR;\r
-       return TRUE;\r
-\r
-      case AmbiguousMove:\r
-      case ImpossibleMove:\r
-      case (ChessMove) 0:      /* end of file */\r
-      case ElapsedTime:\r
-      case Comment:\r
-      case PGNTag:\r
-      case NAG:\r
-      case WhiteWins:\r
-      case BlackWins:\r
-      case GameIsDrawn:\r
-      default:\r
-    if (appData.debugMode) {\r
-        fprintf(debugFP, "Impossible move %s, type = %d\n", currentMoveString, *moveType);\r
-    }\r
-       /* bug? */\r
-       *fromX = *fromY = *toX = *toY = 0;\r
-       *promoChar = NULLCHAR;\r
-       return FALSE;\r
-    }\r
-}\r
-\r
-/* [AS] FRC game initialization */\r
-static int FindEmptySquare( Board board, int n )\r
-{\r
-    int i = 0;\r
-\r
-    while( 1 ) {\r
-        while( board[0][i] != EmptySquare ) i++;\r
-        if( n == 0 )\r
-            break;\r
-        n--;\r
-        i++;\r
-    }\r
-\r
-    return i;\r
-}\r
-\r
-#if 0\r
-static void ShuffleFRC( Board board )\r
-{\r
-    int i;\r
-\r
-    srand( time(0) );\r
-    \r
-    for( i=0; i<8; i++ ) {\r
-        board[0][i] = EmptySquare;\r
-    }\r
-\r
-    board[0][(rand() % 4)*2  ] = WhiteBishop; /* On dark square */\r
-    board[0][(rand() % 4)*2+1] = WhiteBishop; /* On lite square */\r
-    board[0][FindEmptySquare(board, rand() % 6)] = WhiteQueen;\r
-    board[0][FindEmptySquare(board, rand() % 5)] = WhiteKnight;\r
-    board[0][FindEmptySquare(board, rand() % 4)] = WhiteKnight;\r
-    board[0][ i=FindEmptySquare(board, 0) ] = WhiteRook;\r
-    initialRights[1]  = initialRights[4]  =\r
-    castlingRights[0][1] = castlingRights[0][4] = i;\r
-    board[0][ i=FindEmptySquare(board, 0) ] = WhiteKing;\r
-    initialRights[2]  = initialRights[5]  =\r
-    castlingRights[0][2] = castlingRights[0][5] = i;\r
-    board[0][ i=FindEmptySquare(board, 0) ] = WhiteRook;\r
-    initialRights[0]  = initialRights[3]  =\r
-    castlingRights[0][0] = castlingRights[0][3] = i;\r
-\r
-    for( i=BOARD_LEFT; i<BOARD_RGHT; i++ ) {\r
-        board[BOARD_HEIGHT-1][i] = board[0][i] + BlackPawn - WhitePawn;\r
-    }\r
-}\r
-\r
-static unsigned char FRC_KnightTable[10] = {\r
-    0x00, 0x01, 0x02, 0x03, 0x11, 0x12, 0x13, 0x22, 0x23, 0x33\r
-};\r
-\r
-static void SetupFRC( Board board, int pos_index )\r
-{\r
-    int i;\r
-    unsigned char knights;\r
-\r
-    /* Bring the position index into a safe range (just in case...) */\r
-    if( pos_index < 0 ) pos_index = 0;\r
-\r
-    pos_index %= 960;\r
-\r
-    /* Clear the board */\r
-    for( i=0; i<8; i++ ) {\r
-        board[0][i] = EmptySquare;\r
-    }\r
-\r
-    /* Place bishops and queen */\r
-    board[0][ (pos_index % 4)*2 + 1 ] = WhiteBishop; /* On lite square */\r
-    pos_index /= 4;\r
-    \r
-    board[0][ (pos_index % 4)*2     ] = WhiteBishop; /* On dark square */\r
-    pos_index /= 4;\r
-\r
-    board[0][ FindEmptySquare(board, pos_index % 6) ] = WhiteQueen;\r
-    pos_index /= 6;\r
-\r
-    /* Place knigths */\r
-    knights = FRC_KnightTable[ pos_index ];\r
-\r
-    board[0][ FindEmptySquare(board, knights / 16) ] = WhiteKnight;\r
-    board[0][ FindEmptySquare(board, knights % 16) ] = WhiteKnight;\r
-\r
-    /* Place rooks and king */\r
-    board[0][ i=FindEmptySquare(board, 0) ] = WhiteRook;\r
-    initialRights[1]  = initialRights[4]  =\r
-    castlingRights[0][1] = castlingRights[0][4] = i;\r
-    board[0][ i=FindEmptySquare(board, 0) ] = WhiteKing;\r
-    initialRights[2]  = initialRights[5]  =\r
-    castlingRights[0][2] = castlingRights[0][5] = i;\r
-    board[0][ i=FindEmptySquare(board, 0) ] = WhiteRook;\r
-    initialRights[0]  = initialRights[3]  =\r
-    castlingRights[0][0] = castlingRights[0][3] = i;\r
-\r
-    /* Mirror piece placement for black */\r
-    for( i=BOARD_LEFT; i<BOARD_RGHT; i++ ) {\r
-        board[BOARD_HEIGHT-1][i] = board[0][i] + BlackPawn - WhitePawn;\r
-    }\r
-}\r
-#else\r
-// [HGM] shuffle: a more general way to suffle opening setups, applicable to arbitrry variants.\r
-// All positions will have equal probability, but the current method will not provide a unique\r
-// numbering scheme for arrays that contain 3 or more pieces of the same kind.\r
-#define DARK 1\r
-#define LITE 2\r
-#define ANY 3\r
-\r
-int squaresLeft[4];\r
-int piecesLeft[(int)BlackPawn];\r
-long long int seed, nrOfShuffles;\r
-\r
-void GetPositionNumber()\r
-{      // sets global variable seed\r
-       int i;\r
-\r
-       seed = appData.defaultFrcPosition;\r
-       if(seed < 0) { // randomize based on time for negative FRC position numbers\r
-               srandom(time(0)); \r
-               for(i=0; i<50; i++) seed += random();\r
-               seed = random() ^ random() >> 8 ^ random() << 8;\r
-               if(seed<0) seed = -seed;\r
-       }\r
-}\r
-\r
-int put(Board board, int pieceType, int rank, int n, int shade)\r
-// put the piece on the (n-1)-th empty squares of the given shade\r
-{\r
-       int i;\r
-\r
-       for(i=BOARD_LEFT; i<BOARD_RGHT; i++) {\r
-               if( ((i-BOARD_LEFT)&1)+1 & shade && board[rank][i] == EmptySquare && n-- == 0) {\r
-                       board[rank][i] = (ChessSquare) pieceType;\r
-                       squaresLeft[(i-BOARD_LEFT&1) + 1]--;\r
-                       squaresLeft[ANY]--;\r
-                       piecesLeft[pieceType]--; \r
-                       return i;\r
-               }\r
-       }\r
-        return -1;\r
-}\r
-\r
-\r
-void AddOnePiece(Board board, int pieceType, int rank, int shade)\r
-// calculate where the next piece goes, (any empty square), and put it there\r
-{\r
-       int i;\r
-\r
-        i = seed % squaresLeft[shade];\r
-       nrOfShuffles *= squaresLeft[shade];\r
-       seed /= squaresLeft[shade];\r
-        put(board, pieceType, rank, i, shade);\r
-}\r
-\r
-void AddTwoPieces(Board board, int pieceType, int rank)\r
-// calculate where the next 2 identical pieces go, (any empty square), and put it there\r
-{\r
-       int i, n=squaresLeft[ANY], j=n-1, k;\r
-\r
-       k = n*(n-1)/2; // nr of possibilities, not counting permutations\r
-        i = seed % k;  // pick one\r
-       nrOfShuffles *= k;\r
-       seed /= k;\r
-       while(i >= j) i -= j--;\r
-        j = n - 1 - j; i += j;\r
-        put(board, pieceType, rank, j, ANY);\r
-        put(board, pieceType, rank, i, ANY);\r
-}\r
-\r
-void SetUpShuffle(Board board, int number)\r
-{\r
-       int i, p, first=1;\r
-\r
-       GetPositionNumber(); nrOfShuffles = 1;\r
-\r
-       squaresLeft[DARK] = (BOARD_RGHT - BOARD_LEFT + 1)/2;\r
-       squaresLeft[ANY]  = BOARD_RGHT - BOARD_LEFT;\r
-       squaresLeft[LITE] = squaresLeft[ANY] - squaresLeft[DARK];\r
-\r
-       for(p = 0; p<=(int)WhiteKing; p++) piecesLeft[p] = 0;\r
-\r
-       for(i=BOARD_LEFT; i<BOARD_RGHT; i++) { // count pieces and clear board\r
-           p = (int) board[0][i];\r
-           if(p < (int) BlackPawn) piecesLeft[p] ++;\r
-           board[0][i] = EmptySquare;\r
-       }\r
-\r
-       if(PosFlags(0) & F_ALL_CASTLE_OK) {\r
-           // shuffles restricted to allow normal castling put KRR first\r
-           if(piecesLeft[(int)WhiteKing]) // King goes rightish of middle\r
-               put(board, WhiteKing, 0, (gameInfo.boardWidth+1)/2, ANY);\r
-           else if(piecesLeft[(int)WhiteUnicorn]) // in Knightmate Unicorn castles\r
-               put(board, WhiteUnicorn, 0, (gameInfo.boardWidth+1)/2, ANY);\r
-           if(piecesLeft[(int)WhiteRook]) // First supply a Rook for K-side castling\r
-               put(board, WhiteRook, 0, gameInfo.boardWidth-2, ANY);\r
-           if(piecesLeft[(int)WhiteRook]) // Then supply a Rook for Q-side castling\r
-               put(board, WhiteRook, 0, 0, ANY);\r
-           // in variants with super-numerary Kings and Rooks, we leave these for the shuffle\r
-       }\r
-\r
-       if((BOARD_RGHT-BOARD_LEFT & 1) == 0)\r
-           // only for even boards make effort to put pairs of colorbound pieces on opposite colors\r
-           for(p = (int) WhiteKing; p > (int) WhitePawn; p--) {\r
-               if(p != (int) WhiteBishop && p != (int) WhiteFerz && p != (int) WhiteAlfil) continue;\r
-               while(piecesLeft[p] >= 2) {\r
-                   AddOnePiece(board, p, 0, LITE);\r
-                   AddOnePiece(board, p, 0, DARK);\r
-               }\r
-               // Odd color-bound pieces are shuffled with the rest (to not run out of paired squares)\r
-           }\r
-\r
-       for(p = (int) WhiteKing - 2; p > (int) WhitePawn; p--) {\r
-           // Remaining pieces (non-colorbound, or odd color bound) can be put anywhere\r
-           // but we leave King and Rooks for last, to possibly obey FRC restriction\r
-           if(p == (int)WhiteRook) continue;\r
-           while(piecesLeft[p] >= 2) AddTwoPieces(board, p, 0); // add in pairs, for not counting permutations\r
-           if(piecesLeft[p]) AddOnePiece(board, p, 0, ANY);     // add the odd piece\r
-       }\r
-\r
-       // now everything is placed, except perhaps King (Unicorn) and Rooks\r
-\r
-       if(PosFlags(0) & F_FRC_TYPE_CASTLING) {\r
-           // Last King gets castling rights\r
-           while(piecesLeft[(int)WhiteUnicorn]) {\r
-               i = put(board, WhiteUnicorn, 0, piecesLeft[(int)WhiteRook]/2, ANY);\r
-               initialRights[2]  = initialRights[5]  = castlingRights[0][2] = castlingRights[0][5] = i;\r
-           }\r
-\r
-           while(piecesLeft[(int)WhiteKing]) {\r
-               i = put(board, WhiteKing, 0, piecesLeft[(int)WhiteRook]/2, ANY);\r
-               initialRights[2]  = initialRights[5]  = castlingRights[0][2] = castlingRights[0][5] = i;\r
-           }\r
-\r
-\r
-       } else {\r
-           while(piecesLeft[(int)WhiteKing])    AddOnePiece(board, WhiteKing, 0, ANY);\r
-           while(piecesLeft[(int)WhiteUnicorn]) AddOnePiece(board, WhiteUnicorn, 0, ANY);\r
-       }\r
-\r
-       // Only Rooks can be left; simply place them all\r
-       while(piecesLeft[(int)WhiteRook]) {\r
-               i = put(board, WhiteRook, 0, 0, ANY);\r
-               if(PosFlags(0) & F_FRC_TYPE_CASTLING) { // first and last Rook get FRC castling rights\r
-                       if(first) {\r
-                               first=0;\r
-                               initialRights[1]  = initialRights[4]  = castlingRights[0][1] = castlingRights[0][4] = i;\r
-                       }\r
-                       initialRights[0]  = initialRights[3]  = castlingRights[0][0] = castlingRights[0][3] = i;\r
-               }\r
-       }\r
-       for(i=BOARD_LEFT; i<BOARD_RGHT; i++) { // copy black from white\r
-           board[BOARD_HEIGHT-1][i] =  (int) board[0][i] < BlackPawn ? WHITE_TO_BLACK board[0][i] : EmptySquare;\r
-       }\r
-\r
-       if(number >= 0) appData.defaultFrcPosition %= nrOfShuffles; // normalize\r
-}\r
-\r
-#endif\r
-\r
-int SetCharTable( char *table, const char * map )\r
-/* [HGM] moved here from winboard.c because of its general usefulness */\r
-/*       Basically a safe strcpy that uses the last character as King */\r
-{\r
-    int result = FALSE; int NrPieces;\r
-\r
-    if( map != NULL && (NrPieces=strlen(map)) <= (int) EmptySquare \r
-                    && NrPieces >= 12 && !(NrPieces&1)) {\r
-        int i; /* [HGM] Accept even length from 12 to 34 */\r
-\r
-        for( i=0; i<(int) EmptySquare; i++ ) table[i] = '.';\r
-        for( i=0; i<NrPieces/2-1; i++ ) {\r
-            table[i] = map[i];\r
-            table[i + (int)BlackPawn - (int) WhitePawn] = map[i+NrPieces/2];\r
-        }\r
-        table[(int) WhiteKing]  = map[NrPieces/2-1];\r
-        table[(int) BlackKing]  = map[NrPieces-1];\r
-\r
-        result = TRUE;\r
-    }\r
-\r
-    return result;\r
-}\r
-\r
-void Prelude(Board board)\r
-{      // [HGM] superchess: random selection of exo-pieces\r
-       int i, j, k; ChessSquare p; \r
-       static ChessSquare exoPieces[4] = { WhiteAngel, WhiteMarshall, WhiteSilver, WhiteLance };\r
-\r
-       GetPositionNumber(); // use FRC position number\r
-\r
-       if(appData.pieceToCharTable != NULL) { // select pieces to participate from given char table\r
-           SetCharTable(pieceToChar, appData.pieceToCharTable);\r
-           for(i=(int)WhiteQueen+1, j=0; i<(int)WhiteKing && j<4; i++) \r
-               if(PieceToChar((ChessSquare)i) != '.') exoPieces[j++] = (ChessSquare) i;\r
-       }\r
-\r
-       j = seed%4;                 seed /= 4; \r
-       p = board[0][BOARD_LEFT+j];   board[0][BOARD_LEFT+j] = EmptySquare; k = PieceToNumber(p);\r
-       board[k][BOARD_WIDTH-1] = p;  board[k][BOARD_WIDTH-2]++;\r
-       board[BOARD_HEIGHT-1-k][0] = WHITE_TO_BLACK p;  board[BOARD_HEIGHT-1-k][1]++;\r
-       j = seed%3 + (seed%3 >= j); seed /= 3; \r
-       p = board[0][BOARD_LEFT+j];   board[0][BOARD_LEFT+j] = EmptySquare; k = PieceToNumber(p);\r
-       board[k][BOARD_WIDTH-1] = p;  board[k][BOARD_WIDTH-2]++;\r
-       board[BOARD_HEIGHT-1-k][0] = WHITE_TO_BLACK p;  board[BOARD_HEIGHT-1-k][1]++;\r
-       j = seed%3;                 seed /= 3; \r
-       p = board[0][BOARD_LEFT+j+5]; board[0][BOARD_LEFT+j+5] = EmptySquare; k = PieceToNumber(p);\r
-       board[k][BOARD_WIDTH-1] = p;  board[k][BOARD_WIDTH-2]++;\r
-       board[BOARD_HEIGHT-1-k][0] = WHITE_TO_BLACK p;  board[BOARD_HEIGHT-1-k][1]++;\r
-       j = seed%2 + (seed%2 >= j); seed /= 2; \r
-       p = board[0][BOARD_LEFT+j+5]; board[0][BOARD_LEFT+j+5] = EmptySquare; k = PieceToNumber(p);\r
-       board[k][BOARD_WIDTH-1] = p;  board[k][BOARD_WIDTH-2]++;\r
-       board[BOARD_HEIGHT-1-k][0] = WHITE_TO_BLACK p;  board[BOARD_HEIGHT-1-k][1]++;\r
-       j = seed%4; seed /= 4; put(board, exoPieces[3],    0, j, ANY);\r
-       j = seed%3; seed /= 3; put(board, exoPieces[2],   0, j, ANY);\r
-       j = seed%2; seed /= 2; put(board, exoPieces[1], 0, j, ANY);\r
-       put(board, exoPieces[0],    0, 0, ANY);\r
-       for(i=BOARD_LEFT; i<BOARD_RGHT; i++) board[BOARD_HEIGHT-1][i] = WHITE_TO_BLACK board[0][i];\r
-}\r
-\r
-void\r
-InitPosition(redraw)\r
-     int redraw;\r
-{\r
-    ChessSquare (* pieces)[BOARD_SIZE];\r
-    int i, j, pawnRow, overrule,\r
-    oldx = gameInfo.boardWidth,\r
-    oldy = gameInfo.boardHeight,\r
-    oldh = gameInfo.holdingsWidth,\r
-    oldv = gameInfo.variant;\r
-\r
-    currentMove = forwardMostMove = backwardMostMove = 0;\r
-    if(appData.icsActive) shuffleOpenings = FALSE; // [HGM] shuffle: in ICS mode, only shuffle on ICS request\r
-\r
-    /* [AS] Initialize pv info list [HGM] and game status */\r
-    {\r
-        for( i=0; i<MAX_MOVES; i++ ) {\r
-            pvInfoList[i].depth = 0;\r
-            epStatus[i]=EP_NONE;\r
-            for( j=0; j<BOARD_SIZE; j++ ) castlingRights[i][j] = -1;\r
-        }\r
-\r
-        initialRulePlies = 0; /* 50-move counter start */\r
-\r
-        castlingRank[0] = castlingRank[1] = castlingRank[2] = 0;\r
-        castlingRank[3] = castlingRank[4] = castlingRank[5] = BOARD_HEIGHT-1;\r
-    }\r
-\r
-    \r
-    /* [HGM] logic here is completely changed. In stead of full positions */\r
-    /* the initialized data only consist of the two backranks. The switch */\r
-    /* selects which one we will use, which is than copied to the Board   */\r
-    /* initialPosition, which for the rest is initialized by Pawns and    */\r
-    /* empty squares. This initial position is then copied to boards[0],  */\r
-    /* possibly after shuffling, so that it remains available.            */\r
-\r
-    gameInfo.holdingsWidth = 0; /* default board sizes */\r
-    gameInfo.boardWidth    = 8;\r
-    gameInfo.boardHeight   = 8;\r
-    gameInfo.holdingsSize  = 0;\r
-    nrCastlingRights = -1; /* [HGM] Kludge to indicate default should be used */\r
-    for(i=0; i<BOARD_SIZE; i++) initialRights[i] = -1; /* but no rights yet */\r
-    SetCharTable(pieceToChar, "PNBRQ...........Kpnbrq...........k"); \r
-\r
-    switch (gameInfo.variant) {\r
-    case VariantFischeRandom:\r
-      shuffleOpenings = TRUE;\r
-    default:\r
-      pieces = FIDEArray;\r
-      break;\r
-    case VariantShatranj:\r
-      pieces = ShatranjArray;\r
-      nrCastlingRights = 0;\r
-      SetCharTable(pieceToChar, "PN.R.QB...Kpn.r.qb...k"); \r
-      break;\r
-    case VariantTwoKings:\r
-      pieces = twoKingsArray;\r
-      nrCastlingRights = 8;                 /* add rights for second King */\r
-      castlingRights[0][6] = initialRights[2] = 5;\r
-      castlingRights[0][7] = initialRights[5] = 5;\r
-      castlingRank[6] = 0;\r
-      castlingRank[7] = BOARD_HEIGHT-1;\r
-      break;\r
-    case VariantCapaRandom:\r
-      shuffleOpenings = TRUE;\r
-    case VariantCapablanca:\r
-      pieces = CapablancaArray;\r
-      gameInfo.boardWidth = 10;\r
-      SetCharTable(pieceToChar, "PNBRQ..ACKpnbrq..ack"); \r
-      break;\r
-    case VariantGothic:\r
-      pieces = GothicArray;\r
-      gameInfo.boardWidth = 10;\r
-      SetCharTable(pieceToChar, "PNBRQ..ACKpnbrq..ack"); \r
-      break;\r
-    case VariantJanus:\r
-      pieces = JanusArray;\r
-      gameInfo.boardWidth = 10;\r
-      SetCharTable(pieceToChar, "PNBRQ..JKpnbrq..jk"); \r
-      nrCastlingRights = 6;\r
-        castlingRights[0][0] = initialRights[0] = BOARD_RGHT-1;\r
-        castlingRights[0][1] = initialRights[1] = BOARD_LEFT;\r
-        castlingRights[0][2] = initialRights[2] = BOARD_WIDTH-1>>1;\r
-        castlingRights[0][3] = initialRights[3] = BOARD_RGHT-1;\r
-        castlingRights[0][4] = initialRights[4] = BOARD_LEFT;\r
-        castlingRights[0][5] = initialRights[5] = BOARD_WIDTH-1>>1;\r
-      break;\r
-    case VariantFalcon:\r
-      pieces = FalconArray;\r
-      gameInfo.boardWidth = 10;\r
-      SetCharTable(pieceToChar, "PNBRQ.............FKpnbrq.............fk"); \r
-      break;\r
-    case VariantXiangqi:\r
-      pieces = XiangqiArray;\r
-      gameInfo.boardWidth  = 9;\r
-      gameInfo.boardHeight = 10;\r
-      nrCastlingRights = 0;\r
-      SetCharTable(pieceToChar, "PH.R.AE..K.C.ph.r.ae..k.c."); \r
-      break;\r
-    case VariantShogi:\r
-      pieces = ShogiArray;\r
-      gameInfo.boardWidth  = 9;\r
-      gameInfo.boardHeight = 9;\r
-      gameInfo.holdingsSize = 7;\r
-      nrCastlingRights = 0;\r
-      SetCharTable(pieceToChar, "PNBRLS...G.++++++Kpnbrls...g.++++++k"); \r
-      break;\r
-    case VariantCourier:\r
-      pieces = CourierArray;\r
-      gameInfo.boardWidth  = 12;\r
-      nrCastlingRights = 0;\r
-      SetCharTable(pieceToChar, "PNBR.FE..WMKpnbr.fe..wmk"); \r
-      for(i=0; i<BOARD_SIZE; i++) initialRights[i] = -1;\r
-      break;\r
-    case VariantKnightmate:\r
-      pieces = KnightmateArray;\r
-      SetCharTable(pieceToChar, "P.BRQ.....M.........K.p.brq.....m.........k."); \r
-      break;\r
-    case VariantFairy:\r
-      pieces = fairyArray;\r
-      SetCharTable(pieceToChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk"); \r
-      break;\r
-    case VariantGreat:\r
-      pieces = GreatArray;\r
-      gameInfo.boardWidth = 10;\r
-      SetCharTable(pieceToChar, "PN....E...S..HWGMKpn....e...s..hwgmk");\r
-      gameInfo.holdingsSize = 8;\r
-      break;\r
-    case VariantSuper:\r
-      pieces = FIDEArray;\r
-      SetCharTable(pieceToChar, "PNBRQ..SE.......V.AKpnbrq..se.......v.ak");\r
-      gameInfo.holdingsSize = 8;\r
-      startedFromSetupPosition = TRUE;\r
-      break;\r
-    case VariantCrazyhouse:\r
-    case VariantBughouse:\r
-      pieces = FIDEArray;\r
-      SetCharTable(pieceToChar, "PNBRQ.......~~~~Kpnbrq.......~~~~k"); \r
-      gameInfo.holdingsSize = 5;\r
-      break;\r
-    case VariantWildCastle:\r
-      pieces = FIDEArray;\r
-      /* !!?shuffle with kings guaranteed to be on d or e file */\r
-      shuffleOpenings = 1;\r
-      break;\r
-    case VariantNoCastle:\r
-      pieces = FIDEArray;\r
-      nrCastlingRights = 0;\r
-      for(i=0; i<BOARD_SIZE; i++) initialRights[i] = -1;\r
-      /* !!?unconstrained back-rank shuffle */\r
-      shuffleOpenings = 1;\r
-      break;\r
-    }\r
-\r
-    overrule = 0;\r
-    if(appData.NrFiles >= 0) {\r
-        if(gameInfo.boardWidth != appData.NrFiles) overrule++;\r
-        gameInfo.boardWidth = appData.NrFiles;\r
-    }\r
-    if(appData.NrRanks >= 0) {\r
-        gameInfo.boardHeight = appData.NrRanks;\r
-    }\r
-    if(appData.holdingsSize >= 0) {\r
-        i = appData.holdingsSize;\r
-        if(i > gameInfo.boardHeight) i = gameInfo.boardHeight;\r
-        gameInfo.holdingsSize = i;\r
-    }\r
-    if(gameInfo.holdingsSize) gameInfo.holdingsWidth = 2;\r
-    if(BOARD_HEIGHT > BOARD_SIZE || BOARD_WIDTH > BOARD_SIZE)\r
-        DisplayFatalError(_("Recompile to support this BOARD_SIZE!"), 0, 2);\r
-\r
-    pawnRow = gameInfo.boardHeight - 7; /* seems to work in all common variants */\r
-    if(pawnRow < 1) pawnRow = 1;\r
-\r
-    /* User pieceToChar list overrules defaults */\r
-    if(appData.pieceToCharTable != NULL)\r
-        SetCharTable(pieceToChar, appData.pieceToCharTable);\r
-\r
-    for( j=0; j<BOARD_WIDTH; j++ ) { ChessSquare s = EmptySquare;\r
-\r
-        if(j==BOARD_LEFT-1 || j==BOARD_RGHT)\r
-            s = (ChessSquare) 0; /* account holding counts in guard band */\r
-        for( i=0; i<BOARD_HEIGHT; i++ )\r
-            initialPosition[i][j] = s;\r
-\r
-        if(j < BOARD_LEFT || j >= BOARD_RGHT || overrule) continue;\r
-        initialPosition[0][j] = pieces[0][j-gameInfo.holdingsWidth];\r
-        initialPosition[pawnRow][j] = WhitePawn;\r
-        initialPosition[BOARD_HEIGHT-pawnRow-1][j] = BlackPawn;\r
-        if(gameInfo.variant == VariantXiangqi) {\r
-            if(j&1) {\r
-                initialPosition[pawnRow][j] = \r
-                initialPosition[BOARD_HEIGHT-pawnRow-1][j] = EmptySquare;\r
-                if(j==BOARD_LEFT+1 || j>=BOARD_RGHT-2) {\r
-                   initialPosition[2][j] = WhiteCannon;\r
-                   initialPosition[BOARD_HEIGHT-3][j] = BlackCannon;\r
-                }\r
-            }\r
-        }\r
-        initialPosition[BOARD_HEIGHT-1][j] =  pieces[1][j-gameInfo.holdingsWidth];\r
-    }\r
-    if( (gameInfo.variant == VariantShogi) && !overrule ) {\r
-\r
-            j=BOARD_LEFT+1;\r
-            initialPosition[1][j] = WhiteBishop;\r
-            initialPosition[BOARD_HEIGHT-2][j] = BlackRook;\r
-            j=BOARD_RGHT-2;\r
-            initialPosition[1][j] = WhiteRook;\r
-            initialPosition[BOARD_HEIGHT-2][j] = BlackBishop;\r
-    }\r
-\r
-    if( nrCastlingRights == -1) {\r
-        /* [HGM] Build normal castling rights (must be done after board sizing!) */\r
-        /*       This sets default castling rights from none to normal corners   */\r
-        /* Variants with other castling rights must set them themselves above    */\r
-        nrCastlingRights = 6;\r
-       \r
-        castlingRights[0][0] = initialRights[0] = BOARD_RGHT-1;\r
-        castlingRights[0][1] = initialRights[1] = BOARD_LEFT;\r
-        castlingRights[0][2] = initialRights[2] = BOARD_WIDTH>>1;\r
-        castlingRights[0][3] = initialRights[3] = BOARD_RGHT-1;\r
-        castlingRights[0][4] = initialRights[4] = BOARD_LEFT;\r
-        castlingRights[0][5] = initialRights[5] = BOARD_WIDTH>>1;\r
-     }\r
-\r
-     if(gameInfo.variant == VariantSuper) Prelude(initialPosition);\r
-     if(gameInfo.variant == VariantGreat) { // promotion commoners\r
-       initialPosition[PieceToNumber(WhiteMan)][BOARD_RGHT-1] = WhiteMan;\r
-       initialPosition[PieceToNumber(WhiteMan)][BOARD_RGHT-2] = 9;\r
-       initialPosition[BOARD_HEIGHT-1-PieceToNumber(WhiteMan)][0] = BlackMan;\r
-       initialPosition[BOARD_HEIGHT-1-PieceToNumber(WhiteMan)][1] = 9;\r
-     }\r
-#if 0\r
-    if(gameInfo.variant == VariantFischeRandom) {\r
-      if( appData.defaultFrcPosition < 0 ) {\r
-        ShuffleFRC( initialPosition );\r
-      }\r
-      else {\r
-        SetupFRC( initialPosition, appData.defaultFrcPosition );\r
-      }\r
-      startedFromSetupPosition = TRUE;\r
-    } else \r
-#else\r
-  if (appData.debugMode) {\r
-    fprintf(debugFP, "shuffleOpenings = %d\n", shuffleOpenings);\r
-  }\r
-    if(shuffleOpenings) {\r
-       SetUpShuffle(initialPosition, appData.defaultFrcPosition);\r
-       startedFromSetupPosition = TRUE;\r
-    }\r
-#endif\r
-    if(startedFromPositionFile) {\r
-      /* [HGM] loadPos: use PositionFile for every new game */\r
-      CopyBoard(initialPosition, filePosition);\r
-      for(i=0; i<nrCastlingRights; i++)\r
-          castlingRights[0][i] = initialRights[i] = fileRights[i];\r
-      startedFromSetupPosition = TRUE;\r
-    }\r
-\r
-    CopyBoard(boards[0], initialPosition);\r
-\r
-    if(oldx != gameInfo.boardWidth ||\r
-       oldy != gameInfo.boardHeight ||\r
-       oldh != gameInfo.holdingsWidth\r
-#ifdef GOTHIC\r
-       || oldv == VariantGothic ||        // For licensing popups\r
-       gameInfo.variant == VariantGothic\r
-#endif\r
-#ifdef FALCON\r
-       || oldv == VariantFalcon ||\r
-       gameInfo.variant == VariantFalcon\r
-#endif\r
-                                         )\r
-            InitDrawingSizes(-2 ,0);\r
-\r
-    if (redraw)\r
-      DrawPosition(TRUE, boards[currentMove]);\r
-}\r
-\r
-void\r
-SendBoard(cps, moveNum)\r
-     ChessProgramState *cps;\r
-     int moveNum;\r
-{\r
-    char message[MSG_SIZ];\r
-    \r
-    if (cps->useSetboard) {\r
-      char* fen = PositionToFEN(moveNum, cps->useFEN960);\r
-      sprintf(message, "setboard %s\n", fen);\r
-      SendToProgram(message, cps);\r
-      free(fen);\r
-\r
-    } else {\r
-      ChessSquare *bp;\r
-      int i, j;\r
-      /* Kludge to set black to move, avoiding the troublesome and now\r
-       * deprecated "black" command.\r
-       */\r
-      if (!WhiteOnMove(moveNum)) SendToProgram("a2a3\n", cps);\r
-\r
-      SendToProgram("edit\n", cps);\r
-      SendToProgram("#\n", cps);\r
-      for (i = BOARD_HEIGHT - 1; i >= 0; i--) {\r
-       bp = &boards[moveNum][i][BOARD_LEFT];\r
-        for (j = BOARD_LEFT; j < BOARD_RGHT; j++, bp++) {\r
-         if ((int) *bp < (int) BlackPawn) {\r
-           sprintf(message, "%c%c%c\n", PieceToChar(*bp), \r
-                    AAA + j, ONE + i);\r
-            if(message[0] == '+' || message[0] == '~') {\r
-                sprintf(message, "%c%c%c+\n",\r
-                        PieceToChar((ChessSquare)(DEMOTED *bp)),\r
-                        AAA + j, ONE + i);\r
-            }\r
-            if(cps->alphaRank) { /* [HGM] shogi: translate coords */\r
-                message[1] = BOARD_RGHT   - 1 - j + '1';\r
-                message[2] = BOARD_HEIGHT - 1 - i + 'a';\r
-            }\r
-           SendToProgram(message, cps);\r
-         }\r
-       }\r
-      }\r
-    \r
-      SendToProgram("c\n", cps);\r
-      for (i = BOARD_HEIGHT - 1; i >= 0; i--) {\r
-       bp = &boards[moveNum][i][BOARD_LEFT];\r
-        for (j = BOARD_LEFT; j < BOARD_RGHT; j++, bp++) {\r
-         if (((int) *bp != (int) EmptySquare)\r
-             && ((int) *bp >= (int) BlackPawn)) {\r
-           sprintf(message, "%c%c%c\n", ToUpper(PieceToChar(*bp)),\r
-                    AAA + j, ONE + i);\r
-            if(message[0] == '+' || message[0] == '~') {\r
-                sprintf(message, "%c%c%c+\n",\r
-                        PieceToChar((ChessSquare)(DEMOTED *bp)),\r
-                        AAA + j, ONE + i);\r
-            }\r
-            if(cps->alphaRank) { /* [HGM] shogi: translate coords */\r
-                message[1] = BOARD_RGHT   - 1 - j + '1';\r
-                message[2] = BOARD_HEIGHT - 1 - i + 'a';\r
-            }\r
-           SendToProgram(message, cps);\r
-         }\r
-       }\r
-      }\r
-    \r
-      SendToProgram(".\n", cps);\r
-    }\r
-    setboardSpoiledMachineBlack = 0; /* [HGM] assume WB 4.2.7 already solves this after sending setboard */\r
-}\r
-\r
-int\r
-IsPromotion(fromX, fromY, toX, toY)\r
-     int fromX, fromY, toX, toY;\r
-{\r
-    /* [HGM] add Shogi promotions */\r
-    int promotionZoneSize=1, highestPromotingPiece = (int)WhitePawn;\r
-    ChessSquare piece;\r
-\r
-    if(gameMode == EditPosition || gameInfo.variant == VariantXiangqi ||\r
-      !(fromX >=0 && fromY >= 0 && toX >= 0 && toY >= 0) ) return FALSE;\r
-   /* [HGM] Note to self: line above also weeds out drops */\r
-    piece = boards[currentMove][fromY][fromX];\r
-    if(gameInfo.variant == VariantShogi) {\r
-        promotionZoneSize = 3;\r
-        highestPromotingPiece = (int)WhiteKing;\r
-        /* [HGM] Should be Silver = Ferz, really, but legality testing is off,\r
-           and if in normal chess we then allow promotion to King, why not\r
-           allow promotion of other piece in Shogi?                         */\r
-    }\r
-    if((int)piece >= BlackPawn) {\r
-        if(toY >= promotionZoneSize && fromY >= promotionZoneSize)\r
-             return FALSE;\r
-        highestPromotingPiece = WHITE_TO_BLACK highestPromotingPiece;\r
-    } else {\r
-        if(  toY < BOARD_HEIGHT - promotionZoneSize &&\r
-           fromY < BOARD_HEIGHT - promotionZoneSize) return FALSE;\r
-    }\r
-    return ( (int)piece <= highestPromotingPiece );\r
-}\r
-\r
-int\r
-InPalace(row, column)\r
-     int row, column;\r
-{   /* [HGM] for Xiangqi */\r
-    if( (row < 3 || row > BOARD_HEIGHT-4) &&\r
-         column < (BOARD_WIDTH + 4)/2 &&\r
-         column > (BOARD_WIDTH - 5)/2 ) return TRUE;\r
-    return FALSE;\r
-}\r
-\r
-int\r
-PieceForSquare (x, y)\r
-     int x;\r
-     int y;\r
-{\r
-  if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT)\r
-     return -1;\r
-  else\r
-     return boards[currentMove][y][x];\r
-}\r
-\r
-int\r
-OKToStartUserMove(x, y)\r
-     int x, y;\r
-{\r
-    ChessSquare from_piece;\r
-    int white_piece;\r
-\r
-    if (matchMode) return FALSE;\r
-    if (gameMode == EditPosition) return TRUE;\r
-\r
-    if (x >= 0 && y >= 0)\r
-      from_piece = boards[currentMove][y][x];\r
-    else\r
-      from_piece = EmptySquare;\r
-\r
-    if (from_piece == EmptySquare) return FALSE;\r
-\r
-    white_piece = (int)from_piece >= (int)WhitePawn &&\r
-      (int)from_piece < (int)BlackPawn; /* [HGM] can be > King! */\r
-\r
-    switch (gameMode) {\r
-      case PlayFromGameFile:\r
-      case AnalyzeFile:\r
-      case TwoMachinesPlay:\r
-      case EndOfGame:\r
-       return FALSE;\r
-\r
-      case IcsObserving:\r
-      case IcsIdle:\r
-       return FALSE;\r
-\r
-      case MachinePlaysWhite:\r
-      case IcsPlayingBlack:\r
-       if (appData.zippyPlay) return FALSE;\r
-       if (white_piece) {\r
-           DisplayMoveError(_("You are playing Black"));\r
-           return FALSE;\r
-       }\r
-       break;\r
-\r
-      case MachinePlaysBlack:\r
-      case IcsPlayingWhite:\r
-       if (appData.zippyPlay) return FALSE;\r
-       if (!white_piece) {\r
-           DisplayMoveError(_("You are playing White"));\r
-           return FALSE;\r
-       }\r
-       break;\r
-\r
-      case EditGame:\r
-       if (!white_piece && WhiteOnMove(currentMove)) {\r
-           DisplayMoveError(_("It is White's turn"));\r
-           return FALSE;\r
-       }           \r
-       if (white_piece && !WhiteOnMove(currentMove)) {\r
-           DisplayMoveError(_("It is Black's turn"));\r
-           return FALSE;\r
-       }           \r
-       if (cmailMsgLoaded && (currentMove < cmailOldMove)) {\r
-           /* Editing correspondence game history */\r
-           /* Could disallow this or prompt for confirmation */\r
-           cmailOldMove = -1;\r
-       }\r
-       if (currentMove < forwardMostMove) {\r
-           /* Discarding moves */\r
-           /* Could prompt for confirmation here,\r
-              but I don't think that's such a good idea */\r
-           forwardMostMove = currentMove;\r
-       }\r
-       break;\r
-\r
-      case BeginningOfGame:\r
-       if (appData.icsActive) return FALSE;\r
-       if (!appData.noChessProgram) {\r
-           if (!white_piece) {\r
-               DisplayMoveError(_("You are playing White"));\r
-               return FALSE;\r
-           }\r
-       }\r
-       break;\r
-       \r
-      case Training:\r
-       if (!white_piece && WhiteOnMove(currentMove)) {\r
-           DisplayMoveError(_("It is White's turn"));\r
-           return FALSE;\r
-       }           \r
-       if (white_piece && !WhiteOnMove(currentMove)) {\r
-           DisplayMoveError(_("It is Black's turn"));\r
-           return FALSE;\r
-       }           \r
-       break;\r
-\r
-      default:\r
-      case IcsExamining:\r
-       break;\r
-    }\r
-    if (currentMove != forwardMostMove && gameMode != AnalyzeMode\r
-       && gameMode != AnalyzeFile && gameMode != Training) {\r
-       DisplayMoveError(_("Displayed position is not current"));\r
-       return FALSE;\r
-    }\r
-    return TRUE;\r
-}\r
-\r
-FILE *lastLoadGameFP = NULL, *lastLoadPositionFP = NULL;\r
-int lastLoadGameNumber = 0, lastLoadPositionNumber = 0;\r
-int lastLoadGameUseList = FALSE;\r
-char lastLoadGameTitle[MSG_SIZ], lastLoadPositionTitle[MSG_SIZ];\r
-ChessMove lastLoadGameStart = (ChessMove) 0;\r
-\r
-\r
-ChessMove\r
-UserMoveTest(fromX, fromY, toX, toY, promoChar)\r
-     int fromX, fromY, toX, toY;\r
-     int promoChar;\r
-{\r
-    ChessMove moveType;\r
-    ChessSquare pdown, pup;\r
-\r
-    if (fromX < 0 || fromY < 0) return ImpossibleMove;\r
-    if ((fromX == toX) && (fromY == toY)) {\r
-        return ImpossibleMove;\r
-    }\r
-\r
-    /* [HGM] suppress all moves into holdings area and guard band */\r
-    if( toX < BOARD_LEFT || toX >= BOARD_RGHT || toY < 0 )\r
-            return ImpossibleMove;\r
-\r
-    /* [HGM] <sameColor> moved to here from winboard.c */\r
-    /* note: this code seems to exist for filtering out some obviously illegal premoves */\r
-    pdown = boards[currentMove][fromY][fromX];\r
-    pup = boards[currentMove][toY][toX];\r
-    if (    gameMode != EditPosition &&\r
-            (WhitePawn <= pdown && pdown < BlackPawn &&\r
-             WhitePawn <= pup && pup < BlackPawn  ||\r
-             BlackPawn <= pdown && pdown < EmptySquare &&\r
-             BlackPawn <= pup && pup < EmptySquare \r
-            ) && !((gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) &&\r
-                    (pup == WhiteRook && pdown == WhiteKing && fromY == 0 && toY == 0||\r
-                     pup == BlackRook && pdown == BlackKing && fromY == BOARD_HEIGHT-1 && toY == BOARD_HEIGHT-1  ) \r
-        )           )\r
-         return ImpossibleMove;\r
-\r
-    /* Check if the user is playing in turn.  This is complicated because we\r
-       let the user "pick up" a piece before it is his turn.  So the piece he\r
-       tried to pick up may have been captured by the time he puts it down!\r
-       Therefore we use the color the user is supposed to be playing in this\r
-       test, not the color of the piece that is currently on the starting\r
-       square---except in EditGame mode, where the user is playing both\r
-       sides; fortunately there the capture race can't happen.  (It can\r
-       now happen in IcsExamining mode, but that's just too bad.  The user\r
-       will get a somewhat confusing message in that case.)\r
-       */\r
-\r
-    switch (gameMode) {\r
-      case PlayFromGameFile:\r
-      case AnalyzeFile:\r
-      case TwoMachinesPlay:\r
-      case EndOfGame:\r
-      case IcsObserving:\r
-      case IcsIdle:\r
-       /* We switched into a game mode where moves are not accepted,\r
-           perhaps while the mouse button was down. */\r
-        return ImpossibleMove;\r
-\r
-      case MachinePlaysWhite:\r
-       /* User is moving for Black */\r
-       if (WhiteOnMove(currentMove)) {\r
-           DisplayMoveError(_("It is White's turn"));\r
-            return ImpossibleMove;\r
-       }\r
-       break;\r
-\r
-      case MachinePlaysBlack:\r
-       /* User is moving for White */\r
-       if (!WhiteOnMove(currentMove)) {\r
-           DisplayMoveError(_("It is Black's turn"));\r
-            return ImpossibleMove;\r
-       }\r
-       break;\r
-\r
-      case EditGame:\r
-      case IcsExamining:\r
-      case BeginningOfGame:\r
-      case AnalyzeMode:\r
-      case Training:\r
-       if ((int) boards[currentMove][fromY][fromX] >= (int) BlackPawn &&\r
-            (int) boards[currentMove][fromY][fromX] < (int) EmptySquare) {\r
-           /* User is moving for Black */\r
-           if (WhiteOnMove(currentMove)) {\r
-               DisplayMoveError(_("It is White's turn"));\r
-                return ImpossibleMove;\r
-           }\r
-       } else {\r
-           /* User is moving for White */\r
-           if (!WhiteOnMove(currentMove)) {\r
-               DisplayMoveError(_("It is Black's turn"));\r
-                return ImpossibleMove;\r
-           }\r
-       }\r
-       break;\r
-\r
-      case IcsPlayingBlack:\r
-       /* User is moving for Black */\r
-       if (WhiteOnMove(currentMove)) {\r
-           if (!appData.premove) {\r
-               DisplayMoveError(_("It is White's turn"));\r
-           } else if (toX >= 0 && toY >= 0) {\r
-               premoveToX = toX;\r
-               premoveToY = toY;\r
-               premoveFromX = fromX;\r
-               premoveFromY = fromY;\r
-               premovePromoChar = promoChar;\r
-               gotPremove = 1;\r
-               if (appData.debugMode) \r
-                   fprintf(debugFP, "Got premove: fromX %d,"\r
-                           "fromY %d, toX %d, toY %d\n",\r
-                           fromX, fromY, toX, toY);\r
-           }\r
-            return ImpossibleMove;\r
-       }\r
-       break;\r
-\r
-      case IcsPlayingWhite:\r
-       /* User is moving for White */\r
-       if (!WhiteOnMove(currentMove)) {\r
-           if (!appData.premove) {\r
-               DisplayMoveError(_("It is Black's turn"));\r
-           } else if (toX >= 0 && toY >= 0) {\r
-               premoveToX = toX;\r
-               premoveToY = toY;\r
-               premoveFromX = fromX;\r
-               premoveFromY = fromY;\r
-               premovePromoChar = promoChar;\r
-               gotPremove = 1;\r
-               if (appData.debugMode) \r
-                   fprintf(debugFP, "Got premove: fromX %d,"\r
-                           "fromY %d, toX %d, toY %d\n",\r
-                           fromX, fromY, toX, toY);\r
-           }\r
-            return ImpossibleMove;\r
-       }\r
-       break;\r
-\r
-      default:\r
-       break;\r
-\r
-      case EditPosition:\r
-       /* EditPosition, empty square, or different color piece;\r
-          click-click move is possible */\r
-       if (toX == -2 || toY == -2) {\r
-           boards[0][fromY][fromX] = EmptySquare;\r
-           return AmbiguousMove;\r
-       } else if (toX >= 0 && toY >= 0) {\r
-           boards[0][toY][toX] = boards[0][fromY][fromX];\r
-           boards[0][fromY][fromX] = EmptySquare;\r
-           return AmbiguousMove;\r
-       }\r
-        return ImpossibleMove;\r
-    }\r
-\r
-    /* [HGM] If move started in holdings, it means a drop */\r
-    if( fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) { \r
-         if( pup != EmptySquare ) return ImpossibleMove;\r
-         if(appData.testLegality) {\r
-             /* it would be more logical if LegalityTest() also figured out\r
-              * which drops are legal. For now we forbid pawns on back rank.\r
-              * Shogi is on its own here...\r
-              */\r
-             if( (pdown == WhitePawn || pdown == BlackPawn) &&\r
-                 (toY == 0 || toY == BOARD_HEIGHT -1 ) )\r
-                 return(ImpossibleMove); /* no pawn drops on 1st/8th */\r
-         }\r
-         return WhiteDrop; /* Not needed to specify white or black yet */\r
-    }\r
-\r
-    userOfferedDraw = FALSE;\r
-       \r
-    /* [HGM] always test for legality, to get promotion info */\r
-    moveType = LegalityTest(boards[currentMove], PosFlags(currentMove),\r
-                          epStatus[currentMove], castlingRights[currentMove],\r
-                                         fromY, fromX, toY, toX, promoChar);\r
-\r
-    /* [HGM] but possibly ignore an IllegalMove result */\r
-    if (appData.testLegality) {\r
-       if (moveType == IllegalMove || moveType == ImpossibleMove) {\r
-           DisplayMoveError(_("Illegal move"));\r
-            return ImpossibleMove;\r
-       }\r
-    }\r
-if(appData.debugMode) fprintf(debugFP, "moveType 3 = %d, promochar = %x\n", moveType, promoChar);\r
-    return moveType;\r
-    /* [HGM] <popupFix> in stead of calling FinishMove directly, this\r
-       function is made into one that returns an OK move type if FinishMove\r
-       should be called. This to give the calling driver routine the\r
-       opportunity to finish the userMove input with a promotion popup,\r
-       without bothering the user with this for invalid or illegal moves */\r
-\r
-/*    FinishMove(moveType, fromX, fromY, toX, toY, promoChar); */\r
-}\r
-\r
-/* Common tail of UserMoveEvent and DropMenuEvent */\r
-int\r
-FinishMove(moveType, fromX, fromY, toX, toY, promoChar)\r
-     ChessMove moveType;\r
-     int fromX, fromY, toX, toY;\r
-     /*char*/int promoChar;\r
-{\r
-    char *bookHit = 0;\r
-if(appData.debugMode) fprintf(debugFP, "moveType 5 = %d, promochar = %x\n", moveType, promoChar);\r
-    if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) && promoChar != NULLCHAR) { \r
-       // [HGM] superchess: suppress promotions to non-available piece\r
-       int k = PieceToNumber(CharToPiece(ToUpper(promoChar)));\r
-       if(WhiteOnMove(currentMove)) {\r
-           if(!boards[currentMove][k][BOARD_WIDTH-2]) return 0;\r
-       } else {\r
-           if(!boards[currentMove][BOARD_HEIGHT-1-k][1]) return 0;\r
-       }\r
-    }\r
-\r
-    /* [HGM] <popupFix> kludge to avoid having to know the exact promotion\r
-       move type in caller when we know the move is a legal promotion */\r
-    if(moveType == NormalMove && promoChar)\r
-        moveType = PromoCharToMoveType(WhiteOnMove(currentMove), promoChar);\r
-if(appData.debugMode) fprintf(debugFP, "moveType 1 = %d, promochar = %x\n", moveType, promoChar);\r
-    /* [HGM] convert drag-and-drop piece drops to standard form */\r
-    if( fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) {\r
-         moveType = WhiteOnMove(currentMove) ? WhiteDrop : BlackDrop;\r
-         fromX = boards[currentMove][fromY][fromX];\r
-         fromY = DROP_RANK;\r
-    }\r
-\r
-    /* [HGM] <popupFix> The following if has been moved here from\r
-       UserMoveEvent(). Because it seemed to belon here (why not allow\r
-       piece drops in training games?), and because it can only be\r
-       performed after it is known to what we promote. */\r
-    if (gameMode == Training) {\r
-      /* compare the move played on the board to the next move in the\r
-       * game. If they match, display the move and the opponent's response. \r
-       * If they don't match, display an error message.\r
-       */\r
-      int saveAnimate;\r
-      Board testBoard;\r
-      CopyBoard(testBoard, boards[currentMove]);\r
-      ApplyMove(fromX, fromY, toX, toY, promoChar, testBoard);\r
-\r
-      if (CompareBoards(testBoard, boards[currentMove+1])) {\r
-       ForwardInner(currentMove+1);\r
-\r
-       /* Autoplay the opponent's response.\r
-        * if appData.animate was TRUE when Training mode was entered,\r
-        * the response will be animated.\r
-        */\r
-       saveAnimate = appData.animate;\r
-       appData.animate = animateTraining;\r
-       ForwardInner(currentMove+1);\r
-       appData.animate = saveAnimate;\r
-\r
-       /* check for the end of the game */\r
-       if (currentMove >= forwardMostMove) {\r
-         gameMode = PlayFromGameFile;\r
-         ModeHighlight();\r
-         SetTrainingModeOff();\r
-         DisplayInformation(_("End of game"));\r
-       }\r
-      } else {\r
-       DisplayError(_("Incorrect move"), 0);\r
-      }\r
-      return 1;\r
-    }\r
-\r
-  /* Ok, now we know that the move is good, so we can kill\r
-     the previous line in Analysis Mode */\r
-  if (gameMode == AnalyzeMode && currentMove < forwardMostMove) {\r
-    forwardMostMove = currentMove;\r
-  }\r
-\r
-  /* If we need the chess program but it's dead, restart it */\r
-  ResurrectChessProgram();\r
-\r
-  /* A user move restarts a paused game*/\r
-  if (pausing)\r
-    PauseEvent();\r
-\r
-  thinkOutput[0] = NULLCHAR;\r
-\r
-  MakeMove(fromX, fromY, toX, toY, promoChar); /*updates forwardMostMove*/\r
-\r
-    if((gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) \r
-               && promoChar != NULLCHAR && gameInfo.holdingsSize) { \r
-       // [HGM] superchess: take promotion piece out of holdings\r
-       int k = PieceToNumber(CharToPiece(ToUpper(promoChar)));\r
-       if(WhiteOnMove(forwardMostMove-1)) {\r
-           if(!--boards[forwardMostMove][k][BOARD_WIDTH-2])\r
-               boards[forwardMostMove][k][BOARD_WIDTH-1] = EmptySquare;\r
-       } else {\r
-           if(!--boards[forwardMostMove][BOARD_HEIGHT-1-k][1])\r
-               boards[forwardMostMove][BOARD_HEIGHT-1-k][0] = EmptySquare;\r
-       }\r
-    }\r
-\r
-  if (gameMode == BeginningOfGame) {\r
-    if (appData.noChessProgram) {\r
-      gameMode = EditGame;\r
-      SetGameInfo();\r
-    } else {\r
-      char buf[MSG_SIZ];\r
-      gameMode = MachinePlaysBlack;\r
-      StartClocks();\r
-      SetGameInfo();\r
-      sprintf(buf, "%s vs. %s", gameInfo.white, gameInfo.black);\r
-      DisplayTitle(buf);\r
-      if (first.sendName) {\r
-       sprintf(buf, "name %s\n", gameInfo.white);\r
-       SendToProgram(buf, &first);\r
-      }\r
-      StartClocks();\r
-    }\r
-    ModeHighlight();\r
-  }\r
-if(appData.debugMode) fprintf(debugFP, "moveType 2 = %d, promochar = %x\n", moveType, promoChar);\r
-  /* Relay move to ICS or chess engine */\r
-  if (appData.icsActive) {\r
-    if (gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||\r
-       gameMode == IcsExamining) {\r
-      SendMoveToICS(moveType, fromX, fromY, toX, toY);\r
-      ics_user_moved = 1;\r
-    }\r
-  } else {\r
-    if (first.sendTime && (gameMode == BeginningOfGame ||\r
-                          gameMode == MachinePlaysWhite ||\r
-                          gameMode == MachinePlaysBlack)) {\r
-      SendTimeRemaining(&first, gameMode != MachinePlaysBlack);\r
-    }\r
-    if (gameMode != EditGame && gameMode != PlayFromGameFile) {\r
-        // [HGM] book: if program might be playing, let it use book\r
-       bookHit = SendMoveToBookUser(forwardMostMove-1, &first, FALSE);\r
-       first.maybeThinking = TRUE;\r
-    } else SendMoveToProgram(forwardMostMove-1, &first);\r
-    if (currentMove == cmailOldMove + 1) {\r
-      cmailMoveType[lastLoadGameNumber - 1] = CMAIL_MOVE;\r
-    }\r
-  }\r
-\r
-  ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
-\r
-  switch (gameMode) {\r
-  case EditGame:\r
-    switch (MateTest(boards[currentMove], PosFlags(currentMove),\r
-                     EP_UNKNOWN, castlingRights[currentMove]) ) {\r
-    case MT_NONE:\r
-    case MT_CHECK:\r
-      break;\r
-    case MT_CHECKMATE:\r
-      if (WhiteOnMove(currentMove)) {\r
-       GameEnds(BlackWins, "Black mates", GE_PLAYER);\r
-      } else {\r
-       GameEnds(WhiteWins, "White mates", GE_PLAYER);\r
-      }\r
-      break;\r
-    case MT_STALEMATE:\r
-      GameEnds(GameIsDrawn, "Stalemate", GE_PLAYER);\r
-      break;\r
-    }\r
-    break;\r
-    \r
-  case MachinePlaysBlack:\r
-  case MachinePlaysWhite:\r
-    /* disable certain menu options while machine is thinking */\r
-    SetMachineThinkingEnables();\r
-    break;\r
-\r
-  default:\r
-    break;\r
-  }\r
-\r
-  if(bookHit) { // [HGM] book: simulate book reply\r
-       static char bookMove[MSG_SIZ]; // a bit generous?\r
-\r
-       programStats.depth = programStats.nodes = programStats.time = \r
-       programStats.score = programStats.got_only_move = 0;\r
-       sprintf(programStats.movelist, "%s (xbook)", bookHit);\r
-\r
-       strcpy(bookMove, "move ");\r
-       strcat(bookMove, bookHit);\r
-       HandleMachineMove(bookMove, &first);\r
-  }\r
-  return 1;\r
-}\r
-\r
-void\r
-UserMoveEvent(fromX, fromY, toX, toY, promoChar)\r
-     int fromX, fromY, toX, toY;\r
-     int promoChar;\r
-{\r
-    /* [HGM] This routine was added to allow calling of its two logical\r
-       parts from other modules in the old way. Before, UserMoveEvent()\r
-       automatically called FinishMove() if the move was OK, and returned\r
-       otherwise. I separated the two, in order to make it possible to\r
-       slip a promotion popup in between. But that it always needs two\r
-       calls, to the first part, (now called UserMoveTest() ), and to\r
-       FinishMove if the first part succeeded. Calls that do not need\r
-       to do anything in between, can call this routine the old way. \r
-    */\r
-    ChessMove moveType = UserMoveTest(fromX, fromY, toX, toY, promoChar);\r
-if(appData.debugMode) fprintf(debugFP, "moveType 4 = %d, promochar = %x\n", moveType, promoChar);\r
-    if(moveType != ImpossibleMove)\r
-        FinishMove(moveType, fromX, fromY, toX, toY, promoChar);\r
-}\r
-\r
-void SendProgramStatsToFrontend( ChessProgramState * cps, ChessProgramStats * cpstats )\r
-{\r
-    char * hint = lastHint;\r
-    FrontEndProgramStats stats;\r
-\r
-    stats.which = cps == &first ? 0 : 1;\r
-    stats.depth = cpstats->depth;\r
-    stats.nodes = cpstats->nodes;\r
-    stats.score = cpstats->score;\r
-    stats.time = cpstats->time;\r
-    stats.pv = cpstats->movelist;\r
-    stats.hint = lastHint;\r
-    stats.an_move_index = 0;\r
-    stats.an_move_count = 0;\r
-\r
-    if( gameMode == AnalyzeMode || gameMode == AnalyzeFile ) {\r
-        stats.hint = cpstats->move_name;\r
-        stats.an_move_index = cpstats->nr_moves - cpstats->moves_left;\r
-        stats.an_move_count = cpstats->nr_moves;\r
-    }\r
-\r
-    SetProgramStats( &stats );\r
-}\r
-\r
-char *SendMoveToBookUser(int moveNr, ChessProgramState *cps, int initial)\r
-{   // [HGM] book: this routine intercepts moves to simulate book replies\r
-    char *bookHit = NULL;\r
-\r
-    //first determine if the incoming move brings opponent into his book\r
-    if(appData.usePolyglotBook && (cps == &first ? !appData.firstHasOwnBookUCI : !appData.secondHasOwnBookUCI))\r
-       bookHit = ProbeBook(moveNr+1, appData.polyglotBook); // returns move\r
-    if(appData.debugMode) fprintf(debugFP, "book hit = %s\n", bookHit ? bookHit : "(NULL)");\r
-    if(bookHit != NULL && !cps->bookSuspend) {\r
-       // make sure opponent is not going to reply after receiving move to book position\r
-       SendToProgram("force\n", cps);\r
-       cps->bookSuspend = TRUE; // flag indicating it has to be restarted\r
-    }\r
-    if(!initial) SendMoveToProgram(moveNr, cps); // with hit on initial position there is no move\r
-    // now arrange restart after book miss\r
-    if(bookHit) {\r
-       // after a book hit we never send 'go', and the code after the call to this routine\r
-       // has '&& !bookHit' added to suppress potential sending there (based on 'firstMove').\r
-       char buf[MSG_SIZ];\r
-       if (cps->useUsermove) sprintf(buf, "usermove "); // sorry, no SAN yet :(\r
-       sprintf(buf, "%s\n", bookHit); // force book move into program supposed to play it\r
-       SendToProgram(buf, cps);\r
-       if(!initial) firstMove = FALSE; // normally we would clear the firstMove condition after return & sending 'go'\r
-    } else if(initial) { // 'go' was needed irrespective of firstMove, and it has to be done in this routine\r
-       SendToProgram("go\n", cps);\r
-       cps->bookSuspend = FALSE; // after a 'go' we are never suspended\r
-    } else { // 'go' might be sent based on 'firstMove' after this routine returns\r
-       if(cps->bookSuspend && !firstMove) // 'go' needed, and it will not be done after we return\r
-           SendToProgram("go\n", cps); \r
-       cps->bookSuspend = FALSE; // anyhow, we will not be suspended after a miss\r
-    }\r
-    return bookHit; // notify caller of hit, so it can take action to send move to opponent\r
-}\r
-\r
-char *savedMessage;\r
-ChessProgramState *savedState;\r
-void DeferredBookMove(void)\r
-{\r
-       if(savedState->lastPing != savedState->lastPong)\r
-                   ScheduleDelayedEvent(DeferredBookMove, 10);\r
-       else\r
-       HandleMachineMove(savedMessage, savedState);\r
-}\r
-\r
-void\r
-HandleMachineMove(message, cps)\r
-     char *message;\r
-     ChessProgramState *cps;\r
-{\r
-    char machineMove[MSG_SIZ], buf1[MSG_SIZ*10], buf2[MSG_SIZ];\r
-    char realname[MSG_SIZ];\r
-    int fromX, fromY, toX, toY;\r
-    ChessMove moveType;\r
-    char promoChar;\r
-    char *p;\r
-    int machineWhite;\r
-    char *bookHit;\r
-\r
-FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book hit\r
-    /*\r
-     * Kludge to ignore BEL characters\r
-     */\r
-    while (*message == '\007') message++;\r
-\r
-    /*\r
-     * [HGM] engine debug message: ignore lines starting with '#' character\r
-     */\r
-    if(cps->debug && *message == '#') return;\r
-\r
-    /*\r
-     * Look for book output\r
-     */\r
-    if (cps == &first && bookRequested) {\r
-       if (message[0] == '\t' || message[0] == ' ') {\r
-           /* Part of the book output is here; append it */\r
-           strcat(bookOutput, message);\r
-           strcat(bookOutput, "  \n");\r
-           return;\r
-       } else if (bookOutput[0] != NULLCHAR) {\r
-           /* All of book output has arrived; display it */\r
-           char *p = bookOutput;\r
-           while (*p != NULLCHAR) {\r
-               if (*p == '\t') *p = ' ';\r
-               p++;\r
-           }\r
-           DisplayInformation(bookOutput);\r
-           bookRequested = FALSE;\r
-           /* Fall through to parse the current output */\r
-       }\r
-    }\r
-\r
-    /*\r
-     * Look for machine move.\r
-     */\r
-    if ((sscanf(message, "%s %s %s", buf1, buf2, machineMove) == 3 && strcmp(buf2, "...") == 0) ||\r
-       (sscanf(message, "%s %s", buf1, machineMove) == 2 && strcmp(buf1, "move") == 0)) \r
-    {\r
-        /* This method is only useful on engines that support ping */\r
-        if (cps->lastPing != cps->lastPong) {\r
-         if (gameMode == BeginningOfGame) {\r
-           /* Extra move from before last new; ignore */\r
-           if (appData.debugMode) {\r
-               fprintf(debugFP, "Ignoring extra move from %s\n", cps->which);\r
-           }\r
-         } else {\r
-           if (appData.debugMode) {\r
-               fprintf(debugFP, "Undoing extra move from %s, gameMode %d\n",\r
-                       cps->which, gameMode);\r
-           }\r
-\r
-            SendToProgram("undo\n", cps);\r
-         }\r
-         return;\r
-       }\r
-\r
-       switch (gameMode) {\r
-         case BeginningOfGame:\r
-           /* Extra move from before last reset; ignore */\r
-           if (appData.debugMode) {\r
-               fprintf(debugFP, "Ignoring extra move from %s\n", cps->which);\r
-           }\r
-           return;\r
-\r
-         case EndOfGame:\r
-         case IcsIdle:\r
-         default:\r
-           /* Extra move after we tried to stop.  The mode test is\r
-              not a reliable way of detecting this problem, but it's\r
-              the best we can do on engines that don't support ping.\r
-           */\r
-           if (appData.debugMode) {\r
-               fprintf(debugFP, "Undoing extra move from %s, gameMode %d\n",\r
-                       cps->which, gameMode);\r
-           }\r
-           SendToProgram("undo\n", cps);\r
-           return;\r
-\r
-         case MachinePlaysWhite:\r
-         case IcsPlayingWhite:\r
-           machineWhite = TRUE;\r
-           break;\r
-\r
-         case MachinePlaysBlack:\r
-         case IcsPlayingBlack:\r
-           machineWhite = FALSE;\r
-           break;\r
-\r
-         case TwoMachinesPlay:\r
-           machineWhite = (cps->twoMachinesColor[0] == 'w');\r
-           break;\r
-       }\r
-       if (WhiteOnMove(forwardMostMove) != machineWhite) {\r
-           if (appData.debugMode) {\r
-               fprintf(debugFP,\r
-                       "Ignoring move out of turn by %s, gameMode %d"\r
-                       ", forwardMost %d\n",\r
-                       cps->which, gameMode, forwardMostMove);\r
-           }\r
-           return;\r
-       }\r
-\r
-    if (appData.debugMode) { int f = forwardMostMove;\r
-        fprintf(debugFP, "machine move %d, castling = %d %d %d %d %d %d\n", f,\r
-                castlingRights[f][0],castlingRights[f][1],castlingRights[f][2],castlingRights[f][3],castlingRights[f][4],castlingRights[f][5]);\r
-    }\r
-        if(cps->alphaRank) AlphaRank(machineMove, 4);\r
-        if (!ParseOneMove(machineMove, forwardMostMove, &moveType,\r
-                              &fromX, &fromY, &toX, &toY, &promoChar)) {\r
-           /* Machine move could not be parsed; ignore it. */\r
-            sprintf(buf1, _("Illegal move \"%s\" from %s machine"),\r
-                   machineMove, cps->which);\r
-           DisplayError(buf1, 0);\r
-            sprintf(buf1, "Xboard: Forfeit due to invalid move: %s (%c%c%c%c) res=%d%c",\r
-                    machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, 0);\r
-           if (gameMode == TwoMachinesPlay) {\r
-             GameEnds(machineWhite ? BlackWins : WhiteWins,\r
-                       buf1, GE_XBOARD);\r
-           }\r
-           return;\r
-       }\r
-\r
-        /* [HGM] Apparently legal, but so far only tested with EP_UNKOWN */\r
-        /* So we have to redo legality test with true e.p. status here,  */\r
-        /* to make sure an illegal e.p. capture does not slip through,   */\r
-        /* to cause a forfeit on a justified illegal-move complaint      */\r
-        /* of the opponent.                                              */\r
-        if( gameMode==TwoMachinesPlay && appData.testLegality\r
-            && fromY != DROP_RANK /* [HGM] temporary; should still add legality test for drops */\r
-                                                              ) {\r
-           ChessMove moveType;\r
-           moveType = LegalityTest(boards[forwardMostMove], PosFlags(forwardMostMove),\r
-                        epStatus[forwardMostMove], castlingRights[forwardMostMove],\r
-                             fromY, fromX, toY, toX, promoChar);\r
-           if (appData.debugMode) {\r
-                int i;\r
-                for(i=0; i< nrCastlingRights; i++) fprintf(debugFP, "(%d,%d) ",\r
-                    castlingRights[forwardMostMove][i], castlingRank[i]);\r
-                fprintf(debugFP, "castling rights\n");\r
-           }\r
-            if(moveType == IllegalMove) {\r
-                sprintf(buf1, "Xboard: Forfeit due to illegal move: %s (%c%c%c%c)%c",\r
-                        machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, 0);\r
-                GameEnds(machineWhite ? BlackWins : WhiteWins,\r
-                           buf1, GE_XBOARD);\r
-           } else if(gameInfo.variant != VariantFischeRandom && gameInfo.variant != VariantCapaRandom)\r
-           /* [HGM] Kludge to handle engines that send FRC-style castling\r
-              when they shouldn't (like TSCP-Gothic) */\r
-           switch(moveType) {\r
-             case WhiteASideCastleFR:\r
-             case BlackASideCastleFR:\r
-               toX+=2;\r
-               currentMoveString[2]++;\r
-               break;\r
-             case WhiteHSideCastleFR:\r
-             case BlackHSideCastleFR:\r
-               toX--;\r
-               currentMoveString[2]--;\r
-               break;\r
-           }\r
-        }\r
-       hintRequested = FALSE;\r
-       lastHint[0] = NULLCHAR;\r
-       bookRequested = FALSE;\r
-       /* Program may be pondering now */\r
-       cps->maybeThinking = TRUE;\r
-       if (cps->sendTime == 2) cps->sendTime = 1;\r
-       if (cps->offeredDraw) cps->offeredDraw--;\r
-\r
-#if ZIPPY\r
-       if ((gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack) &&\r
-           first.initDone) {\r
-         SendMoveToICS(moveType, fromX, fromY, toX, toY);\r
-         ics_user_moved = 1;\r
-         if(appData.autoKibitz && !appData.icsEngineAnalyze ) { /* [HGM] kibitz: send most-recent PV info to ICS */\r
-               char buf[3*MSG_SIZ];\r
-\r
-               sprintf(buf, "kibitz %d/%+.2f (%.2f sec, %.0f nodes, %1.0f knps) PV = %s\n",\r
-                       programStats.depth,\r
-                       programStats.score / 100.,\r
-                       programStats.time / 100.,\r
-                       (double) programStats.nodes,\r
-                       programStats.nodes / (10*abs(programStats.time) + 1.),\r
-                       programStats.movelist);\r
-               SendToICS(buf);\r
-         }\r
-       }\r
-#endif\r
-       /* currentMoveString is set as a side-effect of ParseOneMove */\r
-       strcpy(machineMove, currentMoveString);\r
-       strcat(machineMove, "\n");\r
-       strcpy(moveList[forwardMostMove], machineMove);\r
-\r
-        /* [AS] Save move info and clear stats for next move */\r
-        pvInfoList[ forwardMostMove ].score = programStats.score;\r
-        pvInfoList[ forwardMostMove ].depth = programStats.depth;\r
-        pvInfoList[ forwardMostMove ].time =  programStats.time; // [HGM] PGNtime: take time from engine stats\r
-        ClearProgramStats();\r
-        thinkOutput[0] = NULLCHAR;\r
-        hiddenThinkOutputState = 0;\r
-\r
-       MakeMove(fromX, fromY, toX, toY, promoChar);/*updates forwardMostMove*/\r
-\r
-        /* [AS] Adjudicate game if needed (note: remember that forwardMostMove now points past the last move) */\r
-        if( gameMode == TwoMachinesPlay && adjudicateLossThreshold != 0 && forwardMostMove >= adjudicateLossPlies ) {\r
-            int count = 0;\r
-\r
-            while( count < adjudicateLossPlies ) {\r
-                int score = pvInfoList[ forwardMostMove - count - 1 ].score;\r
-\r
-                if( count & 1 ) {\r
-                    score = -score; /* Flip score for winning side */\r
-                }\r
-\r
-                if( score > adjudicateLossThreshold ) {\r
-                    break;\r
-                }\r
-\r
-                count++;\r
-            }\r
-\r
-            if( count >= adjudicateLossPlies ) {\r
-               ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
-\r
-                GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, \r
-                    "Xboard adjudication", \r
-                    GE_XBOARD );\r
-\r
-                return;\r
-            }\r
-        }\r
-\r
-       if( gameMode == TwoMachinesPlay ) {\r
-         // [HGM] some adjudications useful with buggy engines\r
-            int k, count = 0, epFile = epStatus[forwardMostMove]; static int bare = 1;\r
-         if(gameInfo.holdingsSize == 0 || gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat) {\r
-\r
-            if(appData.testLegality)\r
-            // don't wait for engine to announce game end if we can judge ourselves\r
-            switch (MateTest(boards[forwardMostMove],\r
-                                 PosFlags(forwardMostMove), epFile,\r
-                                       castlingRights[forwardMostMove]) ) {\r
-             case MT_NONE:\r
-             case MT_CHECK:\r
-             default:\r
-               break;\r
-             case MT_STALEMATE:\r
-               epStatus[forwardMostMove] = EP_STALEMATE;\r
-                if(appData.checkMates) {\r
-                   SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
-                   ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
-                   GameEnds( GameIsDrawn, "Xboard adjudication: Stalemate",\r
-                       GE_XBOARD );\r
-               }\r
-               break;\r
-             case MT_CHECKMATE:\r
-               epStatus[forwardMostMove] = EP_CHECKMATE;\r
-                if(appData.checkMates) {\r
-                   SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
-                   ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
-                   GameEnds( WhiteOnMove(forwardMostMove) ? BlackWins : WhiteWins, \r
-                   "Xboard adjudication: Checkmate", \r
-                   GE_XBOARD );\r
-               }\r
-               break;\r
-           }\r
-\r
-           if( appData.testLegality )\r
-           {   /* [HGM] Some more adjudications for obstinate engines */\r
-               int NrWN=0, NrBN=0, NrWB=0, NrBB=0, NrWR=0, NrBR=0,\r
-                    NrWQ=0, NrBQ=0, NrW=0, bishopsColor = 0,\r
-                    NrPieces=0, NrPawns=0, PawnAdvance=0, i, j, k;\r
-               static int moveCount = 6;\r
-\r
-                /* First absolutely insufficient mating material. Count what is on board. */\r
-               for(i=0; i<BOARD_HEIGHT; i++) for(j=BOARD_LEFT; j<BOARD_RGHT; j++)\r
-               {   ChessSquare p = boards[forwardMostMove][i][j];\r
-                   int m=i;\r
-\r
-                   switch((int) p)\r
-                   {   /* count B,N,R and other of each side */\r
-                        case WhiteKnight:\r
-                             NrWN++; break;\r
-                        case WhiteBishop:\r
-                        case WhiteFerz:    // [HGM] shatranj: kludge to mke it work in shatranj\r
-                             bishopsColor |= 1 << ((i^j)&1);\r
-                             NrWB++; break;\r
-                        case BlackKnight:\r
-                             NrBN++; break;\r
-                        case BlackBishop:\r
-                        case BlackFerz:    // [HGM] shatranj: kludge to mke it work in shatranj\r
-                             bishopsColor |= 1 << ((i^j)&1);\r
-                             NrBB++; break;\r
-                        case WhiteRook:\r
-                             NrWR++; break;\r
-                        case BlackRook:\r
-                             NrBR++; break;\r
-                        case WhiteQueen:\r
-                             NrWQ++; break;\r
-                        case BlackQueen:\r
-                             NrBQ++; break;\r
-                        case EmptySquare: \r
-                             break;\r
-                        case BlackPawn:\r
-                             m = 7-i;\r
-                        case WhitePawn:\r
-                             PawnAdvance += m; NrPawns++;\r
-                    }\r
-                    NrPieces += (p != EmptySquare);\r
-                    NrW += ((int)p < (int)BlackPawn);\r
-                   if(gameInfo.variant == VariantXiangqi && \r
-                     (p == WhiteFerz || p == WhiteAlfil || p == BlackFerz || p == BlackAlfil)) {\r
-                       NrPieces--; // [HGM] XQ: do not count purely defensive pieces\r
-                        NrW -= ((int)p < (int)BlackPawn);\r
-                   }\r
-                }\r
-\r
-                if( NrPieces == 2 || gameInfo.variant != VariantXiangqi &&\r
-                       (NrPieces == 3 && NrWN+NrBN+NrWB+NrBB == 1 ||\r
-                        NrPieces == NrBB+NrWB+2 && bishopsColor != 3)) // [HGM] all Bishops (Ferz!) same color\r
-                {    /* KBK, KNK, KK of KBKB with like Bishops */\r
-\r
-                     /* always flag draws, for judging claims */\r
-                     epStatus[forwardMostMove] = EP_INSUF_DRAW;\r
-\r
-                     if(appData.materialDraws) {\r
-                         /* but only adjudicate them if adjudication enabled */\r
-                        SendToProgram("force\n", cps->other); // suppress reply\r
-                        SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see last move */\r
-                         ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
-                         GameEnds( GameIsDrawn, "Xboard adjudication: Insufficient mating material", GE_XBOARD );\r
-                         return;\r
-                     }\r
-                }\r
-\r
-               /* Shatranj baring rule */\r
-                if( gameInfo.variant == VariantShatranj && (NrW == 1 || NrPieces - NrW == 1) )\r
-                {    /* bare King */\r
-\r
-                     if(--bare < 0 && appData.checkMates) {\r
-                         /* but only adjudicate them if adjudication enabled */\r
-                        SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
-                         ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
-                         GameEnds( NrW > 1 ? WhiteWins : NrPieces - NrW > 1 ? BlackWins : GameIsDrawn, \r
-                                                       "Xboard adjudication: Bare king", GE_XBOARD );\r
-                         return;\r
-                     }\r
-                } else bare = 1;\r
-\r
-                /* Then some trivial draws (only adjudicate, cannot be claimed) */\r
-                if(NrPieces == 4 && \r
-                   (   NrWR == 1 && NrBR == 1 /* KRKR */\r
-                   || NrWQ==1 && NrBQ==1     /* KQKQ */\r
-                   || NrWN==2 || NrBN==2     /* KNNK */\r
-                   || NrWN+NrWB == 1 && NrBN+NrBB == 1 /* KBKN, KBKB, KNKN */\r
-                  ) ) {\r
-                     if(--moveCount < 0 && appData.trivialDraws)\r
-                     {    /* if the first 3 moves do not show a tactical win, declare draw */\r
-                         SendToProgram("force\n", cps->other); // suppress reply\r
-                         SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
-                          ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
-                          GameEnds( GameIsDrawn, "Xboard adjudication: Trivial draw", GE_XBOARD );\r
-                          return;\r
-                     }\r
-                } else moveCount = 6;\r
-           }\r
-         }\r
-#if 1\r
-    if (appData.debugMode) { int i;\r
-      fprintf(debugFP, "repeat test fmm=%d bmm=%d ep=%d, reps=%d\n",\r
-              forwardMostMove, backwardMostMove, epStatus[backwardMostMove],\r
-              appData.drawRepeats);\r
-      for( i=forwardMostMove; i>=backwardMostMove; i-- )\r
-           fprintf(debugFP, "%d ep=%d\n", i, epStatus[i]);\r
-\r
-    }\r
-#endif\r
-                /* Check for rep-draws */\r
-                count = 0;\r
-                for(k = forwardMostMove-2;\r
-                    k>=backwardMostMove && k>=forwardMostMove-100 &&\r
-                        epStatus[k] < EP_UNKNOWN &&\r
-                        epStatus[k+2] <= EP_NONE && epStatus[k+1] <= EP_NONE;\r
-                    k-=2)\r
-                {   int rights=0;\r
-#if 0\r
-    if (appData.debugMode) {\r
-      fprintf(debugFP, " loop\n");\r
-    }\r
-#endif\r
-                    if(CompareBoards(boards[k], boards[forwardMostMove])) {\r
-#if 0\r
-    if (appData.debugMode) {\r
-      fprintf(debugFP, "match\n");\r
-    }\r
-#endif\r
-                        /* compare castling rights */\r
-                        if( castlingRights[forwardMostMove][2] != castlingRights[k][2] &&\r
-                             (castlingRights[k][0] >= 0 || castlingRights[k][1] >= 0) )\r
-                                rights++; /* King lost rights, while rook still had them */\r
-                        if( castlingRights[forwardMostMove][2] >= 0 ) { /* king has rights */\r
-                            if( castlingRights[forwardMostMove][0] != castlingRights[k][0] ||\r
-                                castlingRights[forwardMostMove][1] != castlingRights[k][1] )\r
-                                   rights++; /* but at least one rook lost them */\r
-                        }\r
-                        if( castlingRights[forwardMostMove][5] != castlingRights[k][5] &&\r
-                             (castlingRights[k][3] >= 0 || castlingRights[k][4] >= 0) )\r
-                                rights++; \r
-                        if( castlingRights[forwardMostMove][5] >= 0 ) {\r
-                            if( castlingRights[forwardMostMove][3] != castlingRights[k][3] ||\r
-                                castlingRights[forwardMostMove][4] != castlingRights[k][4] )\r
-                                   rights++;\r
-                        }\r
-#if 0\r
-    if (appData.debugMode) {\r
-      for(i=0; i<nrCastlingRights; i++)\r
-      fprintf(debugFP, " (%d,%d)", castlingRights[forwardMostMove][i], castlingRights[k][i]);\r
-    }\r
-\r
-    if (appData.debugMode) {\r
-      fprintf(debugFP, " %d %d\n", rights, k);\r
-    }\r
-#endif\r
-                        if( rights == 0 && ++count > appData.drawRepeats-2\r
-                            && appData.drawRepeats > 1) {\r
-                             /* adjudicate after user-specified nr of repeats */\r
-                            SendToProgram("force\n", cps->other); // suppress reply\r
-                            SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
-                             ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
-                            if(gameInfo.variant == VariantXiangqi && appData.testLegality) { \r
-                               // [HGM] xiangqi: check for forbidden perpetuals\r
-                               int m, ourPerpetual = 1, hisPerpetual = 1;\r
-                               for(m=forwardMostMove; m>k; m-=2) {\r
-                                   if(MateTest(boards[m], PosFlags(m), \r
-                                                       EP_NONE, castlingRights[m]) != MT_CHECK)\r
-                                       ourPerpetual = 0; // the current mover did not always check\r
-                                   if(MateTest(boards[m-1], PosFlags(m-1), \r
-                                                       EP_NONE, castlingRights[m-1]) != MT_CHECK)\r
-                                       hisPerpetual = 0; // the opponent did not always check\r
-                               }\r
-                               if(ourPerpetual && !hisPerpetual) { // we are actively checking him: forfeit\r
-                                   GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, \r
-                                          "Xboard adjudication: perpetual checking", GE_XBOARD );\r
-                                   return;\r
-                               }\r
-                               if(hisPerpetual && !ourPerpetual)   // he is checking us, but did not repeat yet\r
-                                   break; // (or we would have caught him before). Abort repetition-checking loop.\r
-                               // if neither of us is checking all the time, or both are, it is draw\r
-                               // (illegal-chase forfeits not implemented yet!)\r
-                            }\r
-                             GameEnds( GameIsDrawn, "Xboard adjudication: repetition draw", GE_XBOARD );\r
-                             return;\r
-                        }\r
-                        if( rights == 0 && count > 1 ) /* occurred 2 or more times before */\r
-                             epStatus[forwardMostMove] = EP_REP_DRAW;\r
-                    }\r
-                }\r
-\r
-                /* Now we test for 50-move draws. Determine ply count */\r
-                count = forwardMostMove;\r
-                /* look for last irreversble move */\r
-                while( epStatus[count] <= EP_NONE && count > backwardMostMove )\r
-                    count--;\r
-                /* if we hit starting position, add initial plies */\r
-                if( count == backwardMostMove )\r
-                    count -= initialRulePlies;\r
-                count = forwardMostMove - count; \r
-                if( count >= 100)\r
-                         epStatus[forwardMostMove] = EP_RULE_DRAW;\r
-                         /* this is used to judge if draw claims are legal */\r
-                if(appData.ruleMoves > 0 && count >= 2*appData.ruleMoves) {\r
-                        SendToProgram("force\n", cps->other); // suppress reply\r
-                        SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
-                         ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
-                         GameEnds( GameIsDrawn, "Xboard adjudication: 50-move rule", GE_XBOARD );\r
-                         return;\r
-                }\r
-\r
-                /* if draw offer is pending, treat it as a draw claim\r
-                 * when draw condition present, to allow engines a way to\r
-                 * claim draws before making their move to avoid a race\r
-                 * condition occurring after their move\r
-                 */\r
-                if( cps->other->offeredDraw || cps->offeredDraw ) {\r
-                         char *p = NULL;\r
-                         if(epStatus[forwardMostMove] == EP_RULE_DRAW)\r
-                             p = "Draw claim: 50-move rule";\r
-                         if(epStatus[forwardMostMove] == EP_REP_DRAW)\r
-                             p = "Draw claim: 3-fold repetition";\r
-                         if(epStatus[forwardMostMove] == EP_INSUF_DRAW)\r
-                             p = "Draw claim: insufficient mating material";\r
-                         if( p != NULL ) {\r
-                            SendToProgram("force\n", cps->other); // suppress reply\r
-                            SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
-                             GameEnds( GameIsDrawn, p, GE_XBOARD );\r
-                             ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
-                             return;\r
-                         }\r
-                }\r
-\r
-\r
-               if( appData.adjudicateDrawMoves > 0 && forwardMostMove > (2*appData.adjudicateDrawMoves) ) {\r
-                   SendToProgram("force\n", cps->other); // suppress reply\r
-                   SendMoveToProgram(forwardMostMove-1, cps->other); /* make sure opponent gets to see move */\r
-                   ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
-\r
-                   GameEnds( GameIsDrawn, "Xboard adjudication: long game", GE_XBOARD );\r
-\r
-                   return;\r
-               }\r
-        }\r
-\r
-       bookHit = NULL;\r
-       if (gameMode == TwoMachinesPlay) {\r
-            /* [HGM] relaying draw offers moved to after reception of move */\r
-            /* and interpreting offer as claim if it brings draw condition */\r
-            if (cps->offeredDraw == 1 && cps->other->sendDrawOffers) {\r
-                SendToProgram("draw\n", cps->other);\r
-            }\r
-           if (cps->other->sendTime) {\r
-               SendTimeRemaining(cps->other,\r
-                                 cps->other->twoMachinesColor[0] == 'w');\r
-           }\r
-           bookHit = SendMoveToBookUser(forwardMostMove-1, cps->other, FALSE);\r
-           if (firstMove && !bookHit) {\r
-               firstMove = FALSE;\r
-               if (cps->other->useColors) {\r
-                 SendToProgram(cps->other->twoMachinesColor, cps->other);\r
-               }\r
-               SendToProgram("go\n", cps->other);\r
-           }\r
-           cps->other->maybeThinking = TRUE;\r
-       }\r
-\r
-       ShowMove(fromX, fromY, toX, toY); /*updates currentMove*/\r
-       \r
-        if (!pausing && appData.ringBellAfterMoves) {\r
-           RingBell();\r
-       }\r
-\r
-       /* \r
-        * Reenable menu items that were disabled while\r
-        * machine was thinking\r
-        */\r
-       if (gameMode != TwoMachinesPlay)\r
-           SetUserThinkingEnables();\r
-\r
-       // [HGM] book: after book hit opponent has received move and is now in force mode\r
-       // force the book reply into it, and then fake that it outputted this move by jumping\r
-       // back to the beginning of HandleMachineMove, with cps toggled and message set to this move\r
-       if(bookHit) {\r
-               static char bookMove[MSG_SIZ]; // a bit generous?\r
-\r
-               strcpy(bookMove, "move ");\r
-               strcat(bookMove, bookHit);\r
-               message = bookMove;\r
-               cps = cps->other;\r
-               programStats.depth = programStats.nodes = programStats.time = \r
-               programStats.score = programStats.got_only_move = 0;\r
-               sprintf(programStats.movelist, "%s (xbook)", bookHit);\r
-\r
-               if(cps->lastPing != cps->lastPong) {\r
-                   savedMessage = message; // args for deferred call\r
-                   savedState = cps;\r
-                   ScheduleDelayedEvent(DeferredBookMove, 10);\r
-                   return;\r
-               }\r
-               goto FakeBookMove;\r
-       }\r
-\r
-       return;\r
-    }\r
-\r
-    /* Set special modes for chess engines.  Later something general\r
-     *  could be added here; for now there is just one kludge feature,\r
-     *  needed because Crafty 15.10 and earlier don't ignore SIGINT\r
-     *  when "xboard" is given as an interactive command.\r
-     */\r
-    if (strncmp(message, "kibitz Hello from Crafty", 24) == 0) {\r
-       cps->useSigint = FALSE;\r
-       cps->useSigterm = FALSE;\r
-    }\r
-\r
-    /* [HGM] Allow engine to set up a position. Don't ask me why one would\r
-     * want this, I was asked to put it in, and obliged.\r
-     */\r
-    if (!strncmp(message, "setboard ", 9)) {\r
-        Board initial_position; int i;\r
-\r
-        GameEnds(GameUnfinished, "Engine aborts game", GE_XBOARD);\r
-\r
-        if (!ParseFEN(initial_position, &blackPlaysFirst, message + 9)) {\r
-            DisplayError(_("Bad FEN received from engine"), 0);\r
-            return ;\r
-        } else {\r
-           Reset(FALSE, FALSE);\r
-           CopyBoard(boards[0], initial_position);\r
-           initialRulePlies = FENrulePlies;\r
-           epStatus[0] = FENepStatus;\r
-           for( i=0; i<nrCastlingRights; i++ )\r
-                castlingRights[0][i] = FENcastlingRights[i];\r
-           if(blackPlaysFirst) gameMode = MachinePlaysWhite;\r
-           else gameMode = MachinePlaysBlack;                 \r
-           DrawPosition(FALSE, boards[currentMove]);\r
-        }\r
-       return;\r
-    }\r
-\r
-    /*\r
-     * Look for communication commands\r
-     */\r
-    if (!strncmp(message, "telluser ", 9)) {\r
-       DisplayNote(message + 9);\r
-       return;\r
-    }\r
-    if (!strncmp(message, "tellusererror ", 14)) {\r
-       DisplayError(message + 14, 0);\r
-       return;\r
-    }\r
-    if (!strncmp(message, "tellopponent ", 13)) {\r
-      if (appData.icsActive) {\r
-       if (loggedOn) {\r
-         sprintf(buf1, "%ssay %s\n", ics_prefix, message + 13);\r
-         SendToICS(buf1);\r
-       }\r
-      } else {\r
-       DisplayNote(message + 13);\r
-      }\r
-      return;\r
-    }\r
-    if (!strncmp(message, "tellothers ", 11)) {\r
-      if (appData.icsActive) {\r
-       if (loggedOn) {\r
-         sprintf(buf1, "%swhisper %s\n", ics_prefix, message + 11);\r
-         SendToICS(buf1);\r
-       }\r
-      }\r
-      return;\r
-    }\r
-    if (!strncmp(message, "tellall ", 8)) {\r
-      if (appData.icsActive) {\r
-       if (loggedOn) {\r
-         sprintf(buf1, "%skibitz %s\n", ics_prefix, message + 8);\r
-         SendToICS(buf1);\r
-       }\r
-      } else {\r
-       DisplayNote(message + 8);\r
-      }\r
-      return;\r
-    }\r
-    if (strncmp(message, "warning", 7) == 0) {\r
-       /* Undocumented feature, use tellusererror in new code */\r
-       DisplayError(message, 0);\r
-       return;\r
-    }\r
-    if (sscanf(message, "askuser %s %[^\n]", buf1, buf2) == 2) {\r
-       strcpy(realname, cps->tidy);\r
-       strcat(realname, " query");\r
-       AskQuestion(realname, buf2, buf1, cps->pr);\r
-       return;\r
-    }\r
-    /* Commands from the engine directly to ICS.  We don't allow these to be \r
-     *  sent until we are logged on. Crafty kibitzes have been known to \r
-     *  interfere with the login process.\r
-     */\r
-    if (loggedOn) {\r
-       if (!strncmp(message, "tellics ", 8)) {\r
-           SendToICS(message + 8);\r
-           SendToICS("\n");\r
-           return;\r
-       }\r
-       if (!strncmp(message, "tellicsnoalias ", 15)) {\r
-           SendToICS(ics_prefix);\r
-           SendToICS(message + 15);\r
-           SendToICS("\n");\r
-           return;\r
-       }\r
-       /* The following are for backward compatibility only */\r
-       if (!strncmp(message,"whisper",7) || !strncmp(message,"kibitz",6) ||\r
-           !strncmp(message,"draw",4) || !strncmp(message,"tell",3)) {\r
-           SendToICS(ics_prefix);\r
-           SendToICS(message);\r
-           SendToICS("\n");\r
-           return;\r
-       }\r
-    }\r
-    if (strncmp(message, "feature ", 8) == 0) {\r
-      ParseFeatures(message+8, cps);\r
-    }\r
-    if (sscanf(message, "pong %d", &cps->lastPong) == 1) {\r
-       return;\r
-    }\r
-    /*\r
-     * If the move is illegal, cancel it and redraw the board.\r
-     * Also deal with other error cases.  Matching is rather loose\r
-     * here to accommodate engines written before the spec.\r
-     */\r
-    if (strncmp(message + 1, "llegal move", 11) == 0 ||\r
-       strncmp(message, "Error", 5) == 0) {\r
-       if (StrStr(message, "name") || \r
-           StrStr(message, "rating") || StrStr(message, "?") ||\r
-           StrStr(message, "result") || StrStr(message, "board") ||\r
-           StrStr(message, "bk") || StrStr(message, "computer") ||\r
-           StrStr(message, "variant") || StrStr(message, "hint") ||\r
-           StrStr(message, "random") || StrStr(message, "depth") ||\r
-           StrStr(message, "accepted")) {\r
-           return;\r
-       }\r
-       if (StrStr(message, "protover")) {\r
-         /* Program is responding to input, so it's apparently done\r
-             initializing, and this error message indicates it is\r
-             protocol version 1.  So we don't need to wait any longer\r
-             for it to initialize and send feature commands. */\r
-         FeatureDone(cps, 1);\r
-         cps->protocolVersion = 1;\r
-         return;\r
-       }\r
-       cps->maybeThinking = FALSE;\r
-\r
-       if (StrStr(message, "draw")) {\r
-           /* Program doesn't have "draw" command */\r
-           cps->sendDrawOffers = 0;\r
-           return;\r
-       }\r
-       if (cps->sendTime != 1 &&\r
-           (StrStr(message, "time") || StrStr(message, "otim"))) {\r
-         /* Program apparently doesn't have "time" or "otim" command */\r
-         cps->sendTime = 0;\r
-         return;\r
-       }\r
-       if (StrStr(message, "analyze")) {\r
-           cps->analysisSupport = FALSE;\r
-           cps->analyzing = FALSE;\r
-           Reset(FALSE, TRUE);\r
-           sprintf(buf2, _("%s does not support analysis"), cps->tidy);\r
-           DisplayError(buf2, 0);\r
-           return;\r
-       }\r
-       if (StrStr(message, "(no matching move)st")) {\r
-         /* Special kludge for GNU Chess 4 only */\r
-         cps->stKludge = TRUE;\r
-         SendTimeControl(cps, movesPerSession, timeControl,\r
-                         timeIncrement, appData.searchDepth,\r
-                         searchTime);\r
-         return;\r
-       }\r
-       if (StrStr(message, "(no matching move)sd")) {\r
-         /* Special kludge for GNU Chess 4 only */\r
-         cps->sdKludge = TRUE;\r
-         SendTimeControl(cps, movesPerSession, timeControl,\r
-                         timeIncrement, appData.searchDepth,\r
-                         searchTime);\r
-         return;\r
-       }\r
-        if (!StrStr(message, "llegal")) {\r
-            return;\r
-        }\r
-       if (gameMode == BeginningOfGame || gameMode == EndOfGame ||\r
-           gameMode == IcsIdle) return;\r
-       if (forwardMostMove <= backwardMostMove) return;\r
-#if 0\r
-       /* Following removed: it caused a bug where a real illegal move\r
-          message in analyze mored would be ignored. */\r
-       if (cps == &first && programStats.ok_to_send == 0) {\r
-           /* Bogus message from Crafty responding to "."  This filtering\r
-              can miss some of the bad messages, but fortunately the bug \r
-              is fixed in current Crafty versions, so it doesn't matter. */\r
-           return;\r
-       }\r
-#endif\r
-       if (pausing) PauseEvent();\r
-       if (gameMode == PlayFromGameFile) {\r
-           /* Stop reading this game file */\r
-           gameMode = EditGame;\r
-           ModeHighlight();\r
-       }\r
-       currentMove = --forwardMostMove;\r
-       DisplayMove(currentMove-1); /* before DisplayMoveError */\r
-       SwitchClocks();\r
-       DisplayBothClocks();\r
-       sprintf(buf1, _("Illegal move \"%s\" (rejected by %s chess program)"),\r
-               parseList[currentMove], cps->which);\r
-       DisplayMoveError(buf1);\r
-       DrawPosition(FALSE, boards[currentMove]);\r
-\r
-        /* [HGM] illegal-move claim should forfeit game when Xboard */\r
-        /* only passes fully legal moves                            */\r
-        if( appData.testLegality && gameMode == TwoMachinesPlay ) {\r
-            GameEnds( cps->twoMachinesColor[0] == 'w' ? BlackWins : WhiteWins,\r
-                                "False illegal-move claim", GE_XBOARD );\r
-        }\r
-       return;\r
-    }\r
-    if (strncmp(message, "time", 4) == 0 && StrStr(message, "Illegal")) {\r
-       /* Program has a broken "time" command that\r
-          outputs a string not ending in newline.\r
-          Don't use it. */\r
-       cps->sendTime = 0;\r
-    }\r
-    \r
-    /*\r
-     * If chess program startup fails, exit with an error message.\r
-     * Attempts to recover here are futile.\r
-     */\r
-    if ((StrStr(message, "unknown host") != NULL)\r
-       || (StrStr(message, "No remote directory") != NULL)\r
-       || (StrStr(message, "not found") != NULL)\r
-       || (StrStr(message, "No such file") != NULL)\r
-       || (StrStr(message, "can't alloc") != NULL)\r
-       || (StrStr(message, "Permission denied") != NULL)) {\r
-\r
-       cps->maybeThinking = FALSE;\r
-       sprintf(buf1, _("Failed to start %s chess program %s on %s: %s\n"),\r
-               cps->which, cps->program, cps->host, message);\r
-       RemoveInputSource(cps->isr);\r
-       DisplayFatalError(buf1, 0, 1);\r
-       return;\r
-    }\r
-    \r
-    /* \r
-     * Look for hint output\r
-     */\r
-    if (sscanf(message, "Hint: %s", buf1) == 1) {\r
-       if (cps == &first && hintRequested) {\r
-           hintRequested = FALSE;\r
-           if (ParseOneMove(buf1, forwardMostMove, &moveType,\r
-                                &fromX, &fromY, &toX, &toY, &promoChar)) {\r
-               (void) CoordsToAlgebraic(boards[forwardMostMove],\r
-                                   PosFlags(forwardMostMove), EP_UNKNOWN,\r
-                                   fromY, fromX, toY, toX, promoChar, buf1);\r
-               sprintf(buf2, _("Hint: %s"), buf1);\r
-               DisplayInformation(buf2);\r
-           } else {\r
-               /* Hint move could not be parsed!? */\r
-               sprintf(buf2,\r
-                       _("Illegal hint move \"%s\"\nfrom %s chess program"),\r
-                       buf1, cps->which);\r
-               DisplayError(buf2, 0);\r
-           }\r
-       } else {\r
-           strcpy(lastHint, buf1);\r
-       }\r
-       return;\r
-    }\r
-\r
-    /*\r
-     * Ignore other messages if game is not in progress\r
-     */\r
-    if (gameMode == BeginningOfGame || gameMode == EndOfGame ||\r
-       gameMode == IcsIdle || cps->lastPing != cps->lastPong) return;\r
-\r
-    /*\r
-     * look for win, lose, draw, or draw offer\r
-     */\r
-    if (strncmp(message, "1-0", 3) == 0) {\r
-       char *p, *q, *r = "";\r
-        p = strchr(message, '{');\r
-       if (p) {\r
-           q = strchr(p, '}');\r
-           if (q) {\r
-               *q = NULLCHAR;\r
-               r = p + 1;\r
-           }\r
-       }\r
-        GameEnds(WhiteWins, r, GE_ENGINE1 + (cps != &first)); /* [HGM] pass claimer indication for claim test */\r
-       return;\r
-    } else if (strncmp(message, "0-1", 3) == 0) {\r
-       char *p, *q, *r = "";\r
-        p = strchr(message, '{');\r
-       if (p) {\r
-           q = strchr(p, '}');\r
-           if (q) {\r
-               *q = NULLCHAR;\r
-               r = p + 1;\r
-           }\r
-       }\r
-       /* Kludge for Arasan 4.1 bug */\r
-       if (strcmp(r, "Black resigns") == 0) {\r
-            GameEnds(WhiteWins, r, GE_ENGINE1 + (cps != &first));\r
-           return;\r
-       }\r
-        GameEnds(BlackWins, r, GE_ENGINE1 + (cps != &first));\r
-       return;\r
-    } else if (strncmp(message, "1/2", 3) == 0) {\r
-       char *p, *q, *r = "";\r
-        p = strchr(message, '{');\r
-       if (p) {\r
-           q = strchr(p, '}');\r
-           if (q) {\r
-               *q = NULLCHAR;\r
-               r = p + 1;\r
-           }\r
-       }\r
-            \r
-        GameEnds(GameIsDrawn, r, GE_ENGINE1 + (cps != &first));\r
-       return;\r
-\r
-    } else if (strncmp(message, "White resign", 12) == 0) {\r
-        GameEnds(BlackWins, "White resigns", GE_ENGINE1 + (cps != &first));\r
-       return;\r
-    } else if (strncmp(message, "Black resign", 12) == 0) {\r
-        GameEnds(WhiteWins, "Black resigns", GE_ENGINE1 + (cps != &first));\r
-       return;\r
-    } else if (strncmp(message, "White matches", 13) == 0 ||\r
-               strncmp(message, "Black matches", 13) == 0   ) {\r
-        /* [HGM] ignore GNUShogi noises */\r
-        return;\r
-    } else if (strncmp(message, "White", 5) == 0 &&\r
-              message[5] != '(' &&\r
-              StrStr(message, "Black") == NULL) {\r
-        GameEnds(WhiteWins, "White mates", GE_ENGINE1 + (cps != &first));\r
-       return;\r
-    } else if (strncmp(message, "Black", 5) == 0 &&\r
-              message[5] != '(') {\r
-        GameEnds(BlackWins, "Black mates", GE_ENGINE1 + (cps != &first));\r
-       return;\r
-    } else if (strcmp(message, "resign") == 0 ||\r
-              strcmp(message, "computer resigns") == 0) {\r
-       switch (gameMode) {\r
-         case MachinePlaysBlack:\r
-         case IcsPlayingBlack:\r
-            GameEnds(WhiteWins, "Black resigns", GE_ENGINE);\r
-           break;\r
-         case MachinePlaysWhite:\r
-         case IcsPlayingWhite:\r
-            GameEnds(BlackWins, "White resigns", GE_ENGINE);\r
-           break;\r
-         case TwoMachinesPlay:\r
-           if (cps->twoMachinesColor[0] == 'w')\r
-              GameEnds(BlackWins, "White resigns", GE_ENGINE1 + (cps != &first));\r
-           else\r
-              GameEnds(WhiteWins, "Black resigns", GE_ENGINE1 + (cps != &first));\r
-           break;\r
-         default:\r
-           /* can't happen */\r
-           break;\r
-       }\r
-       return;\r
-    } else if (strncmp(message, "opponent mates", 14) == 0) {\r
-       switch (gameMode) {\r
-         case MachinePlaysBlack:\r
-         case IcsPlayingBlack:\r
-            GameEnds(WhiteWins, "White mates", GE_ENGINE);\r
-           break;\r
-         case MachinePlaysWhite:\r
-         case IcsPlayingWhite:\r
-            GameEnds(BlackWins, "Black mates", GE_ENGINE);\r
-           break;\r
-         case TwoMachinesPlay:\r
-           if (cps->twoMachinesColor[0] == 'w')\r
-              GameEnds(BlackWins, "Black mates", GE_ENGINE1 + (cps != &first));\r
-           else\r
-              GameEnds(WhiteWins, "White mates", GE_ENGINE1 + (cps != &first));\r
-           break;\r
-         default:\r
-           /* can't happen */\r
-           break;\r
-       }\r
-       return;\r
-    } else if (strncmp(message, "computer mates", 14) == 0) {\r
-       switch (gameMode) {\r
-         case MachinePlaysBlack:\r
-         case IcsPlayingBlack:\r
-            GameEnds(BlackWins, "Black mates", GE_ENGINE1);\r
-           break;\r
-         case MachinePlaysWhite:\r
-         case IcsPlayingWhite:\r
-            GameEnds(WhiteWins, "White mates", GE_ENGINE);\r
-           break;\r
-         case TwoMachinesPlay:\r
-           if (cps->twoMachinesColor[0] == 'w')\r
-              GameEnds(WhiteWins, "White mates", GE_ENGINE1 + (cps != &first));\r
-           else\r
-              GameEnds(BlackWins, "Black mates", GE_ENGINE1 + (cps != &first));\r
-           break;\r
-         default:\r
-           /* can't happen */\r
-           break;\r
-       }\r
-       return;\r
-    } else if (strncmp(message, "checkmate", 9) == 0) {\r
-       if (WhiteOnMove(forwardMostMove)) {\r
-            GameEnds(BlackWins, "Black mates", GE_ENGINE1 + (cps != &first));\r
-       } else {\r
-            GameEnds(WhiteWins, "White mates", GE_ENGINE1 + (cps != &first));\r
-       }\r
-       return;\r
-    } else if (strstr(message, "Draw") != NULL ||\r
-              strstr(message, "game is a draw") != NULL) {\r
-        GameEnds(GameIsDrawn, "Draw", GE_ENGINE1 + (cps != &first));\r
-       return;\r
-    } else if (strstr(message, "offer") != NULL &&\r
-              strstr(message, "draw") != NULL) {\r
-#if ZIPPY\r
-       if (appData.zippyPlay && first.initDone) {\r
-           /* Relay offer to ICS */\r
-           SendToICS(ics_prefix);\r
-           SendToICS("draw\n");\r
-       }\r
-#endif\r
-       cps->offeredDraw = 2; /* valid until this engine moves twice */\r
-       if (gameMode == TwoMachinesPlay) {\r
-           if (cps->other->offeredDraw) {\r
-               GameEnds(GameIsDrawn, "Draw agreed", GE_XBOARD);\r
-            /* [HGM] in two-machine mode we delay relaying draw offer      */\r
-            /* until after we also have move, to see if it is really claim */\r
-           }\r
-#if 0\r
-              else {\r
-               if (cps->other->sendDrawOffers) {\r
-                   SendToProgram("draw\n", cps->other);\r
-               }\r
-           }\r
-#endif\r
-       } else if (gameMode == MachinePlaysWhite ||\r
-                  gameMode == MachinePlaysBlack) {\r
-         if (userOfferedDraw) {\r
-           DisplayInformation(_("Machine accepts your draw offer"));\r
-           GameEnds(GameIsDrawn, "Draw agreed", GE_XBOARD);\r
-         } else {\r
-            DisplayInformation(_("Machine offers a draw\nSelect Action / Draw to agree"));\r
-         }\r
-       }\r
-    }\r
-\r
-    \r
-    /*\r
-     * Look for thinking output\r
-     */\r
-    if ( appData.showThinking // [HGM] thinking: test all options that cause this output\r
-         || !appData.hideThinkingFromHuman || appData.adjudicateLossThreshold != 0 || EngineOutputIsUp()\r
-                               ) {\r
-       int plylev, mvleft, mvtot, curscore, time;\r
-       char mvname[MOVE_LEN];\r
-       u64 nodes; // [DM]\r
-       char plyext;\r
-       int ignore = FALSE;\r
-       int prefixHint = FALSE;\r
-       mvname[0] = NULLCHAR;\r
-\r
-       switch (gameMode) {\r
-         case MachinePlaysBlack:\r
-         case IcsPlayingBlack:\r
-           if (WhiteOnMove(forwardMostMove)) prefixHint = TRUE;\r
-           break;\r
-         case MachinePlaysWhite:\r
-         case IcsPlayingWhite:\r
-           if (!WhiteOnMove(forwardMostMove)) prefixHint = TRUE;\r
-           break;\r
-         case AnalyzeMode:\r
-         case AnalyzeFile:\r
-            break;\r
-          case IcsObserving: /* [DM] icsEngineAnalyze */\r
-            if (!appData.icsEngineAnalyze) ignore = TRUE;\r
-           break;\r
-         case TwoMachinesPlay:\r
-           if ((cps->twoMachinesColor[0] == 'w') != WhiteOnMove(forwardMostMove)) {\r
-               ignore = TRUE;\r
-           }\r
-           break;\r
-         default:\r
-           ignore = TRUE;\r
-           break;\r
-       }\r
-\r
-       if (!ignore) {\r
-           buf1[0] = NULLCHAR;\r
-           if (sscanf(message, "%d%c %d %d " u64Display " %[^\n]\n",\r
-                      &plylev, &plyext, &curscore, &time, &nodes, buf1) >= 5) {\r
-\r
-               if