ChessProgramState *savCps;
-GameMode oldMode;
+GameMode oldMode, tryNr;
+
+extern char *engineName, *engineDir, *engineChoice, *engineLine, *nickName, *params;
+extern Boolean isUCI, hasBook, storeVariant, v1, addToList, useNick;
+char *insert, *wbOptions, *currentEngine[2]; // point in ChessProgramNames were we should insert new engine
+static char newEngineCommand[MSG_SIZ];
+
+void
+FloatToFront(char **list, char *engineLine)
+{
+ char buf[MSG_SIZ], tidy[MSG_SIZ], *p = buf, *q, *r = buf;
+ int i=0;
+ if(appData.recentEngines <= 0) return;
+ TidyProgramName(engineLine, "localhost", tidy+1);
+ tidy[0] = buf[0] = '\n'; strcat(tidy, "\n");
+ strncpy(buf+1, *list, MSG_SIZ-50);
+ if(p = strstr(buf, tidy)) { // tidy name appears in list
+ q = strchr(++p, '\n'); if(q == NULL) return; // malformed, don't touch
+ while(*p++ = *++q); // squeeze out
+ }
+ strcat(tidy, buf+1); // put list behind tidy name
+ p = tidy + 1; while(q = strchr(p, '\n')) i++, r = p, p = q + 1; // count entries in new list
+ if(i > appData.recentEngines) *r = NULLCHAR; // if maximum rached, strip off last
+ ASSIGN(*list, tidy+1);
+}
+
+void
+SaveEngineList ()
+{
+ FILE *f;
+ if(*engineListFile && (f = fopen(engineListFile, "w"))) {
+ fprintf(f, "-firstChessProgramNames {%s}\n", firstChessProgramNames);
+ fclose(f);
+ }
+}
+
+void
+AddToEngineList (int i)
+{
+ if(addToList) {
+ int len;
+ char quote, buf[MSG_SIZ];
+ char *q = firstChessProgramNames, *p = newEngineCommand;
+ if(nickName[0]) snprintf(buf, MSG_SIZ, "\"%s\" -fcp ", nickName); else buf[0] = NULLCHAR;
+ 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",
+ quote, p, quote, appData.directory[i],
+ useNick ? " -fn \"" : "",
+ useNick ? nickName : "",
+ useNick ? "\"" : "",
+ v1 ? " -firstProtocolVersion 1" : "",
+ hasBook ? "" : " -fNoOwnBookUCI",
+ isUCI ? (isUCI == TRUE ? " -fUCI" : gameInfo.variant == VariantShogi ? " -fUSI" : " -fUCCI") : "",
+ storeVariant ? " -variant " : "",
+ storeVariant ? VariantName(gameInfo.variant) : "");
+ if(wbOptions && wbOptions[0]) snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " %s", wbOptions);
+ firstChessProgramNames = malloc(len = strlen(q) + strlen(buf) + 2);
+ if(insert != q) insert[-1] = NULLCHAR;
+ snprintf(firstChessProgramNames, len, "%s\n%s\n%s", q, buf, insert);
+ if(q) free(q);
+ SaveEngineList();
+ FloatToFront(&appData.recentEngineList, buf);
+ ASSIGN(currentEngine[i], buf);
+ }
+}
void
LoadEngine ()
{
int i;
if(WaitForEngine(savCps, LoadEngine)) return;
+ if(tryNr == 1 && !isUCI) { SendToProgram("uci\n", savCps); tryNr = 2; ScheduleDelayedEvent(LoadEngine, FEATURE_TIMEOUT); return; }
+ if(tryNr) v1 |= (tryNr == 2), tryNr = 0, AddToEngineList(0); // deferred to after protocol determination
CommonEngineInit(); // recalculate time odds
if(gameInfo.variant != StringToVariant(appData.variant)) {
// we changed variant when loading the engine; this forces us to reset
appData.clockMode = TRUE;
InitEngine(cps, n);
UpdateLogos(TRUE);
- if(n) return; // only startup first engine immediately; second can wait
+ if(n && !tryNr) return; // only startup first engine immediately; second can wait (unless autodetect)
savCps = cps; // parameter to LoadEngine passed as globals, to allow scheduled calling :-(
LoadEngine();
}
-extern char *engineName, *engineDir, *engineChoice, *engineLine, *nickName, *params;
-extern Boolean isUCI, hasBook, storeVariant, v1, addToList, useNick;
-
static char resetOptions[] =
"-reuse -firstIsUCI false -firstHasOwnBookUCI true -firstTimeOdds 1 "
"-firstInitString \"" INIT_STRING "\" -firstComputerString \"" COMPUTER_STRING "\" "
"-firstOptions \"\" -firstNPS -1 -fn \"\" -firstScoreAbs false";
void
-FloatToFront(char **list, char *engineLine)
-{
- char buf[MSG_SIZ], tidy[MSG_SIZ], *p = buf, *q, *r = buf;
- int i=0;
- if(appData.recentEngines <= 0) return;
- TidyProgramName(engineLine, "localhost", tidy+1);
- tidy[0] = buf[0] = '\n'; strcat(tidy, "\n");
- strncpy(buf+1, *list, MSG_SIZ-50);
- if(p = strstr(buf, tidy)) { // tidy name appears in list
- q = strchr(++p, '\n'); if(q == NULL) return; // malformed, don't touch
- while(*p++ = *++q); // squeeze out
- }
- strcat(tidy, buf+1); // put list behind tidy name
- p = tidy + 1; while(q = strchr(p, '\n')) i++, r = p, p = q + 1; // count entries in new list
- if(i > appData.recentEngines) *r = NULLCHAR; // if maximum rached, strip off last
- ASSIGN(*list, tidy+1);
-}
-
-char *insert, *wbOptions, *currentEngine[2]; // point in ChessProgramNames were we should insert new engine
-
-void
Load (ChessProgramState *cps, int i)
{
char *p, *q, buf[MSG_SIZ], command[MSG_SIZ], buf2[MSG_SIZ], buf3[MSG_SIZ], jar;
}
if(jar) { snprintf(buf3, MSG_SIZ, "java -jar %s", p); p = buf3; }
ASSIGN(appData.chessProgram[i], p);
+ tryNr = 3; // requests adding to list without auto-detect
+ if(isUCI == 3) tryNr = 1, isUCI = 0; // auto-detect
appData.isUCI[i] = isUCI;
appData.protocolVersion[i] = v1 ? 1 : PROTOVER;
appData.hasOwnBookUCI[i] = hasBook;
if(!nickName[0]) useNick = FALSE;
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;
- 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",
- quote, p, quote, appData.directory[i],
- useNick ? " -fn \"" : "",
- useNick ? nickName : "",
- useNick ? "\"" : "",
- v1 ? " -firstProtocolVersion 1" : "",
- hasBook ? "" : " -fNoOwnBookUCI",
- isUCI ? (isUCI == TRUE ? " -fUCI" : gameInfo.variant == VariantShogi ? " -fUSI" : " -fUCCI") : "",
- storeVariant ? " -variant " : "",
- storeVariant ? VariantName(gameInfo.variant) : "");
- if(wbOptions && wbOptions[0]) snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " %s", wbOptions);
- firstChessProgramNames = malloc(len = strlen(q) + strlen(buf) + 2);
- if(insert != q) insert[-1] = NULLCHAR;
- snprintf(firstChessProgramNames, len, "%s\n%s\n%s", q, buf, insert);
- if(q) free(q);
- FloatToFront(&appData.recentEngineList, buf);
- ASSIGN(currentEngine[i], buf);
- }
+ safeStrCpy(newEngineCommand, p, MSG_SIZ);
ReplaceEngine(cps, i);
}
i++;
}
}
- if( count >= 100)
+ if( count >= 100 && gameInfo.variant != VariantMakruk) // do not accept 50-move claims in Makruk
boards[forwardMostMove][EP_STATUS] = EP_RULE_DRAW;
/* this is used to judge if draw claims are legal */
if(canAdjudicate && appData.ruleMoves > 0 && count >= 2*appData.ruleMoves) {
GameEnds(cps->twoMachinesColor[0] == 'w' ? BlackWins : WhiteWins,
buf1, GE_XBOARD);
return;
- } else if(!appData.fischerCastling)
+ } else if(!appData.fischerCastling && toX != BOARD_WIDTH>>1)
/* [HGM] Kludge to handle engines that send FRC-style castling
when they shouldn't (like TSCP-Gothic) */
switch(moveType) {
cps->useSigterm = FALSE;
}
if (strncmp(message, "feature ", 8) == 0) { // [HGM] moved forward to pre-empt non-compliant commands
- ParseFeatures(message+8, cps);
+ ParseFeatures(message+8, cps); if(tryNr && tryNr < 3) tryNr = 3;
return; // [HGM] This return was missing, causing option features to be recognized as non-compliant commands!
}
first.highlight = f;
return;
}
+ if(strncmp(message, "uciok", 5) == 0) { // response to "uci" probe
+ int nr = (cps == &second);
+ appData.isUCI[nr] = isUCI = 1;
+ ReplaceEngine(cps, nr); // retry install as UCI
+ return;
+ }
/*
* If the move is illegal, cancel it and redraw the board.
* Also deal with other error cases. Matching is rather loose
{
int len; char *p, *q, *s, buf[MSG_SIZ], *optionSettings;
if(!currentEngine[n] || !currentEngine[n][0]) { DisplayMessage("saving failed: engine not from list", ""); return; } // no engine from list is loaded
+ if(*engineListFile) ParseSettingsFile(engineListFile, &engineListFile); // update engine list
p = strstr(firstChessProgramNames, currentEngine[n]);
if(!p) { DisplayMessage("saving failed: engine not found in list", ""); return; } // sanity check; engine could be deleted from list after loading
optionSettings = ResendOptions(n ? &second : &first, FALSE);
s = malloc(len);
snprintf(s, len, "%s%s%s", firstChessProgramNames, currentEngine[n], q);
FREE(firstChessProgramNames); firstChessProgramNames = s; // new list
+ if(*engineListFile) SaveEngineList();
}
// following implemented as macro to avoid type limitations