#ifdef WIN32
#include <windows.h>
-#define DoSleep( n ) if( (n) != 0 ) Sleep( (n) );
-
int flock(int f, int code);
#define LOCK_EX 2
#define SLASH '\\'
#else
#include <sys/file.h>
-#define DoSleep( n ) if( (n) >= 0) sleep(n)
#define SLASH '/'
#endif
#endif
-/* A point in time */
-typedef struct {
- long sec; /* Assuming this is >= 32 bits */
- int ms; /* Assuming this is >= 16 bits */
-} TimeMark;
-
int establish P((void));
void read_from_player P((InputSourceRef isr, VOIDSTAR closure,
char *buf, int count, int error));
int LoadGameFromFile P((char *filename, int n, char *title, int useList));
int LoadPositionFromFile P((char *filename, int n, char *title));
int SavePositionToFile P((char *filename));
-void ApplyMove P((int fromX, int fromY, int toX, int toY, int promoChar,
- Board board));
void MakeMove P((int fromX, int fromY, int toX, int toY, int promoChar));
void ShowMove P((int fromX, int fromY, int toX, int toY));
int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
void ResetClocks P((void));
char *PGNDate P((void));
void SetGameInfo P((void));
-Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
int RegisterMove P((void));
void MakeRegisteredMove P((void));
void TruncateGame P((void));
char *SavePart P((char *));
int SaveGameOldStyle P((FILE *));
int SaveGamePGN P((FILE *));
-void GetTimeMark P((TimeMark *));
-long SubtractTimeMarks P((TimeMark *, TimeMark *));
int CheckFlags P((void));
long NextTickLength P((long));
void CheckTimeControl P((void));
int movesPerSession;
int suddenDeath, whiteStartMove, blackStartMove; /* [HGM] for implementation of 'any per time' sessions, as in first part of byoyomi TC */
long whiteTimeRemaining, blackTimeRemaining, timeControl, timeIncrement, lastWhite, lastBlack;
+Boolean adjustedClock;
long timeControl_2; /* [AS] Allow separate time controls */
char *fullTimeControlString = NULL, *nextSession, *whiteTC, *blackTC; /* [HGM] secondary TC: merge of MPS, TC and inc */
long timeRemaining[2][MAX_MOVES];
#ifdef FALCON
ChessSquare FalconArray[2][BOARD_FILES] = {
- { WhiteRook, WhiteKnight, WhiteBishop, WhiteLance, WhiteQueen,
- WhiteKing, WhiteLance, WhiteBishop, WhiteKnight, WhiteRook },
- { BlackRook, BlackKnight, BlackBishop, BlackLance, BlackQueen,
- BlackKing, BlackLance, BlackBishop, BlackKnight, BlackRook }
+ { WhiteRook, WhiteKnight, WhiteBishop, WhiteFalcon, WhiteQueen,
+ WhiteKing, WhiteFalcon, WhiteBishop, WhiteKnight, WhiteRook },
+ { BlackRook, BlackKnight, BlackBishop, BlackFalcon, BlackQueen,
+ BlackKing, BlackFalcon, BlackBishop, BlackKnight, BlackRook }
};
#else // !FALCON
#define FalconArray CapablancaArray
len = snprintf(buf, MSG_SIZ, _("protocol version %d not supported"),
appData.protocolVersion[n]);
- if( (len > MSG_SIZ) && appData.debugMode )
+ if( (len >= MSG_SIZ) && appData.debugMode )
fprintf(debugFP, "InitBackEnd1: buffer truncated.\n");
DisplayFatalError(buf, 0, 2);
}
InitEngineUCI( installDir, cps ); // [HGM] moved here from winboard.c, to make available in xboard
+ ParseFeatures(appData.featureDefaults, cps);
}
ChessProgramState *savCps;
static char resetOptions[] =
"-reuse -firstIsUCI false -firstHasOwnBookUCI true -firstTimeOdds 1 "
+ "-firstInitString \"" INIT_STRING "\" -firstComputerString \"" COMPUTER_STRING "\" "
"-firstOptions \"\" -firstNPS -1 -fn \"\"";
void
Load(ChessProgramState *cps, int i)
{
char *p, *q, buf[MSG_SIZ], command[MSG_SIZ], buf2[MSG_SIZ];
- if(engineLine[0]) { // an engine was selected from the combo box
+ if(engineLine && engineLine[0]) { // an engine was selected from the combo box
snprintf(buf, MSG_SIZ, "-fcp %s", engineLine);
SwapEngines(i); // kludge to parse -f* / -first* like it is -s* / -second*
- ParseArgsFromString(resetOptions); appData.fenOverride[0] = NULL;
+ ParseArgsFromString(resetOptions); appData.fenOverride[0] = NULL; appData.pvSAN[0] = FALSE;
ParseArgsFromString(buf);
SwapEngines(i);
ReplaceEngine(cps, i);
appData.directory[i] = strdup(engineName);
p[-1] = SLASH;
} else appData.directory[i] = ".";
- if(strchr(p, ' ') && !strchr(p, '"')) snprintf(buf2, MSG_SIZ, "\"%s\"", p), p = buf2; // quote if it contains spaces
if(params[0]) {
+ if(strchr(p, ' ') && !strchr(p, '"')) snprintf(buf2, MSG_SIZ, "\"%s\"", p), p = buf2; // quote if it contains spaces
snprintf(command, MSG_SIZ, "%s %s", p, params);
p = command;
}
case VariantKriegspiel: /* need to hide pieces and move details */
/* case VariantFischeRandom: (Fabien: moved below) */
len = snprintf(buf,MSG_SIZ, _("Variant %s supported only in ICS mode"), appData.variant);
- if( (len > MSG_SIZ) && appData.debugMode )
+ if( (len >= MSG_SIZ) && appData.debugMode )
fprintf(debugFP, "InitBackEnd1: buffer truncated.\n");
DisplayFatalError(buf, 0, 2);
case Variant36:
default:
len = snprintf(buf, MSG_SIZ, _("Unknown variant name %s"), appData.variant);
- if( (len > MSG_SIZ) && appData.debugMode )
+ if( (len >= MSG_SIZ) && appData.debugMode )
fprintf(debugFP, "InitBackEnd1: buffer truncated.\n");
DisplayFatalError(buf, 0, 2);
len = snprintf(buf, MSG_SIZ, _("Could not connect to host %s, port %s"),
appData.icsHost, appData.icsPort);
- if( (len > MSG_SIZ) && appData.debugMode )
+ if( (len >= MSG_SIZ) && appData.debugMode )
fprintf(debugFP, "InitBackEnd3: buffer truncated.\n");
DisplayFatalError(buf, err, 1);
initialMode = Training;
} else {
len = snprintf(buf, MSG_SIZ, _("Unknown initialMode %s"), appData.initialMode);
- if( (len > MSG_SIZ) && appData.debugMode )
+ if( (len >= MSG_SIZ) && appData.debugMode )
fprintf(debugFP, "InitBackEnd3: buffer truncated.\n");
DisplayFatalError(buf, 0, 2);
}
}
+void
+HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
+{
+ DisplayBook(current+1);
+
+ MoveHistorySet( movelist, first, last, current, pvInfoList );
+
+ EvalGraphSet( first, last, current, pvInfoList );
+
+ MakeEngineOutputTitle();
+}
+
/*
* Establish will establish a contact to a remote host.port.
* Sets icsPR to a ProcRef for a process (or pseudo-process)
{
int count, outCount, outError;
- if (icsPR == NULL) return;
+ if (icsPR == NoProc) return;
count = strlen(s);
outCount = OutputMaybeTelnet(icsPR, s, count, &outError);
{
int count, outCount, outError;
- if (icsPR == NULL) return;
+ if (icsPR == NoProc) return;
count = strlen(s);
if (appData.debugMode) {
break;
default:
len = snprintf(buf, MSG_SIZ, _("Unknown wild type %d"), wnum);
- if( (len > MSG_SIZ) && appData.debugMode )
+ if( (len >= MSG_SIZ) && appData.debugMode )
fprintf(debugFP, "StringToVariant: buffer truncated.\n");
DisplayError(buf, 0);
flipView = appData.flipView;
DrawPosition(TRUE, boards[currentMove]);
DisplayBothClocks();
- snprintf(str, MSG_SIZ, "%s vs. %s",
+ snprintf(str, MSG_SIZ, _("%s vs. %s"),
gameInfo.white, gameInfo.black);
DisplayTitle(str);
gameMode = IcsIdle;
strncmp(why, "Continuing ", 11) == 0) {
gs_gamenum = gamenum;
safeStrCpy(gs_kind, strchr(why, ' ') + 1,sizeof(gs_kind)/sizeof(gs_kind[0]));
+ if(ics_gamenum == -1) // [HGM] only if we are not already involved in a game (because gin=1 sends us such messages)
VariantSwitch(boards[currentMove], StringToVariant(gs_kind)); // [HGM] variantswitch: even before we get first board
#if ZIPPY
if (appData.zippyPlay) {
#if ZIPPY
if (appData.zippyPlay && first.initDone) {
ZippyGameEnd(endtype, why);
- if (first.pr == NULL) {
+ if (first.pr == NoProc) {
/* Start the next process early so that we'll
be ready for the next challenge */
StartChessProgram(&first);
char wh[16], bh[16];
PackHolding(wh, white_holding);
PackHolding(bh, black_holding);
- snprintf(str, MSG_SIZ,"[%s-%s] %s-%s", wh, bh,
+ snprintf(str, MSG_SIZ, "[%s-%s] %s-%s", wh, bh,
gameInfo.white, gameInfo.black);
} else {
- snprintf(str, MSG_SIZ, "%s [%s] vs. %s [%s]",
+ snprintf(str, MSG_SIZ, _("%s [%s] vs. %s [%s]"),
gameInfo.white, white_holding,
gameInfo.black, black_holding);
}
basetime, increment, (int) gameInfo.variant);
} else {
if(gameInfo.variant == VariantNormal)
- snprintf(str, MSG_SIZ, "%s (%d) vs. %s (%d) {%d %d}",
+ snprintf(str, MSG_SIZ, _("%s (%d) vs. %s (%d) {%d %d}"),
gameInfo.white, white_stren, gameInfo.black, black_stren,
basetime, increment);
else
- snprintf(str, MSG_SIZ, "%s (%d) vs. %s (%d) {%d %d %s}",
+ snprintf(str, MSG_SIZ, _("%s (%d) vs. %s (%d) {%d %d %s}"),
gameInfo.white, white_stren, gameInfo.black, black_stren,
basetime, increment, VariantName(gameInfo.variant));
}
char promoChar;
{
char user_move[MSG_SIZ];
+ char suffix[4];
+
+ if(gameInfo.variant == VariantSChess && promoChar) {
+ snprintf(suffix, 4, "=%c", toX == BOARD_WIDTH<<1 ? ToUpper(promoChar) : ToLower(promoChar));
+ if(toX == BOARD_WIDTH>>1) moveType = WhitePromotion; // kludge to do gating at Rook
+ } else suffix[0] = NULLCHAR;
switch (moveType) {
default:
case WhiteHSideCastleFR:
case BlackHSideCastleFR:
/* POP Fabien */
- snprintf(user_move, MSG_SIZ, "o-o\n");
+ snprintf(user_move, MSG_SIZ, "o-o%s\n", suffix);
break;
case WhiteQueenSideCastle:
case BlackQueenSideCastle:
case WhiteASideCastleFR:
case BlackASideCastleFR:
/* POP Fabien */
- snprintf(user_move, MSG_SIZ, "o-o-o\n");
+ snprintf(user_move, MSG_SIZ, "o-o-o%s\n",suffix);
break;
case WhiteNonPromotion:
case BlackNonPromotion:
int i, last = forwardMostMove; // make sure ICS reply cannot pre-empt us by clearing fmm
static char *castlingStrings[4] = { "none", "kside", "qside", "both" };
if(gameMode == IcsObserving || gameMode == IcsPlayingBlack || gameMode == IcsPlayingWhite) {
- DisplayError("You cannot do this while you are playing or observing", 0);
- return;
+ DisplayError(_("You cannot do this while you are playing or observing"), 0);
+ return;
}
if(gameMode != IcsExamining) { // is this ever not the case?
char buf[MSG_SIZ], *p, *fen, command[MSG_SIZ], bsetup = 0;
else if((int)promoSweep == -1) promoSweep = WhiteKing;
else if(promoSweep == BlackPawn && step < 0) promoSweep = WhitePawn;
else if(promoSweep == WhiteKing && step > 0) promoSweep = BlackKing;
- if(!step) step = 1;
+ if(!step) step = -1;
} while(PieceToChar(promoSweep) == '.' || PieceToChar(promoSweep) == '~' || promoSweep == pawn ||
appData.testLegality && (promoSweep == king ||
gameInfo.variant == VariantShogi && promoSweep != PROMOTED last && last != PROMOTED promoSweep && last != promoSweep));
int step = 0;
if(promoSweep == EmptySquare || !appData.sweepSelect) return FALSE;
- if(abs(x - lastX) < 15 && abs(y - lastY) < 15) return FALSE;
+ if(abs(x - lastX) < 25 && abs(y - lastY) < 25) return FALSE;
if( y > lastY + 2 ) step = -1; else if(y < lastY - 2) step = 1;
if(!step) return FALSE;
lastX = x; lastY = y;
PvToSAN(char *pv)
{
static char buf[10*MSG_SIZ];
- int i, k=0, savedEnd=endPV;
+ int i, k=0, savedEnd=endPV, saveFMM = forwardMostMove;
*buf = NULLCHAR;
if(forwardMostMove < endPV) PushInner(forwardMostMove, endPV);
ParsePV(pv, FALSE, 2); // this appends PV to game, suppressing any display of it
k += strlen(buf+k);
}
snprintf(buf+k, 10*MSG_SIZ-k, "%s", lastParseAttempt); // if we ran into stuff that could not be parsed, print it verbatim
- if(forwardMostMove < savedEnd) PopInner(0);
+ if(forwardMostMove < savedEnd) { PopInner(0); forwardMostMove = saveFMM; } // PopInner would set fmm to endPV!
endPV = savedEnd;
return buf;
}
void
MovePV(int x, int y, int h)
{ // step through PV based on mouse coordinates (called on mouse move)
- int margin = h>>3, step = 0;
+ int margin = h>>3, step = 0, threshold = (pieceSweep == EmptySquare ? 10 : 15);
// we must somehow check if right button is still down (might be released off board!)
if(endPV < 0 && pieceSweep == EmptySquare) return; // needed in XBoard because lastX/Y is shared :-(
- if(abs(x - lastX) < 7 && abs(y - lastY) < 7) return;
+ if(abs(x - lastX) < threshold && abs(y - lastY) < threshold) return;
if( y > lastY + 2 ) step = -1; else if(y < lastY - 2) step = 1;
if(!step) return;
lastX = x; lastY = y;
gameMode = MachinePlaysBlack;
StartClocks();
SetGameInfo();
- snprintf(buf, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
+ snprintf(buf, MSG_SIZ, _("%s vs. %s"), gameInfo.white, gameInfo.black);
DisplayTitle(buf);
if (first.sendName) {
snprintf(buf, MSG_SIZ,"name %s\n", gameInfo.white);
hisPerpetual = PerpetualChase(k, forwardMostMove);
ourPerpetual = PerpetualChase(k+1, forwardMostMove);
if(ourPerpetual && !hisPerpetual) { // we are actively chasing him: forfeit
+ static char resdet[MSG_SIZ];
result = WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins;
- details = "Xboard adjudication: perpetual chasing";
+ details = resdet;
+ snprintf(resdet, MSG_SIZ, "Xboard adjudication: perpetual chasing of %c%c", ourPerpetual>>8, ourPerpetual&255);
} else
if(hisPerpetual && !ourPerpetual) // he is chasing us, but did not repeat yet
break; // Abort repetition-checking loop.
return; // [HGM] This return was missing, causing option features to be recognized as non-compliant commands!
}
- if (!appData.testLegality && !strncmp(message, "setup ", 6)) { // [HGM] allow first engine to define opening position
+ if ((!appData.testLegality || gameInfo.variant == VariantFairy) &&
+ !strncmp(message, "setup ", 6)) { // [HGM] allow first engine to define opening position
int dummy, s=6; char buf[MSG_SIZ];
- if(appData.icsActive || forwardMostMove != 0 || cps != &first || startedFromSetupPosition) return;
+ if(appData.icsActive || forwardMostMove != 0 || cps != &first) return;
if(sscanf(message, "setup (%s", buf) == 1) s = 8 + strlen(buf), buf[s-9] = NULLCHAR, SetCharTable(pieceToChar, buf);
+ if(startedFromSetupPosition) return;
ParseFEN(boards[0], &dummy, message+s);
DrawPosition(TRUE, boards[0]);
startedFromSetupPosition = TRUE;
if (StrStr(message, "analyze")) {
cps->analysisSupport = FALSE;
cps->analyzing = FALSE;
- Reset(FALSE, TRUE);
+// Reset(FALSE, TRUE); // [HGM] this caused discrepancy between display and internal state!
+ EditGameEvent(); // [HGM] try to preserve loaded game
snprintf(buf2,MSG_SIZ, _("%s does not support analysis"), cps->tidy);
DisplayError(buf2, 0);
return;
if(appData.pvSAN[cps==&second]) pv = PvToSAN(buf1);
+ if(serverMoves && (time > 100 || time == 0 && plylev > 7)) {
+ char buf[MSG_SIZ];
+ FILE *f;
+ snprintf(buf, MSG_SIZ, "%s", appData.serverMovesName);
+ buf[strlen(buf)-1] = gameMode == MachinePlaysWhite ? 'w' :
+ gameMode == MachinePlaysBlack ? 'b' : cps->twoMachinesColor[0];
+ if(appData.debugMode) fprintf(debugFP, "write PV on file '%s'\n", buf);
+ if(f = fopen(buf, "w")) { // export PV to applicable PV file
+ fprintf(f, "%5.2f/%-2d %s", curscore/100., plylev, pv);
+ fclose(f);
+ } else DisplayError(_("failed writing PV"), 0);
+ }
+
tempStats.depth = plylev;
tempStats.nodes = nodes;
tempStats.time = time;
break;
case WhiteDrop:
case BlackDrop:
+ if(currentMoveString[0] == '@') continue; // no null moves in ICS mode!
fromX = moveType == WhiteDrop ?
(int) CharToPiece(ToUpper(currentMoveString[0])) :
(int) CharToPiece(ToLower(currentMoveString[0]));
{
// forwardMostMove++; // [HGM] bare: moved downstream
+ (void) CoordsToAlgebraic(boards[forwardMostMove],
+ PosFlags(forwardMostMove),
+ fromY, fromX, toY, toX, promoChar,
+ parseList[forwardMostMove]);
+
if(serverMoves != NULL) { /* [HGM] write moves on file for broadcasting (should be separate routine, really) */
int timeLeft; static int lastLoadFlag=0; int king, piece;
piece = boards[forwardMostMove][fromY][fromX];
if(gameInfo.variant == VariantKnightmate)
king += (int) WhiteUnicorn - (int) WhiteKing;
if(forwardMostMove == 0) {
- if(blackPlaysFirst)
+ if(gameMode == MachinePlaysBlack || gameMode == BeginningOfGame)
+ fprintf(serverMoves, "%s;", UserName());
+ else if(gameMode == TwoMachinesPlay && first.twoMachinesColor[0] == 'b')
fprintf(serverMoves, "%s;", second.tidy);
fprintf(serverMoves, "%s;", first.tidy);
- if(!blackPlaysFirst)
+ if(gameMode == MachinePlaysWhite)
+ fprintf(serverMoves, "%s;", UserName());
+ else if(gameMode == TwoMachinesPlay && first.twoMachinesColor[0] == 'w')
fprintf(serverMoves, "%s;", second.tidy);
} else fprintf(serverMoves, loadFlag|lastLoadFlag ? ":" : ";");
lastLoadFlag = loadFlag;
fprintf(serverMoves, ":%c%c:%c%c", AAA+fromX, ONE+fromY, AAA+toX, ONE+fromY);
// promotion suffix
if(promoChar != NULLCHAR)
- fprintf(serverMoves, ":%c:%c%c", promoChar, AAA+toX, ONE+toY);
+ fprintf(serverMoves, ":%c:%c%c", ToLower(promoChar), AAA+toX, ONE+toY);
if(!loadFlag) {
+ char buf[MOVE_LEN*2], *p; int len;
fprintf(serverMoves, "/%d/%d",
pvInfoList[forwardMostMove].depth, pvInfoList[forwardMostMove].score);
if(forwardMostMove+1 & 1) timeLeft = whiteTimeRemaining/1000;
else timeLeft = blackTimeRemaining/1000;
fprintf(serverMoves, "/%d", timeLeft);
+ strncpy(buf, parseList[forwardMostMove], MOVE_LEN*2);
+ if(p = strchr(buf, '=')) *p = NULLCHAR;
+ len = strlen(buf); if(len > 1 && buf[len-2] != '-') buf[len-2] = NULLCHAR; // strip to-square
+ fprintf(serverMoves, "/%s", buf);
}
fflush(serverMoves);
}
- if (forwardMostMove+1 > framePtr) { // [HGM] vari: do not run into saved variations
- DisplayFatalError(_("Game too long; increase MAX_MOVES and recompile"),
- 0, 1);
+ if (forwardMostMove+1 > framePtr) { // [HGM] vari: do not run into saved variations..
+ GameEnds(GameUnfinished, _("Game too long; increase MAX_MOVES and recompile"), GE_XBOARD);
return;
}
UnLoadPV(); // [HGM] pv: if we are looking at a PV, abort this
SwitchClocks(forwardMostMove+1); // [HGM] race: incrementing move nr inside
timeRemaining[0][forwardMostMove] = whiteTimeRemaining;
timeRemaining[1][forwardMostMove] = blackTimeRemaining;
+ adjustedClock = FALSE;
gameInfo.result = GameUnfinished;
if (gameInfo.resultDetails != NULL) {
free(gameInfo.resultDetails);
}
CoordsToComputerAlgebraic(fromY, fromX, toY, toX, promoChar,
moveList[forwardMostMove - 1]);
- (void) CoordsToAlgebraic(boards[forwardMostMove - 1],
- PosFlags(forwardMostMove - 1),
- fromY, fromX, toY, toX, promoChar,
- parseList[forwardMostMove - 1]);
switch (MateTest(boards[forwardMostMove], PosFlags(forwardMostMove)) ) {
case MT_NONE:
case MT_STALEMATE:
DrawPosition(FALSE, boards[currentMove]);
DisplayBothClocks();
HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1);
- DisplayBook(currentMove);
}
void SendEgtPath(ChessProgramState *cps)
hintRequested = FALSE;
bookRequested = FALSE;
+ ParseFeatures(appData.features[cps == &second], cps); // [HGM] allow user to overrule features
/* [HGM] some new WB protocol commands to configure engine are sent now, if engine supports them */
/* moved to before sending initstring in 4.3.15, so Polyglot can delay UCI 'isready' to recepton of 'new' */
if(cps->memSize) { /* [HGM] memory */
fprintf(f, "-loadPositionFile \"%s\"\n", appData.loadPositionFile);
fprintf(f, "-loadPositionIndex %d\n", appData.loadPositionIndex);
fprintf(f, "-rewindIndex %d\n", appData.rewindIndex);
+ fprintf(f, "-discourageOwnBooks %s\n", appData.defNoBook ? "true" : "false");
if(searchTime > 0)
fprintf(f, "-searchTime \"%d:%02d\"\n", searchTime/60, searchTime%60);
else {
SWAP(logo, p)
SWAP(pgnName, p)
SWAP(pvSAN, h)
+ SWAP(engOptions, p)
}
void
for(i=1; command[i]; i++) if(!strcmp(mnemonic[i], engineName)) break;
if(mnemonic[i]) {
snprintf(buf, MSG_SIZ, "-fcp %s", command[i]);
- ParseArgsFromString(resetOptions); appData.fenOverride[0] = NULL;
+ ParseArgsFromString(resetOptions); appData.fenOverride[0] = NULL; appData.pvSAN[0] = FALSE;
+ appData.firstHasOwnBookUCI = !appData.defNoBook;
ParseArgsFromString(buf);
}
free(engineName);
matchGame = 1; roundNr = nr / syncInterval + 1;
}
- if(first.pr != NoProc) return 1; // engines already loaded
+ if(first.pr != NoProc || second.pr != NoProc) return 1; // engines already loaded
// redefine engines, engine dir, etc.
NamesToList(firstChessProgramNames, command, mnemonic); // get mnemonics of installed engines
void
NextMatchGame()
{ // performs game initialization that does not invoke engines, and then tries to start the game
- int firstWhite, swapColors = 0;
+ int res, firstWhite, swapColors = 0;
if(!NextTourneyGame(nextGame, &swapColors)) return; // this sets matchGame, -fcp / -scp and other options for next game, if needed
firstWhite = appData.firstPlaysBlack ^ (matchGame & 1 | appData.sameColorGames > 1); // non-incremental default
firstWhite ^= swapColors; // reverses if NextTourneyGame says we are in an odd round
appData.noChessProgram = (first.pr == NoProc); // kludge to prevent Reset from starting up chess program
if(appData.loadGameIndex == -2) srandom(appData.seedBase + 68163*(nextGame & ~1)); // deterministic seed to force same opening
Reset(FALSE, first.pr != NoProc);
- appData.noChessProgram = FALSE;
- if(!LoadGameOrPosition(matchGame)) return; // setup game; abort when bad game/pos file
+ res = LoadGameOrPosition(matchGame); // setup game
+ appData.noChessProgram = FALSE; // LoadGameOrPosition might call Reset too!
+ if(!res) return; // abort when bad game/pos file
TwoMachinesEvent();
}
if(result==WhiteWins) c = '+';
if(result==BlackWins) c = '-';
if(resultDetails != NULL)
- fprintf(serverMoves, ";%c;%s\n", c, resultDetails);
+ fprintf(serverMoves, ";%c;%s\n", c, resultDetails), fflush(serverMoves);
}
if (resultDetails != NULL) {
gameInfo.result = result;
if(waitingForGame) resChar = ' '; // quit while waiting for round sync: unreserve already reserved game
if(appData.tourneyFile[0]){ // [HGM] we are in a tourney; update tourney file with game result
+ if(appData.afterGame && appData.afterGame[0]) RunCommand(appData.afterGame);
ReserveGame(nextGame, resChar); // sets nextGame
if(nextGame > appData.matchGames) appData.tourneyFile[0] = 0, ranking = TourneyStandings(3); // tourney is done
else ranking = strdup("busy"); //suppress popup when aborted but not finished
first.matchWins, second.matchWins,
appData.matchGames - (first.matchWins + second.matchWins));
if(!appData.tourneyFile[0]) matchGame++, DisplayTwoMachinesTitle(); // [HGM] update result in window title
+ if(strcmp(ranking, "busy") && appData.afterTourney && appData.afterTourney[0]) RunCommand(appData.afterTourney);
popupRequested++; // [HGM] crash: postpone to after resetting endingGame
if (appData.firstPlaysBlack) { // [HGM] match: back to original for next match
first.twoMachinesColor = "black\n";
timeRemaining[0][0] = whiteTimeRemaining;
timeRemaining[1][0] = blackTimeRemaining;
- if (first.pr == NULL) {
+ if (first.pr == NoProc) {
StartChessProgram(&first);
}
if (init) {
return TRUE;
}
+#define Q_PROMO 4
+#define Q_EP 3
+#define Q_BCASTL 2
+#define Q_WCASTL 1
+
+int pieceList[256], quickBoard[256];
+ChessSquare pieceType[256] = { EmptySquare };
+Board soughtBoard, reverseBoard, flipBoard, rotateBoard;
+int counts[EmptySquare], minSought[EmptySquare], minReverse[EmptySquare], maxSought[EmptySquare], maxReverse[EmptySquare];
+int soughtTotal, turn;
+Boolean epOK, flipSearch;
+
+typedef struct {
+ unsigned char piece, to;
+} Move;
+
+#define DSIZE (250000)
+
+Move initialSpace[DSIZE+1000]; // gamble on that game will not be more than 500 moves
+Move *moveDatabase = initialSpace;
+unsigned int movePtr, dataSize = DSIZE;
+
+int MakePieceList(Board board, int *counts)
+{
+ int r, f, n=Q_PROMO, total=0;
+ for(r=0;r<EmptySquare;r++) counts[r] = 0; // piece-type counts
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+ int sq = f + (r<<4);
+ if(board[r][f] == EmptySquare) quickBoard[sq] = 0; else {
+ quickBoard[sq] = ++n;
+ pieceList[n] = sq;
+ pieceType[n] = board[r][f];
+ counts[board[r][f]]++;
+ if(board[r][f] == WhiteKing) pieceList[1] = n; else
+ if(board[r][f] == BlackKing) pieceList[2] = n; // remember which are Kings, for castling
+ total++;
+ }
+ }
+ epOK = gameInfo.variant != VariantXiangqi && gameInfo.variant != VariantBerolina;
+ return total;
+}
+
+void PackMove(int fromX, int fromY, int toX, int toY, ChessSquare promoPiece)
+{
+ int sq = fromX + (fromY<<4);
+ int piece = quickBoard[sq];
+ quickBoard[sq] = 0;
+ moveDatabase[movePtr].to = pieceList[piece] = sq = toX + (toY<<4);
+ if(piece == pieceList[1] && fromY == toY && (toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
+ int from = toX>fromX ? BOARD_RGHT-1 : BOARD_LEFT;
+ moveDatabase[movePtr++].piece = Q_WCASTL;
+ quickBoard[sq] = piece;
+ piece = quickBoard[from]; quickBoard[from] = 0;
+ moveDatabase[movePtr].to = pieceList[piece] = sq = toX>fromX ? sq-1 : sq+1;
+ } else
+ if(piece == pieceList[2] && fromY == toY && (toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
+ int from = (toX>fromX ? BOARD_RGHT-1 : BOARD_LEFT) + (BOARD_HEIGHT-1 <<4);
+ moveDatabase[movePtr++].piece = Q_BCASTL;
+ quickBoard[sq] = piece;
+ piece = quickBoard[from]; quickBoard[from] = 0;
+ moveDatabase[movePtr].to = pieceList[piece] = sq = toX>fromX ? sq-1 : sq+1;
+ } else
+ if(epOK && (pieceType[piece] == WhitePawn || pieceType[piece] == BlackPawn) && fromX != toX && quickBoard[sq] == 0) {
+ quickBoard[(fromY<<4)+toX] = 0;
+ moveDatabase[movePtr].piece = Q_EP;
+ moveDatabase[movePtr++].to = (fromY<<4)+toX;
+ moveDatabase[movePtr].to = sq;
+ } else
+ if(promoPiece != pieceType[piece]) {
+ moveDatabase[movePtr++].piece = Q_PROMO;
+ moveDatabase[movePtr].to = pieceType[piece] = (int) promoPiece;
+ }
+ moveDatabase[movePtr].piece = piece;
+ quickBoard[sq] = piece;
+ movePtr++;
+}
+
+int PackGame(Board board)
+{
+ Move *newSpace = NULL;
+ moveDatabase[movePtr].piece = 0; // terminate previous game
+ if(movePtr > dataSize) {
+ if(appData.debugMode) fprintf(debugFP, "move-cache overflow, enlarge to %d MB\n", dataSize/128);
+ dataSize *= 8; // increase size by factor 8 (512KB -> 4MB -> 32MB -> 256MB -> 2GB)
+ if(dataSize) newSpace = (Move*) calloc(8*dataSize + 1000, sizeof(Move));
+ if(newSpace) {
+ int i;
+ Move *p = moveDatabase, *q = newSpace;
+ for(i=0; i<movePtr; i++) *q++ = *p++; // copy to newly allocated space
+ if(dataSize > 8*DSIZE) free(moveDatabase); // and free old space (if it was allocated)
+ moveDatabase = newSpace;
+ } else { // calloc failed, we must be out of memory. Too bad...
+ dataSize = 0; // prevent calloc events for all subsequent games
+ return 0; // and signal this one isn't cached
+ }
+ }
+ movePtr++;
+ MakePieceList(board, counts);
+ return movePtr;
+}
+
+int QuickCompare(Board board, int *minCounts, int *maxCounts)
+{ // compare according to search mode
+ int r, f;
+ switch(appData.searchMode)
+ {
+ case 1: // exact position match
+ if(!(turn & board[EP_STATUS-1])) return FALSE; // wrong side to move
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+ if(board[r][f] != pieceType[quickBoard[(r<<4)+f]]) return FALSE;
+ }
+ break;
+ case 2: // can have extra material on empty squares
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+ if(board[r][f] == EmptySquare) continue;
+ if(board[r][f] != pieceType[quickBoard[(r<<4)+f]]) return FALSE;
+ }
+ break;
+ case 3: // material with exact Pawn structure
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+ if(board[r][f] != WhitePawn && board[r][f] != BlackPawn) continue;
+ if(board[r][f] != pieceType[quickBoard[(r<<4)+f]]) return FALSE;
+ } // fall through to material comparison
+ case 4: // exact material
+ for(r=0; r<EmptySquare; r++) if(counts[r] != maxCounts[r]) return FALSE;
+ break;
+ case 6: // material range with given imbalance
+ for(r=0; r<BlackPawn; r++) if(counts[r] - minCounts[r] != counts[r+BlackPawn] - minCounts[r+BlackPawn]) return FALSE;
+ // fall through to range comparison
+ case 5: // material range
+ for(r=0; r<EmptySquare; r++) if(counts[r] < minCounts[r] || counts[r] > maxCounts[r]) return FALSE;
+ }
+ return TRUE;
+}
+
+int QuickScan(Board board, Move *move)
+{ // reconstruct game,and compare all positions in it
+ int cnt=0, stretch=0, total = MakePieceList(board, counts);
+ do {
+ int piece = move->piece;
+ int to = move->to, from = pieceList[piece];
+ if(piece <= Q_PROMO) { // special moves encoded by otherwise invalid piece numbers 1-4
+ if(!piece) return -1;
+ if(piece == Q_PROMO) { // promotion, encoded as (Q_PROMO, to) + (piece, promoType)
+ piece = (++move)->piece;
+ from = pieceList[piece];
+ counts[pieceType[piece]]--;
+ pieceType[piece] = (ChessSquare) move->to;
+ counts[move->to]++;
+ } else if(piece == Q_EP) { // e.p. capture, encoded as (Q_EP, ep-sqr) + (piece, to)
+ counts[pieceType[quickBoard[to]]]--;
+ quickBoard[to] = 0; total--;
+ move++;
+ continue;
+ } else if(piece <= Q_BCASTL) { // castling, encoded as (Q_XCASTL, king-to) + (rook, rook-to)
+ piece = pieceList[piece]; // first two elements of pieceList contain King numbers
+ from = pieceList[piece]; // so this must be King
+ quickBoard[from] = 0;
+ quickBoard[to] = piece;
+ pieceList[piece] = to;
+ move++;
+ continue;
+ }
+ }
+ if(appData.searchMode > 2) counts[pieceType[quickBoard[to]]]--; // account capture
+ if((total -= (quickBoard[to] != 0)) < soughtTotal) return -1; // piece count dropped below what we search for
+ quickBoard[from] = 0;
+ quickBoard[to] = piece;
+ pieceList[piece] = to;
+ cnt++; turn ^= 3;
+ if(QuickCompare(soughtBoard, minSought, maxSought) ||
+ appData.ignoreColors && QuickCompare(reverseBoard, minReverse, maxReverse) ||
+ flipSearch && (QuickCompare(flipBoard, minSought, maxSought) ||
+ appData.ignoreColors && QuickCompare(rotateBoard, minReverse, maxReverse))
+ ) {
+ static int lastCounts[EmptySquare+1];
+ int i;
+ if(stretch) for(i=0; i<EmptySquare; i++) if(lastCounts[i] != counts[i]) { stretch = 0; break; } // reset if material changes
+ if(stretch++ == 0) for(i=0; i<EmptySquare; i++) lastCounts[i] = counts[i]; // remember actual material
+ } else stretch = 0;
+ if(stretch && (appData.searchMode == 1 || stretch >= appData.stretch)) return cnt + 1 - stretch;
+ move++;
+ } while(1);
+}
+
+void InitSearch()
+{
+ int r, f;
+ flipSearch = FALSE;
+ CopyBoard(soughtBoard, boards[currentMove]);
+ soughtTotal = MakePieceList(soughtBoard, maxSought);
+ soughtBoard[EP_STATUS-1] = (currentMove & 1) + 1;
+ if(currentMove == 0 && gameMode == EditPosition) soughtBoard[EP_STATUS-1] = blackPlaysFirst + 1; // (!)
+ CopyBoard(reverseBoard, boards[currentMove]);
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+ int piece = boards[currentMove][BOARD_HEIGHT-1-r][f];
+ if(piece < BlackPawn) piece += BlackPawn; else if(piece < EmptySquare) piece -= BlackPawn; // color-flip
+ reverseBoard[r][f] = piece;
+ }
+ reverseBoard[EP_STATUS-1] = soughtBoard[EP_STATUS-1] ^ 3;
+ for(r=0; r<6; r++) reverseBoard[CASTLING][r] = boards[currentMove][CASTLING][(r+3)%6];
+ if(appData.findMirror && appData.searchMode <= 3 && (!nrCastlingRights
+ || (boards[currentMove][CASTLING][2] == NoRights ||
+ boards[currentMove][CASTLING][0] == NoRights && boards[currentMove][CASTLING][1] == NoRights )
+ && (boards[currentMove][CASTLING][5] == NoRights ||
+ boards[currentMove][CASTLING][3] == NoRights && boards[currentMove][CASTLING][4] == NoRights ) )
+ ) {
+ flipSearch = TRUE;
+ CopyBoard(flipBoard, soughtBoard);
+ CopyBoard(rotateBoard, reverseBoard);
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+ flipBoard[r][f] = soughtBoard[r][BOARD_WIDTH-1-f];
+ rotateBoard[r][f] = reverseBoard[r][BOARD_WIDTH-1-f];
+ }
+ }
+ for(r=0; r<BlackPawn; r++) maxReverse[r] = maxSought[r+BlackPawn], maxReverse[r+BlackPawn] = maxSought[r];
+ if(appData.searchMode >= 5) {
+ for(r=BOARD_HEIGHT/2; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) soughtBoard[r][f] = EmptySquare;
+ MakePieceList(soughtBoard, minSought);
+ for(r=0; r<BlackPawn; r++) minReverse[r] = minSought[r+BlackPawn], minReverse[r+BlackPawn] = minSought[r];
+ }
+ if(gameInfo.variant == VariantCrazyhouse || gameInfo.variant == VariantShogi || gameInfo.variant == VariantBughouse)
+ soughtTotal = 0; // in drop games nr of pieces does not fall monotonously
+}
+
GameInfo dummyInfo;
int GameContainsPosition(FILE *f, ListGame *lg)
char promoChar;
static int initDone=FALSE;
+ // weed out games based on numerical tag comparison
+ if(lg->gameInfo.variant != gameInfo.variant) return -1; // wrong variant
+ if(appData.eloThreshold1 && (lg->gameInfo.whiteRating < appData.eloThreshold1 && lg->gameInfo.blackRating < appData.eloThreshold1)) return -1;
+ if(appData.eloThreshold2 && (lg->gameInfo.whiteRating < appData.eloThreshold2 || lg->gameInfo.blackRating < appData.eloThreshold2)) return -1;
+ if(appData.dateThreshold && (!lg->gameInfo.date || atoi(lg->gameInfo.date) < appData.dateThreshold)) return -1;
if(!initDone) {
for(next = WhitePawn; next<EmptySquare; next++) keys[next] = random()>>8 ^ random()<<6 ^random()<<20;
initDone = TRUE;
}
- dummyInfo.variant = VariantNormal;
- FREE(dummyInfo.fen); dummyInfo.fen = NULL;
- dummyInfo.whiteRating = 0;
- dummyInfo.blackRating = 0;
- FREE(dummyInfo.date); dummyInfo.date = NULL;
+ if(lg->gameInfo.fen) ParseFEN(boards[scratch], &btm, lg->gameInfo.fen);
+ else CopyBoard(boards[scratch], initialPosition); // default start position
+ if(lg->moves) {
+ turn = btm + 1;
+ if((next = QuickScan( boards[scratch], &moveDatabase[lg->moves] )) < 0) return -1; // quick scan rules out it is there
+ if(appData.searchMode >= 4) return next; // for material searches, trust QuickScan.
+ }
+ if(btm) plyNr++;
+ if(PositionMatches(boards[scratch], boards[currentMove])) return plyNr;
fseek(f, lg->offset, 0);
yynewfile(f);
- CopyBoard(boards[scratch], initialPosition); // default start position
while(1) {
- yyboardindex = scratch + (plyNr&1);
- quickFlag = 1;
+ yyboardindex = scratch;
+ quickFlag = plyNr+1;
next = Myylex();
- quickFlag = 0;
+ quickFlag = 0;
switch(next) {
case PGNTag:
if(plyNr) return -1; // after we have seen moves, any tags will be start of next game
-#if 0
- ParsePGNTag(yy_text, &dummyInfo); // this has a bad memory leak...
- if(dummyInfo.fen) ParseFEN(boards[scratch], &btm, dummyInfo.fen), free(dummyInfo.fen), dummyInfo.fen = NULL;
-#else
- // do it ourselves avoiding malloc
- { char *p = yy_text+1, *q;
- while(!isdigit(*p) && !isalpha(*p)) p++;
- q = p; while(*p != ' ' && *p != '\t' && *p != '\n') p++;
- *p = NULLCHAR;
- if(!StrCaseCmp(q, "Date") && (p = strchr(p+1, '"'))) { if(atoi(p+1) < appData.dateThreshold) return -1; } else
- if(!StrCaseCmp(q, "Variant") && (p = strchr(p+1, '"'))) dummyInfo.variant = StringToVariant(p+1); else
- if(!StrCaseCmp(q, "WhiteElo") && (p = strchr(p+1, '"'))) dummyInfo.whiteRating = atoi(p+1); else
- if(!StrCaseCmp(q, "BlackElo") && (p = strchr(p+1, '"'))) dummyInfo.blackRating = atoi(p+1); else
- if(!StrCaseCmp(q, "WhiteUSCF") && (p = strchr(p+1, '"'))) dummyInfo.whiteRating = atoi(p+1); else
- if(!StrCaseCmp(q, "BlackUSCF") && (p = strchr(p+1, '"'))) dummyInfo.blackRating = atoi(p+1); else
- if(!StrCaseCmp(q, "FEN") && (p = strchr(p+1, '"'))) ParseFEN(boards[scratch], &btm, p+1);
- }
-#endif
default:
continue;
fromY = DROP_RANK;
toX = currentMoveString[2] - AAA;
toY = currentMoveString[3] - ONE;
+ promoChar = 0;
break;
}
// Move encountered; peform it. We need to shuttle between two boards, as even/odd index determines side to move
- if(plyNr == 0) { // but first figure out variant and initial position
- if(dummyInfo.variant != gameInfo.variant) return -1; // wrong variant
- if(appData.eloThreshold1 && (dummyInfo.whiteRating < appData.eloThreshold1 && dummyInfo.blackRating < appData.eloThreshold1)) return -1;
- if(appData.eloThreshold2 && (dummyInfo.whiteRating < appData.eloThreshold2 || dummyInfo.blackRating < appData.eloThreshold2)) return -1;
- if(appData.dateThreshold && (!dummyInfo.date || atoi(dummyInfo.date) < appData.dateThreshold)) return -1;
- if(btm) CopyBoard(boards[scratch+1], boards[scratch]), plyNr++;
- if(PositionMatches(boards[scratch + plyNr], boards[currentMove])) return plyNr;
- }
- CopyBoard(boards[scratch + (plyNr+1&1)], boards[scratch + (plyNr&1)]);
plyNr++;
- ApplyMove(fromX, fromY, toX, toY, promoChar, boards[scratch + (plyNr&1)]);
- if(PositionMatches(boards[scratch + (plyNr&1)], boards[currentMove])) return plyNr;
+ ApplyMove(fromX, fromY, toX, toY, promoChar, boards[scratch]);
+ if(PositionMatches(boards[scratch], boards[currentMove])) return plyNr;
+ if(appData.ignoreColors && PositionMatches(boards[scratch], reverseBoard)) return plyNr;
+ if(appData.findMirror) {
+ if(PositionMatches(boards[scratch], flipBoard)) return plyNr;
+ if(appData.ignoreColors && PositionMatches(boards[scratch], rotateBoard)) return plyNr;
+ }
}
}
yynewfile(f);
if (lg && lg->gameInfo.white && lg->gameInfo.black) {
- snprintf(buf, sizeof(buf), "%s vs. %s", lg->gameInfo.white,
+ snprintf(buf, sizeof(buf), _("%s vs. %s"), lg->gameInfo.white,
lg->gameInfo.black);
DisplayTitle(buf);
} else if (*title != NULLCHAR) {
lastLoadPositionFP = f;
lastLoadPositionNumber = positionNumber;
safeStrCpy(lastLoadPositionTitle, title, sizeof(lastLoadPositionTitle)/sizeof(lastLoadPositionTitle[0]));
- if (first.pr == NoProc) {
+ if (first.pr == NoProc && !appData.noChessProgram) {
StartChessProgram(&first);
InitChessProgram(&first, FALSE);
}
}
startedFromSetupPosition = TRUE;
- SendToProgram("force\n", &first);
CopyBoard(boards[0], initial_position);
if (blackPlaysFirst) {
currentMove = forwardMostMove = backwardMostMove = 1;
DisplayMessage("", _("White to play"));
}
initialRulePlies = FENrulePlies; /* [HGM] copy FEN attributes as well */
- SendBoard(&first, forwardMostMove);
+ if(first.pr != NoProc) { // [HGM] in tourney-mode a position can be loaded before the chess engine is installed
+ SendToProgram("force\n", &first);
+ SendBoard(&first, forwardMostMove);
+ }
if (appData.debugMode) {
int i, j;
for(i=0;i<2;i++){for(j=0;j<6;j++)fprintf(debugFP, " %d", boards[i][CASTLING][j]);fprintf(debugFP,"\n");}
{
FILE *f;
char buf[MSG_SIZ];
- int result;
+ int result, i, t,tot=0;
if (strcmp(filename, "-") == 0) {
return SaveGame(stdout, 0, NULL);
} else {
- f = fopen(filename, append ? "a" : "w");
+ for(i=0; i<10; i++) { // upto 10 tries
+ f = fopen(filename, append ? "a" : "w");
+ if(f && i) fprintf(f, "[Delay \"%d retries, %d msec\"]\n",i,tot);
+ if(f || errno != 13) break;
+ DoSleep(t = 5 + random()%11); // wait 5-15 msec
+ tot += t;
+ }
if (f == NULL) {
snprintf(buf, sizeof(buf), _("Can't open \"%s\""), filename);
DisplayError(buf, errno);
DisplayMessage(_("Waiting for access to save file"), "");
flock(fileno(f), LOCK_EX); // [HGM] lock: lock file while we are writing
DisplayMessage(_("Saving game"), "");
- if(lseek(fileno(f), 0, SEEK_END) == -1) DisplayError("Bad Seek", errno); // better safe than sorry...
+ if(lseek(fileno(f), 0, SEEK_END) == -1) DisplayError(_("Bad Seek"), errno); // better safe than sorry...
result = SaveGame(f, 0, NULL);
DisplayMessage(buf, "");
return result;
StartAnalysisClock();
GetTimeMark(&lastNodeCountTime);
lastNodeCount = 0;
+ if(appData.timeDelay > 0) StartLoadGameTimer((long)(1000.0 * appData.timeDelay));
}
void
pausing = FALSE;
ModeHighlight();
SetGameInfo();
- snprintf(buf, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
+ snprintf(buf, MSG_SIZ, _("%s vs. %s"), gameInfo.white, gameInfo.black);
DisplayTitle(buf);
if (first.sendName) {
snprintf(buf, MSG_SIZ, "name %s\n", gameInfo.black);
pausing = FALSE;
ModeHighlight();
SetGameInfo();
- snprintf(buf, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
+ snprintf(buf, MSG_SIZ, _("%s vs. %s"), gameInfo.white, gameInfo.black);
DisplayTitle(buf);
if (first.sendName) {
snprintf(buf, MSG_SIZ, "name %s\n", gameInfo.white);
char buf[MSG_SIZ];
if (appData.matchGames > 0) {
if(appData.tourneyFile[0]) {
- snprintf(buf, MSG_SIZ, "%s vs. %s (%d/%d%s)",
+ snprintf(buf, MSG_SIZ, _("%s vs. %s (%d/%d%s)"),
gameInfo.white, gameInfo.black,
nextGame+1, appData.matchGames+1,
appData.tourneyType>0 ? "gt" : appData.tourneyType<0 ? "sw" : "rr");
} else
if (first.twoMachinesColor[0] == 'w') {
- snprintf(buf, MSG_SIZ, "%s vs. %s (%d-%d-%d)",
+ snprintf(buf, MSG_SIZ, _("%s vs. %s (%d-%d-%d)"),
gameInfo.white, gameInfo.black,
first.matchWins, second.matchWins,
matchGame - 1 - (first.matchWins + second.matchWins));
} else {
- snprintf(buf, MSG_SIZ, "%s vs. %s (%d-%d-%d)",
+ snprintf(buf, MSG_SIZ, _("%s vs. %s (%d-%d-%d)"),
gameInfo.white, gameInfo.black,
second.matchWins, first.matchWins,
matchGame - 1 - (first.matchWins + second.matchWins));
}
} else {
- snprintf(buf, MSG_SIZ, "%s vs. %s", gameInfo.white, gameInfo.black);
+ snprintf(buf, MSG_SIZ, _("%s vs. %s"), gameInfo.white, gameInfo.black);
}
DisplayTitle(buf);
}
WaitForEngine(ChessProgramState *cps, DelayedEventCallback retry)
{
char buf[MSG_SIZ];
- if (cps->pr == NULL) {
+ if (cps->pr == NoProc) {
StartChessProgram(cps);
if (cps->protocolVersion == 1) {
retry();
SendToProgram("undo\n", &first);
i--;
}
+ if(!adjustedClock) {
whiteTimeRemaining = timeRemaining[0][currentMove];
blackTimeRemaining = timeRemaining[1][currentMove];
DisplayBothClocks();
+ }
if (whiteFlag || blackFlag) {
whiteFlag = blackFlag = 0;
}
if (gameMode == EditPosition)
return;
+ MarkTargetSquares(1);
+
if (gameMode == PlayFromGameFile && !pausing)
PauseEvent();
if ( !matchMode && gameMode != Training) { // [HGM] PV info: routine tests if empty
DisplayComment(currentMove - 1, commentList[currentMove]);
}
- DisplayBook(currentMove);
}
target, currentMove, forwardMostMove);
if (gameMode == EditPosition) return;
+ MarkTargetSquares(1);
if (currentMove <= backwardMostMove) {
ClearHighlights();
DrawPosition(full_redraw, boards[currentMove]);
HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1);
// [HGM] PV info: routine tests if comment empty
DisplayComment(currentMove - 1, commentList[currentMove]);
- DisplayBook(currentMove);
}
void
if (len == 0) return;
if (commentList[index] != NULL) {
+ Boolean addClosingBrace = addBraces;
old = commentList[index];
oldlen = strlen(old);
while(commentList[index][oldlen-1] == '\n')
if(addBraces) strcat(commentList[index], addBraces == 2 ? "\n(" : "\n{\n");
else strcat(commentList[index], "\n");
strcat(commentList[index], text);
- if(addBraces) strcat(commentList[index], addBraces == 2 ? ")\n" : "\n}\n");
+ if(addClosingBrace) strcat(commentList[index], addClosingBrace == 2 ? ")\n" : "\n}\n");
else strcat(commentList[index], "\n");
} else {
commentList[index] = (char *) malloc(len + 6); // perhaps wastes 4...
while( *++sep >= '0' && *sep <= '9'); // strip seconds
if(deci >= 0)
while( *++sep >= '0' && *sep <= '9'); // strip fractional seconds
- while(*sep == ' ') sep++;
+ while(*sep == ' ' || *sep == '\n' || *sep == '\r') sep++;
}
if( depth <= 0 ) {
int count, outCount, error;
char buf[MSG_SIZ];
- if (cps->pr == NULL) return;
+ if (cps->pr == NoProc) return;
Attention(cps);
if (appData.debugMode) {
void
AdjustClock(Boolean which, int dir)
{
+ if(appData.autoCallFlag) { DisplayError(_("Clock adjustment not allowed in auto-flag mode"), 0); return; }
if(which) blackTimeRemaining += 60000*dir;
else whiteTimeRemaining += 60000*dir;
DisplayBothClocks();
+ adjustedClock = TRUE;
}
/* Stop clocks and reset to a fresh time control */
}
lastWhite = lastBlack = whiteStartMove = blackStartMove = 0;
DisplayBothClocks();
+ adjustedClock = FALSE;
}
#define FUDGE 25 /* 25ms = 1/40 sec; should be plenty even for 50 Hz clocks */