void NextMatchGame P((void));
int NextTourneyGame P((int nr, int *swap));
int Pairing P((int nr, int nPlayers, int *w, int *b, int *sync));
-FILE *WriteTourneyFile P((char *results));
+FILE *WriteTourneyFile P((char *results, FILE *f));
void DisplayTwoMachinesTitle P(());
#ifdef WIN32
if(strchr(appData.results, '*') == NULL) {
FILE *f;
appData.tourneyCycles++;
- if(f = WriteTourneyFile(appData.results)) { // make a tourney file with increased number of cycles
+ if(f = WriteTourneyFile(appData.results, NULL)) { // make a tourney file with increased number of cycles
fclose(f);
NextTourneyGame(-1, &dummy);
ReserveGame(-1, 0);
}
FILE *
-WriteTourneyFile(char *results)
+WriteTourneyFile(char *results, FILE *f)
{ // write tournament parameters on tourneyFile; on success return the stream pointer for closing
- FILE *f = fopen(appData.tourneyFile, "w");
+ if(f == NULL) f = fopen(appData.tourneyFile, "w");
if(f == NULL) DisplayError(_("Could not write on tourney file"), 0); else {
// create a file with tournament description
fprintf(f, "-participants {%s}\n", appData.participants);
return f;
}
+#define MAXENGINES 1000
+char *command[MAXENGINES], *mnemonic[MAXENGINES];
+
+void Substitute(char *participants, int expunge)
+{
+ int i, changed, changes=0, nPlayers=0;
+ char *p, *q, *r, buf[MSG_SIZ];
+ if(participants == NULL) return;
+ if(appData.tourneyFile[0] == NULLCHAR) { free(participants); return; }
+ r = p = participants; q = appData.participants;
+ while(*p && *p == *q) {
+ if(*p == '\n') r = p+1, nPlayers++;
+ p++; q++;
+ }
+ if(*p) { // difference
+ while(*p && *p++ != '\n');
+ while(*q && *q++ != '\n');
+ changed = nPlayers;
+ changes = 1 + (strcmp(p, q) != 0);
+ }
+ if(changes == 1) { // a single engine mnemonic was changed
+ q = r; while(*q) nPlayers += (*q++ == '\n');
+ p = buf; while(*r && (*p = *r++) != '\n') p++;
+ *p = NULLCHAR;
+ NamesToList(firstChessProgramNames, command, mnemonic);
+ for(i=1; mnemonic[i]; i++) if(!strcmp(buf, mnemonic[i])) break;
+ if(mnemonic[i]) { // The substitute is valid
+ FILE *f;
+ if(appData.tourneyFile[0] && (f = fopen(appData.tourneyFile, "r+")) ) {
+ flock(fileno(f), LOCK_EX);
+ ParseArgsFromFile(f);
+ fseek(f, 0, SEEK_SET);
+ FREE(appData.participants); appData.participants = participants;
+ if(expunge) { // erase results of replaced engine
+ int len = strlen(appData.results), w, b, dummy;
+ for(i=0; i<len; i++) {
+ Pairing(i, nPlayers, &w, &b, &dummy);
+ if((w == changed || b == changed) && appData.results[i] == '*') {
+ DisplayError(_("You cannot replace an engine while it is engaged!\nTerminate its game first."), 0);
+ fclose(f);
+ return;
+ }
+ }
+ for(i=0; i<len; i++) {
+ Pairing(i, nPlayers, &w, &b, &dummy);
+ if(w == changed || b == changed) appData.results[i] = ' '; // mark as not played
+ }
+ }
+ WriteTourneyFile(appData.results, f);
+ fclose(f); // release lock
+ return;
+ }
+ } else DisplayError(_("No engine with the name you gave is installed"), 0);
+ }
+ if(changes == 0) DisplayError(_("First change an engine by editing the participants list\nof the Tournament Options dialog"), 0);
+ if(changes > 1) DisplayError(_("You can only change one engine at the time"), 0);
+ free(participants);
+ return;
+}
+
int
CreateTourney(char *name)
{
FILE *f;
+ if(matchMode && strcmp(name, appData.tourneyFile)) {
+ ASSIGN(name, appData.tourneyFile); //do not allow change of tourneyfile while playing
+ }
if(name[0] == NULLCHAR) {
if(appData.participants[0])
DisplayError(_("You must supply a tournament file,\nfor storing the tourney progress"), 0);
}
ASSIGN(appData.tourneyFile, name);
if(appData.tourneyType < 0) appData.defaultMatchGames = 1; // Swiss forces games/pairing = 1
- if((f = WriteTourneyFile("")) == NULL) return 0;
+ if((f = WriteTourneyFile("", NULL)) == NULL) return 0;
}
fclose(f);
appData.noChessProgram = FALSE;
return 1;
}
-#define MAXENGINES 1000
-char *command[MAXENGINES], *mnemonic[MAXENGINES];
-
void NamesToList(char *names, char **engineList, char **engineMnemonic)
{
char buf[MSG_SIZ], *p, *q;
names = p; i++;
if(i > MAXENGINES - 2) break;
}
- engineList[i] = NULL;
+ engineList[i] = engineMnemonic[i] = NULL;
}
// following implemented as macro to avoid type limitations
int CreateTourney P((char *name));
char *MakeName P((char *templ));
void SwapEngines P((int n));
+void Substitute P((char *participants, int expunge));
extern char* StripHighlight P((char *)); /* returns static data */
extern char* StripHighlightAndTitle P((char *)); /* returns static data */
if( activeList[j].type == SaveButton)\r
GetOptionValues(hDlg, activeCps, activeList);\r
else if( activeList[j].type != Button) break;\r
+ else if( !activeCps ) { (*(ButtonCallback*) activeList[j].target)(hDlg); break; }\r
snprintf(buf, MSG_SIZ, "option %s\n", activeList[j].name);\r
SendToProgram(buf, activeCps);\r
}\r
{\r
if(autoinc) appData.loadGameIndex = appData.loadPositionIndex = -(twice + 1);\r
if(swiss) { appData.defaultMatchGames = 1; appData.tourneyType = -1; }\r
- if(CreateTourney(tfName)) MatchEvent(2); else return !appData.participants[0];\r
- return 1;\r
+ if(CreateTourney(tfName) && !matchMode) { // CreateTourney reloads original settings if file already existed\r
+ MatchEvent(2);\r
+ return 1; // close dialog\r
+ }\r
+ return matchMode || !appData.participants[0]; // if we failed to create and are not in playing, forbid popdown if there are participants\r
+}\r
+\r
+char *GetParticipants(HWND hDlg)\r
+{\r
+ int len = GetWindowTextLength(GetDlgItem(hDlg, 2001+2*9)) + 1;\r
+ char *participants,*p, *q;\r
+ if(len < 4) return NULL; // box is empty (enough)\r
+ participants = (char*) malloc(len);\r
+ GetDlgItemText(hDlg, 2001+2*9, participants, len );\r
+ p = q = participants;\r
+ while(*p++ = *q++) if(p[-1] == '\r') p--;\r
+ return participants;\r
+}\r
+\r
+void ReplaceParticipant(HWND hDlg)\r
+{\r
+ char *participants = GetParticipants(hDlg);\r
+ Substitute(participants, TRUE);\r
+}\r
+ \r
+void UpgradeParticipant(HWND hDlg)\r
+{\r
+ char *participants = GetParticipants(hDlg);\r
+ Substitute(participants, FALSE);\r
}\r
\r
Option tourneyOptions[] = {\r
{ 0, 0, 1000000000, NULL, (void*) &appData.rewindIndex, "", NULL, Spin, N_("Rewind after (0 = never):") },\r
{ 0, 0, 0, NULL, (void*) &twice, "", NULL, CheckBox, N_("Use each line/position twice") },\r
{ 0, 0, 1000000000, NULL, (void*) &appData.matchPause, "", NULL, Spin, N_("Pause between Games (ms):") },\r
+ { 0, 0, 0, NULL, (void*) &ReplaceParticipant, "", NULL, Button, N_("Replace Engine") },\r
+ { 0, 0, 0, NULL, (void*) &UpgradeParticipant, "", NULL, Button, N_("Upgrade Engine") },\r
{ 0, 0, 0, NULL, (void*) &MatchOK, "", NULL, EndMark , "" }\r
};\r
\r
int MatchOK(int n)
{
- if(appData.participants && appData.participants[0]) free(appData.participants);
- appData.participants = strdup(engineName);
- if(!CreateTourney(tfName)) return !appData.participants[0];
+ ASSIGN(appData.participants, engineName);
+ if(!CreateTourney(tfName) || matchMode) return matchMode || !appData.participants[0];
PopDown(0); // early popdown to prevent FreezeUI called through MatchEvent from causing XtGrab warning
MatchEvent(2); // start tourney
return 1;
}
+void ReplaceParticipant()
+{
+ GenericReadout(3);
+ Substitute(strdup(engineName), True);
+}
+
+void UpgradeParticipant()
+{
+ GenericReadout(3);
+ Substitute(strdup(engineName), False);
+}
+
Option matchOptions[] = {
{ 0, 0, 0, NULL, (void*) &tfName, ".trn", NULL, FileName, N_("Tournament file:") },
{ 0, 0, 0, NULL, (void*) &appData.roundSync, "", NULL, CheckBox, N_("Sync after round (for concurrent playing of a single") },
{ 0, 0, 0, NULL, (void*) &appData.loadPositionFile, ".fen", NULL, FileName, N_("File with Start Positions:") },
{ 0, -2, 1000000000, NULL, (void*) &appData.loadPositionIndex, "", NULL, Spin, N_("Position Number (-1 or -2 = Auto-Increment):") },
{ 0, 0, 1000000000, NULL, (void*) &appData.rewindIndex, "", NULL, Spin, N_("Rewind Index after this many Games (0 = never):") },
-{ 0, 0, 0, NULL, (void*) &MatchOK, "", NULL, EndMark , "" }
+{ 0, 0, 0, NULL, (void*) &ReplaceParticipant, NULL, NULL, Button, N_("Replace Engine") },
+{ 0, 1, 0, NULL, (void*) &UpgradeParticipant, NULL, NULL, Button, N_("Upgrade Engine") },
+{ 0, 1, 0, NULL, (void*) &MatchOK, "", NULL, EndMark , "" }
};
int GeneralOptionsOK(int n)
comboCallback = &AddToTourney;
matchOptions[5].min = -(appData.pairingEngine[0] != NULLCHAR); // with pairing engine, allow Swiss
ASSIGN(tfName, appData.tourneyFile[0] ? appData.tourneyFile : MakeName(appData.defName));
+ ASSIGN(engineName, appData.participants);
GenericPopUp(matchOptions, _("Match Options"), 0);
}