void
Load(ChessProgramState *cps, int i)
{
- char *p, *q, buf[MSG_SIZ], command[MSG_SIZ];
+ char *p, *q, buf[MSG_SIZ], command[MSG_SIZ], buf2[MSG_SIZ];
if(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*
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]) {
snprintf(command, MSG_SIZ, "%s %s", p, params);
p = command;
if(useNick) ASSIGN(appData.pgnName[i], nickName);
if(addToList) {
int len;
+ char quote;
q = firstChessProgramNames;
if(nickName[0]) snprintf(buf, MSG_SIZ, "\"%s\" -fcp ", nickName); else buf[0] = NULLCHAR;
- snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), "\"%s\" -fd \"%s\"%s%s%s%s%s%s%s%s\n", p, appData.directory[i],
+ quote = strchr(p, '"') ? '\'' : '"'; // use single quotes around engine command if it contains double quotes
+ snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), "%c%s%c -fd \"%s\"%s%s%s%s%s%s%s%s\n",
+ quote, p, quote, appData.directory[i],
useNick ? " -fn \"" : "",
useNick ? nickName : "",
useNick ? "\"" : "",
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] = '*';
}
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.
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) {
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);
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
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;
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.
TwoMachinesEvent();
}
+char *
+MakeName(char *template)
+{
+ time_t clock;
+ struct tm *tm;
+ static char buf[MSG_SIZ];
+ char *p = buf;
+ int i;
+
+ clock = time((time_t *)NULL);
+ tm = localtime(&clock);
+
+ while(*p++ = *template++) if(p[-1] == '%') {
+ switch(*template++) {
+ case 0: *p = 0; return buf;
+ case 'Y': i = tm->tm_year+1900; break;
+ case 'y': i = tm->tm_year-100; break;
+ case 'M': i = tm->tm_mon+1; break;
+ case 'd': i = tm->tm_mday; break;
+ case 'h': i = tm->tm_hour; break;
+ case 'm': i = tm->tm_min; break;
+ case 's': i = tm->tm_sec; break;
+ default: i = 0;
+ }
+ snprintf(p-1, MSG_SIZ-10 - (p - buf), "%02d", i); p += strlen(p);
+ }
+ return buf;
+}
+
int
CountPlayers(char *p)
{
{
FILE *f;
if(name[0] == NULLCHAR) {
- DisplayError(_("You must supply a tournament file,\nfor storing the tourney progress"), 0);
+ if(appData.participants[0])
+ DisplayError(_("You must supply a tournament file,\nfor storing the tourney progress"), 0);
return 0;
}
- f = fopen(appData.tourneyFile, "r");
+ f = fopen(name, "r");
if(f) { // file exists
+ ASSIGN(appData.tourneyFile, name);
ParseArgsFromFile(f); // parse it
} else {
- if(CountPlayers(appData.participants) < appData.tourneyType + (!appData.tourneyType) + 1) {
+ if(!appData.participants[0]) return 0; // ignore tourney file if non-existing & no participants
+ if(CountPlayers(appData.participants) < (appData.tourneyType>0 ? appData.tourneyType+1 : 2)) {
DisplayError(_("Not enough participants"), 0);
return 0;
}
+ ASSIGN(appData.tourneyFile, name);
if((f = WriteTourneyFile("")) == NULL) return 0;
}
fclose(f);
*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) {
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) {
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.
}
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) {
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);
{
char buf[MSG_SIZ];
if (appData.matchGames > 0) {
+ if(appData.tourneyFile[0]) {
+ 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)",
gameInfo.white, gameInfo.black,