Fix display of last move of last match game
[xboard.git] / backend.c
index 4771e63..05e60b5 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -1380,7 +1380,7 @@ ReserveGame(int gameNr, char resChar)
     safeStrCpy(q, p, strlen(p) + 2);
     if(gameNr >= 0) q[gameNr] = resChar; // replace '*' with result
     if(appData.debugMode) fprintf(debugFP, "pick next game from '%s': %d\n", q, nextGame);
-    if(nextGame <= appData.matchGames && resChar != ' ') { // already reserve next game, if tourney not yet done
+    if(nextGame <= appData.matchGames && resChar != ' ' && !abortMatch) { // reserve next game if tourney not yet done
        if(q[nextGame] == NULLCHAR) q[nextGame+1] = NULLCHAR; // append one char
        q[nextGame] = '*';
     }
@@ -1392,7 +1392,7 @@ ReserveGame(int gameNr, char resChar)
     fprintf(tf, "%s\"\n", q); fclose(tf); // update, and flush by closing
     DisplayMessage(buf, "");
     free(p); appData.results = q;
-    if(nextGame <= appData.matchGames && resChar != ' ' &&
+    if(nextGame <= appData.matchGames && resChar != ' ' && !abortMatch &&
        (gameNr < 0 || nextGame / appData.defaultMatchGames != gameNr / appData.defaultMatchGames)) {
        UnloadEngine(&first);  // next game belongs to other pairing;
        UnloadEngine(&second); // already unload the engines, so TwoMachinesEvent will load new ones.
@@ -1405,8 +1405,7 @@ MatchEvent(int mode)
        int dummy;
        if(matchMode) { // already in match mode: switch it off
            abortMatch = TRUE;
-           appData.matchGames = appData.tourneyFile[0] ? nextGame: matchGame; // kludge to let match terminate after next game.
-           ModeHighlight(); // kludgey way to remove checkmark...
+           if(!appData.tourneyFile[0]) appData.matchGames = matchGame; // kludge to let match terminate after next game.
            return;
        }
 //     if(gameMode != BeginningOfGame) {
@@ -1551,6 +1550,8 @@ InitBackEnd3 P((void))
            if(f = fopen(appData.tourneyFile, "r")) {
                ParseArgsFromFile(f); // make sure tourney parmeters re known
                fclose(f);
+               appData.clockMode = TRUE;
+               SetGNUMode();
            } else appData.tourneyFile[0] = NULLCHAR; // for now ignore bad tourney file
        }
        MatchEvent(TRUE);
@@ -7143,8 +7144,6 @@ TourneyStandings(int display)
     int score[MAXPLAYERS], ranking[MAXPLAYERS], points[MAXPLAYERS], games[MAXPLAYERS];
     char result, *p, *names[MAXPLAYERS];
 
-    if(appData.tourneyType < 0) return strdup("Swiss tourney finished"); // standings of Swiss yet TODO
-
     names[0] = p = strdup(appData.participants);
     while(p = strchr(p, '\n')) *p++ = NULLCHAR, names[++nPlayers] = p; // count participants
 
@@ -7167,6 +7166,7 @@ TourneyStandings(int display)
        games[b]++;
        nr++;
     }
+    if(appData.tourneyType < 0) return strdup("Swiss tourney finished"); // standings of Swiss yet TODO
     if(appData.tourneyType > 0) nPlayers = appData.tourneyType; // in gauntlet, list only gauntlet engine(s)
     for(w=0; w<nPlayers; w++) {
        bScore = -1;
@@ -7661,7 +7661,10 @@ HandleMachineMove(message, cps)
 
     if(cps == &pairing && sscanf(message, "%d-%d", &savedWhitePlayer, &savedBlackPlayer) == 2) {
        // [HGM] pairing: Mega-hack! Pairing engine also uses this routine (so it could give other WB commands).
-       if(savedWhitePlayer == 0 || savedBlackPlayer == 0) return;
+       if(savedWhitePlayer == 0 || savedBlackPlayer == 0) {
+           DisplayError(_("Invalid pairing from pairing engine"), 0);
+           return;
+       }
        pairingReceived = 1;
        NextMatchGame();
        return; // Skim the pairing messages here.
@@ -9748,9 +9751,9 @@ Pairing(int nr, int nPlayers, int *whitePlayer, int *blackPlayer, int *syncInter
            *whitePlayer = curRound;
            *blackPlayer = nPlayers - 1; // this is the 'bye' when nPlayer is odd
        } else {
-           *whitePlayer = curRound - pairingsPerRound + curPairing;
+           *whitePlayer = curRound - (nPlayers-1)/2 + curPairing;
            if(*whitePlayer < 0) *whitePlayer += nPlayers-1+(nPlayers&1);
-           *blackPlayer = curRound + pairingsPerRound - curPairing;
+           *blackPlayer = curRound + (nPlayers-1)/2 - curPairing;
            if(*blackPlayer >= nPlayers-1+(nPlayers&1)) *blackPlayer -= nPlayers-1+(nPlayers&1);
        }
     } else if(appData.tourneyType > 0) {
@@ -9776,22 +9779,7 @@ NextTourneyGame(int nr, int *swapColors)
     InitTimeControls(); // TC might be altered from tourney file
 
     nPlayers = CountPlayers(appData.participants); // count participants
-    if(appData.tourneyType < 0 && appData.pairingEngine[0]) {
-       if(nr>=0 && !pairingReceived) {
-           char buf[1<<16];
-           if(pairing.pr == NoProc) StartChessProgram(&pairing);
-           snprintf(buf, 1<<16, "results %d %s\n", nPlayers, appData.results);
-           SendToProgram(buf, &pairing);
-           snprintf(buf, 1<<16, "pairing %d\n", nr+1);
-           SendToProgram(buf, &pairing);
-           return 0; // wait for pairing engine to answer (which causes NextTourneyGame to be called again...
-       }
-       pairingReceived = 0;                              // ... so we continue here 
-       syncInterval = nPlayers/2; *swapColors = 0;
-       appData.matchGames = appData.tourneyCycles * syncInterval - 1;
-       whitePlayer = savedWhitePlayer-1; blackPlayer = savedBlackPlayer-1;
-       matchGame = 1; roundNr = nr / syncInterval + 1;
-    } else
+    if(appData.tourneyType < 0) syncInterval = nPlayers/2; else
     *swapColors = Pairing(nr<0 ? 0 : nr, nPlayers, &whitePlayer, &blackPlayer, &syncInterval);
 
     if(syncInterval) {
@@ -9806,6 +9794,29 @@ NextTourneyGame(int nr, int *swapColors)
        waitingForGame = FALSE;
     }
 
+    if(appData.tourneyType < 0) {
+       if(nr>=0 && !pairingReceived) {
+           char buf[1<<16];
+           if(pairing.pr == NoProc) {
+               if(!appData.pairingEngine[0]) {
+                   DisplayFatalError(_("No pairing engine specified"), 0, 1);
+                   return 0;
+               }
+               StartChessProgram(&pairing); // starts the pairing engine
+           }
+           snprintf(buf, 1<<16, "results %d %s\n", nPlayers, appData.results);
+           SendToProgram(buf, &pairing);
+           snprintf(buf, 1<<16, "pairing %d\n", nr+1);
+           SendToProgram(buf, &pairing);
+           return 0; // wait for pairing engine to answer (which causes NextTourneyGame to be called again...
+       }
+       pairingReceived = 0;                              // ... so we continue here 
+       *swapColors = 0;
+       appData.matchGames = appData.tourneyCycles * syncInterval - 1;
+       whitePlayer = savedWhitePlayer-1; blackPlayer = savedBlackPlayer-1;
+       matchGame = 1; roundNr = nr / syncInterval + 1;
+    }
+
     if(first.pr != NoProc) return 1; // engines already loaded
 
     // redefine engines, engine dir, etc.
@@ -10211,9 +10222,10 @@ GameEnds(result, resultDetails, whosays)
        }
 
        if(waitingForGame) resChar = ' '; // quit while waiting for round sync: unreserve already reserved game
-       if(appData.tourneyFile[0] && !abortMatch){ // [HGM] we are in a tourney; update tourney file with game result
+       if(appData.tourneyFile[0]){ // [HGM] we are in a tourney; update tourney file with game result
            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
        } else roundNr = nextGame = matchGame + 1; // normal match, just increment; round equals matchGame
 
        if (nextGame <= appData.matchGames && !abortMatch) {
@@ -10248,6 +10260,7 @@ GameEnds(result, resultDetails, whosays)
     if(popupRequested) { // [HGM] crash: this calls GameEnds recursively through ExitEvent! Make it a harmless tail recursion.
        if(matchMode == TRUE) { // match through command line: exit with or without popup
            if(ranking) {
+               ToNrEvent(forwardMostMove);
                if(strcmp(ranking, "busy")) DisplayFatalError(ranking, 0, 0);
                else ExitEvent(0);
            } else DisplayFatalError(buf, 0, 0);