void DisplayTwoMachinesTitle P(());
static void ExcludeClick P((int index));
void ToggleSecond P((void));
+void PauseEngine P((ChessProgramState *cps));
#ifdef WIN32
extern void ConsoleCreate();
Boolean valid;
int nr = 0;
- if (gameMode == AnalyzeMode && currentMove < forwardMostMove) {
+ lastParseAttempt = pv; if(!*pv) return; // turns out we crash when we parse an empty PV
+ if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) && currentMove < forwardMostMove) {
PushInner(currentMove, forwardMostMove); // [HGM] engine might not be thinking on forwardMost position!
pushed = TRUE;
}
static char buf[10*MSG_SIZ];
int i, k=0, savedEnd=endPV, saveFMM = forwardMostMove;
*buf = NULLCHAR;
- if(forwardMostMove < endPV) PushInner(forwardMostMove, endPV);
+ if(forwardMostMove < endPV) PushInner(forwardMostMove, endPV); // shelve PV of PV-walk
ParsePV(pv, FALSE, 2); // this appends PV to game, suppressing any display of it
for(i = forwardMostMove; i<endPV; i++){
if(i&1) snprintf(buf+k, 10*MSG_SIZ-k, "%s ", parseList[i]);
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(pushed) { PopInner(0); pushed = FALSE; } // restore game continuation shelved by ParsePV
if(forwardMostMove < savedEnd) { PopInner(0); forwardMostMove = saveFMM; } // PopInner would set fmm to endPV!
endPV = savedEnd;
return buf;
}
static int savedWhitePlayer, savedBlackPlayer, pairingReceived;
+static ChessProgramState *stalledEngine;
+static char stashedInputMove[MSG_SIZ];
void
HandleMachineMove (char *message, ChessProgramState *cps)
if ((sscanf(message, "%s %s %s", buf1, buf2, machineMove) == 3 && strcmp(buf2, "...") == 0) ||
(sscanf(message, "%s %s", buf1, machineMove) == 2 && strcmp(buf1, "move") == 0))
{
+ if(pausing && !cps->pause) { // for pausing engine that does not support 'pause', we stash its move for processing when we resume.
+ if(appData.debugMode) fprintf(debugFP, "pause %s engine after move\n", cps->which);
+ safeStrCpy(stashedInputMove, message, MSG_SIZ);
+ stalledEngine = cps;
+ if(appData.ponderNextMove) { // bring opponent out of ponder
+ if(gameMode == TwoMachinesPlay) {
+ if(cps->other->pause)
+ PauseEngine(cps->other);
+ else
+ SendToProgram("easy\n", cps->other);
+ }
+ }
+ StopClocks();
+ return;
+ }
+
/* This method is only useful on engines that support ping */
if (cps->lastPing != cps->lastPong) {
if (gameMode == BeginningOfGame) {
fromX = fromY = -1; // [HGM] abort any move the user is entering.
+ if(pausing) PauseEvent(); // can happen when we abort a paused game (New Game or Quit)
+
if (appData.icsActive && (whosays == GE_ENGINE || whosays >= GE_ENGINE1)) {
/* If we are playing on ICS, the server decides when the
game is over, but the engine can offer to draw, claim
if (oldGameMode == AnalyzeFile ||
oldGameMode == AnalyzeMode) {
appData.loadGameIndex = -1; // [HGM] order auto-stepping through games
- keepInfo = 1;
AnalyzeFileEvent();
- keepInfo = 0;
}
if(creatingBook) return TRUE;
}
void
+PauseEngine (ChessProgramState *cps)
+{
+ SendToProgram("pause\n", cps);
+ cps->pause = 2;
+}
+
+void
+UnPauseEngine (ChessProgramState *cps)
+{
+ SendToProgram("resume\n", cps);
+ cps->pause = 1;
+}
+
+void
PauseEvent ()
{
if (appData.debugMode)
if (pausing) {
pausing = FALSE;
ModeHighlight();
+ if(stalledEngine) { // [HGM] pause: resume game by releasing withheld move
+ StartClocks();
+ if(gameMode == TwoMachinesPlay) { // we might have to make the opponent resume pondering
+ if(stalledEngine->other->pause == 2) UnPauseEngine(stalledEngine->other);
+ else if(appData.ponderNextMove) SendToProgram("hard\n", stalledEngine->other);
+ }
+ if(appData.ponderNextMove) SendToProgram("hard\n", stalledEngine);
+ HandleMachineMove(stashedInputMove, stalledEngine);
+ stalledEngine = NULL;
+ return;
+ }
if (gameMode == MachinePlaysWhite ||
- gameMode == MachinePlaysBlack) {
+ gameMode == TwoMachinesPlay ||
+ gameMode == MachinePlaysBlack) { // the thinking engine must have used pause mode, or it would have been stalledEngine
+ if(first.pause) UnPauseEngine(&first);
+ else if(appData.ponderNextMove) SendToProgram("hard\n", &first);
+ if(second.pause) UnPauseEngine(&second);
+ else if(gameMode == TwoMachinesPlay && appData.ponderNextMove) SendToProgram("hard\n", &second);
StartClocks();
} else {
DisplayBothClocks();
case TwoMachinesPlay:
if (forwardMostMove == 0)
return; /* don't pause if no one has moved */
- if ((gameMode == MachinePlaysWhite &&
- !WhiteOnMove(forwardMostMove)) ||
- (gameMode == MachinePlaysBlack &&
- WhiteOnMove(forwardMostMove))) {
+ if(gameMode == TwoMachinesPlay) { // [HGM] pause: stop clocks if engine can be paused immediately
+ ChessProgramState *onMove = (WhiteOnMove(forwardMostMove) == (first.twoMachinesColor[0] == 'w') ? &first : &second);
+ if(onMove->pause) { // thinking engine can be paused
+ PauseEngine(onMove); // do it
+ if(onMove->other->pause) // pondering opponent can always be paused immediately
+ PauseEngine(onMove->other);
+ else
+ SendToProgram("easy\n", onMove->other);
+ StopClocks();
+ } else if(appData.ponderNextMove) SendToProgram("easy\n", onMove); // pre-emptively bring out of ponder
+ } else if(gameMode == (WhiteOnMove(forwardMostMove) ? MachinePlaysWhite : MachinePlaysBlack)) { // engine on move
+ if(first.pause) {
+ PauseEngine(&first);
+ StopClocks();
+ } else if(appData.ponderNextMove) SendToProgram("easy\n", &first); // pre-emptively bring out of ponder
+ } else { // human on move, pause pondering by either method
+ if(first.pause)
+ PauseEngine(&first);
+ else if(appData.ponderNextMove)
+ SendToProgram("easy\n", &first);
StopClocks();
}
+ // if no immediate pausing is possible, wait for engine to move, and stop clocks then
case AnalyzeMode:
pausing = TRUE;
ModeHighlight();
}
if (gameMode != AnalyzeMode) {
+ keepInfo = 1; // mere annotating should not alter PGN tags
EditGameEvent();
+ keepInfo = 0;
if (gameMode != EditGame) return;
if (!appData.showThinking) ToggleShowThinking();
ResurrectChessProgram();
gameMode = AnalyzeFile;
pausing = FALSE;
ModeHighlight();
- SetGameInfo();
StartAnalysisClock();
GetTimeMark(&lastNodeCountTime);
if (BoolFeature(&p, "exclude", &cps->excludeMoves, cps)) continue;
if (BoolFeature(&p, "ics", &cps->sendICS, cps)) continue;
if (BoolFeature(&p, "name", &cps->sendName, cps)) continue;
- if (BoolFeature(&p, "pause", &val, cps)) continue; /* unused at present */
+ if (BoolFeature(&p, "pause", &cps->pause, cps)) continue; // [HGM] pause
if (IntFeature(&p, "done", &val, cps)) {
FeatureDone(cps, val);
continue;