* 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
+ * Copyright 1991 by Digital Equipment Corporation, Maynard,\r
+ * Massachusetts. Enhancements Copyright\r
+ * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software\r
+ * Foundation, Inc.\r
*\r
* The following terms apply to Digital Equipment Corporation's copyright\r
* interest in XBoard:\r
* SOFTWARE.\r
* ------------------------------------------------------------------------\r
*\r
- * The following terms apply to the enhanced version of XBoard distributed\r
- * by the Free Software Foundation:\r
+ * The following terms apply to the enhanced version of XBoard\r
+ * distributed by the Free Software Foundation:\r
* ------------------------------------------------------------------------\r
- * This program is free software; you can redistribute it and/or modify\r
+ *\r
+ * GNU XBoard 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
+ * the Free Software Foundation, either version 3 of the License, or (at\r
+ * 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
+ * GNU XBoard is distributed in the hope that it will be useful, but\r
+ * WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+ * 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
+ * along with this program. If not, see http://www.gnu.org/licenses/. *\r
*\r
- * See the file ChangeLog for a revision history. */\r
+ *------------------------------------------------------------------------\r
+ ** See the file ChangeLog for a revision history. */\r
\r
/* [AS] Also useful here for debugging */\r
#ifdef WIN32\r
#include <sys/types.h>\r
#include <sys/stat.h>\r
#include <math.h>\r
+#include <ctype.h>\r
\r
#if STDC_HEADERS\r
# include <stdlib.h>\r
void InitBackEnd3 P((void));\r
void FeatureDone P((ChessProgramState* cps, int val));\r
void InitChessProgram P((ChessProgramState *cps, int setup));\r
+void OutputKibitz(int window, char *text);\r
+int PerpetualChase(int first, int last);\r
+int EngineOutputIsUp();\r
+void InitDrawingSizes(int x, int y);\r
\r
#ifdef WIN32\r
extern void ConsoleCreate();\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
+static int setboardSpoiledMachineBlack = 0 /*, errorExitFlag = 0*/;\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
return dst;\r
}\r
\r
+#if 0\r
+//[HGM] for future use? Conditioned out for now to suppress warning.\r
static char * safeStrCat( char * dst, const char * src, size_t count )\r
{\r
size_t dst_len;\r
\r
return dst;\r
}\r
+#endif\r
\r
/* Some compiler can't cast u64 to double\r
* This function do the job for us:\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
{\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
+// Board tempBoard; int saveCastling[BOARD_SIZE], saveEP;\r
\r
startedFromPositionFile = FALSE;\r
if(gameInfo.variant == newVariant) return;\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
+ 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
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.nodes = programStats.depth = programStats.time = \r
programStats.score = programStats.got_only_move = 0;\r
sprintf(programStats.movelist, "%s (xbook)", bookHit);\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.nodes = programStats.depth = programStats.time = \r
programStats.score = programStats.got_only_move = 0;\r
sprintf(programStats.movelist, "%s (xbook)", bookHit);\r
\r
void\r
AlphaRank(char *move, int n)\r
{\r
- char *p = move, c; int x, y;\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
\r
+#if 0\r
/* [AS] FRC game initialization */\r
static int FindEmptySquare( Board board, int n )\r
{\r
return i;\r
}\r
\r
-#if 0\r
static void ShuffleFRC( Board board )\r
{\r
int i;\r
\r
int squaresLeft[4];\r
int piecesLeft[(int)BlackPawn];\r
-long long int seed, nrOfShuffles;\r
+u64 seed, nrOfShuffles;\r
\r
void GetPositionNumber()\r
{ // sets global variable seed\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
+ 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[((i-BOARD_LEFT)&1) + 1]--;\r
squaresLeft[ANY]--;\r
piecesLeft[pieceType]--; \r
return i;\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
+ 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
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][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
+ castlingRights[0][5] = initialRights[5] =(BOARD_WIDTH-1)>>1;\r
break;\r
case VariantFalcon:\r
pieces = FalconArray;\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.nodes = programStats.depth = programStats.time = \r
programStats.score = programStats.got_only_move = 0;\r
sprintf(programStats.movelist, "%s (xbook)", bookHit);\r
\r
\r
void SendProgramStatsToFrontend( ChessProgramState * cps, ChessProgramStats * cpstats )\r
{\r
- char * hint = lastHint;\r
+// char * hint = lastHint;\r
FrontEndProgramStats stats;\r
\r
stats.which = cps == &first ? 0 : 1;\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
+ sprintf(buf1, "Xboard: Forfeit due to invalid move: %s (%c%c%c%c) res=%d",\r
+ machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, moveType);\r
if (gameMode == TwoMachinesPlay) {\r
GameEnds(machineWhite ? BlackWins : WhiteWins,\r
buf1, GE_XBOARD);\r
toX--;\r
currentMoveString[2]--;\r
break;\r
+ default: ; // nothing to do, but suppresses warning of pedantic compilers\r
}\r
}\r
hintRequested = FALSE;\r
programStats.depth,\r
programStats.score / 100.,\r
programStats.time / 100.,\r
- (double) programStats.nodes,\r
- programStats.nodes / (10*abs(programStats.time) + 1.),\r
+ u64ToDouble(programStats.nodes),\r
+ u64ToDouble(programStats.nodes) / (10*abs(programStats.time) + 1.),\r
programStats.movelist);\r
SendToICS(buf);\r
}\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
+ NrPieces=0, NrPawns=0, PawnAdvance=0, i, j;\r
static int moveCount = 6;\r
\r
/* First absolutely insufficient mating material. Count what is on board. */\r
EP_NONE, castlingRights[m-1]) != MT_CHECK)\r
hisPerpetual = 0; // the opponent did not always check\r
}\r
+ if(appData.debugMode) fprintf(debugFP, "XQ perpetual test, our=%d, his=%d\n",\r
+ ourPerpetual, hisPerpetual);\r
if(ourPerpetual && !hisPerpetual) { // we are actively checking him: forfeit\r
GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, \r
"Xboard adjudication: perpetual checking", GE_XBOARD );\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
+ // Now check for perpetual chases\r
+ if(!ourPerpetual && !hisPerpetual) { // no perpetual check, test for chase\r
+ hisPerpetual = PerpetualChase(k, forwardMostMove);\r
+ ourPerpetual = PerpetualChase(k+1, forwardMostMove);\r
+ if(ourPerpetual && !hisPerpetual) { // we are actively checking him: forfeit\r
+ GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, \r
+ "Xboard adjudication: perpetual chasing", GE_XBOARD );\r
+ return;\r
+ }\r
+ if(hisPerpetual && !ourPerpetual) // he is chasing us, but did not repeat yet\r
+ break; // Abort repetition-checking loop.\r
+ }\r
+ // if neither of us is checking or chasing all the time, or both are, it is draw\r
}\r
GameEnds( GameIsDrawn, "Xboard adjudication: repetition draw", GE_XBOARD );\r
return;\r
strcat(bookMove, bookHit);\r
message = bookMove;\r
cps = cps->other;\r
- programStats.depth = programStats.nodes = programStats.time = \r
+ programStats.nodes = programStats.depth = programStats.time = \r
programStats.score = programStats.got_only_move = 0;\r
sprintf(programStats.movelist, "%s (xbook)", bookHit);\r
\r
if(cps->nps >= 0) { /* [HGM] nps: use engine nodes or time to decrement clock */\r
int ticklen;\r
\r
- if(cps->nps == 0) ticklen = 10*time; // use engine reported time\r
- else ticklen = (1000. * nodes) / cps->nps; // convert node count to time\r
+ if(cps->nps == 0) ticklen = 10*time; // use engine reported time\r
+ else ticklen = (1000. * u64ToDouble(nodes)) / cps->nps; // convert node count to time\r
if(WhiteOnMove(forwardMostMove)) \r
whiteTimeRemaining = timeRemaining[0][forwardMostMove] - ticklen;\r
else blackTimeRemaining = timeRemaining[1][forwardMostMove] - ticklen;\r
else {\r
buf1[0] = NULLCHAR;\r
\r
- if (sscanf(message, "%d%c %d %d %lu %[^\n]\n",\r
+ if (sscanf(message, "%d%c %d %d " u64Display " %[^\n]\n",\r
&plylev, &plyext, &curscore, &time, &nodes, buf1) >= 5) \r
{\r
ChessProgramStats cpstats;\r
/* [HGM] compute & store e.p. status and castling rights for new position */\r
/* if we are updating a board for which those exist (i.e. in boards[]) */\r
if((p = ((int)board - (int)boards[0])/((int)boards[1]-(int)boards[0])) < MAX_MOVES && p > 0)\r
- { int i, j;\r
+ { int i;\r
\r
if(gameInfo.variant == VariantBerolina) berolina = EP_BEROLIN_A;\r
oldEP = epStatus[p-1];\r
int fromX, fromY, toX, toY;\r
int promoChar;\r
{\r
- forwardMostMove++;\r
+// forwardMostMove++; // [HGM] bare: moved downstream\r
\r
- if(serverMoves != NULL) { /* [HGM] write moves on file for broadcasting */\r
+ if(serverMoves != NULL) { /* [HGM] write moves on file for broadcasting (should be separate routine, really) */\r
int timeLeft; static int lastLoadFlag=0; int king, piece;\r
- piece = boards[forwardMostMove-1][fromY][fromX];\r
+ piece = boards[forwardMostMove][fromY][fromX];\r
king = piece < (int) BlackPawn ? WhiteKing : BlackKing;\r
if(gameInfo.variant == VariantKnightmate)\r
king += (int) WhiteUnicorn - (int) WhiteKing;\r
- if(forwardMostMove == 1) {\r
+ if(forwardMostMove == 0) {\r
if(blackPlaysFirst) \r
fprintf(serverMoves, "%s;", second.tidy);\r
fprintf(serverMoves, "%s;", first.tidy);\r
fprintf(serverMoves, ":%c%c:%c%c", AAA+BOARD_LEFT, ONE+fromY, AAA+toX+1,ONE+toY);\r
}\r
// e.p. suffix\r
- if( (boards[forwardMostMove-1][fromY][fromX] == WhitePawn ||\r
- boards[forwardMostMove-1][fromY][fromX] == BlackPawn ) &&\r
- boards[forwardMostMove-1][toY][toX] == EmptySquare\r
+ if( (boards[forwardMostMove][fromY][fromX] == WhitePawn ||\r
+ boards[forwardMostMove][fromY][fromX] == BlackPawn ) &&\r
+ boards[forwardMostMove][toY][toX] == EmptySquare\r
&& fromX != toX )\r
fprintf(serverMoves, ":%c%c:%c%c", AAA+fromX, ONE+fromY, AAA+toX, ONE+fromY);\r
// promotion suffix\r
fprintf(serverMoves, ":%c:%c%c", promoChar, AAA+toX, ONE+toY);\r
if(!loadFlag) {\r
fprintf(serverMoves, "/%d/%d",\r
- pvInfoList[forwardMostMove-1].depth, pvInfoList[forwardMostMove-1].score);\r
- if(forwardMostMove & 1) timeLeft = whiteTimeRemaining/1000;\r
- else timeLeft = blackTimeRemaining/1000;\r
+ pvInfoList[forwardMostMove].depth, pvInfoList[forwardMostMove].score);\r
+ if(forwardMostMove+1 & 1) timeLeft = whiteTimeRemaining/1000;\r
+ else timeLeft = blackTimeRemaining/1000;\r
fprintf(serverMoves, "/%d", timeLeft);\r
}\r
fflush(serverMoves);\r
}\r
\r
- if (forwardMostMove >= MAX_MOVES) {\r
+ if (forwardMostMove+1 >= MAX_MOVES) {\r
DisplayFatalError(_("Game too long; increase MAX_MOVES and recompile"),\r
0, 1);\r
return;\r
}\r
SwitchClocks();\r
- timeRemaining[0][forwardMostMove] = whiteTimeRemaining;\r
- timeRemaining[1][forwardMostMove] = blackTimeRemaining;\r
- if (commentList[forwardMostMove] != NULL) {\r
- free(commentList[forwardMostMove]);\r
- commentList[forwardMostMove] = NULL;\r
- }\r
- CopyBoard(boards[forwardMostMove], boards[forwardMostMove - 1]);\r
- ApplyMove(fromX, fromY, toX, toY, promoChar, boards[forwardMostMove]);\r
+ timeRemaining[0][forwardMostMove+1] = whiteTimeRemaining;\r
+ timeRemaining[1][forwardMostMove+1] = blackTimeRemaining;\r
+ if (commentList[forwardMostMove+1] != NULL) {\r
+ free(commentList[forwardMostMove+1]);\r
+ commentList[forwardMostMove+1] = NULL;\r
+ }\r
+ CopyBoard(boards[forwardMostMove+1], boards[forwardMostMove]);\r
+ ApplyMove(fromX, fromY, toX, toY, promoChar, boards[forwardMostMove+1]);\r
+ forwardMostMove++; // [HGM] bare: moved to after ApplyMove, to make sure clock interrupt finds complete board\r
gameInfo.result = GameUnfinished;\r
if (gameInfo.resultDetails != NULL) {\r
free(gameInfo.resultDetails);\r
{\r
int i, offset, linelen, newblock;\r
time_t tm;\r
- char *movetext;\r
+// char *movetext;\r
char numtext[32];\r
int movelen, numlen, blank;\r
char move_buffer[100]; /* [AS] Buffer for move+PV info */\r
#else\r
seconds = (pvInfoList[i].time + 5)/10; // [HGM] PVtime: use engine time\r
#endif\r
- if (appData.debugMode,0) {\r
- fprintf(debugFP, "times = %d %d %d %d, seconds=%d\n",\r
- timeRemaining[0][i+1], timeRemaining[0][i],\r
- timeRemaining[1][i+1], timeRemaining[1][i], seconds\r
- );\r
- }\r
\r
if( seconds <= 0) buf[0] = 0; else\r
if( seconds < 30 ) sprintf(buf, " %3.1f%c", seconds/10., 0); else {\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.nodes = programStats.depth = programStats.time = \r
programStats.score = programStats.got_only_move = 0;\r
sprintf(programStats.movelist, "%s (xbook)", bookHit);\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.nodes = programStats.depth = programStats.time = \r
programStats.score = programStats.got_only_move = 0;\r
sprintf(programStats.movelist, "%s (xbook)", bookHit);\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.nodes = programStats.depth = programStats.time = \r
programStats.score = programStats.got_only_move = 0;\r
sprintf(programStats.movelist, "%s (xbook)", bookHit);\r
\r
opt->type = SaveButton;\r
} else return FALSE;\r
*p = 0; // terminate option name\r
+ // now look if the command-line options define a setting for this engine option.\r
+ p = strstr(cps->optionSettings, opt->name);\r
+ if(p == cps->optionSettings || p[-1] == ',') {\r
+ sprintf(buf, "option %s", p);\r
+ if(p = strstr(buf, ",")) *p = 0;\r
+ strcat(buf, "\n");\r
+ SendToProgram(buf, cps);\r
+ }\r
return TRUE;\r
}\r
\r
char res[MSG_SIZ];\r
char cpThinkOutput[MSG_SIZ];\r
\r
+ if(appData.noGUI) return; // [HGM] fast: suppress display of moves\r
+ \r
if (moveNumber == forwardMostMove - 1 || \r
gameMode == AnalyzeMode || gameMode == AnalyzeFile) {\r
\r
} else {\r
res[0] = NULLCHAR;\r
}\r
- \r
+\r
if (moveNumber < 0 || parseList[moveNumber][0] == NULLCHAR) {\r
DisplayMessage(res, cpThinkOutput);\r
} else {\r
you have neither ftime nor gettimeofday.\r
*/\r
\r
+/* VS 2008 requires the #include outside of the function */\r
+#if !HAVE_GETTIMEOFDAY && HAVE_FTIME\r
+#include <sys/timeb.h>\r
+#endif\r
+\r
/* Get the current time as a TimeMark */\r
void\r
GetTimeMark(tm)\r
#else /*!HAVE_GETTIMEOFDAY*/\r
#if HAVE_FTIME\r
\r
-#include <sys/timeb.h>\r
+// include <sys/timeb.h> / moved to just above start of function\r
struct timeb timeB;\r
\r
ftime(&timeB);\r