FILE *WriteTourneyFile P((char *results, FILE *f));
void DisplayTwoMachinesTitle P(());
static void ExcludeClick P((int index));
+void ToggleSecond P((void));
#ifdef WIN32
extern void ConsoleCreate();
ChessSquare pieceSweep = EmptySquare;
ChessSquare promoSweep = EmptySquare, defaultPromoChoice;
int promoDefaultAltered;
+int keepInfo = 0; /* [HGM] to protect PGN tags in auto-step game analysis */
/* States for ics_getting_history */
#define H_FALSE 0
}
void
+SendToBoth (char *msg)
+{ // to make it easy to keep two engines in step in dual analysis
+ SendToProgram(msg, &first);
+ if(second.analyzing) SendToProgram(msg, &second);
+}
+
+void
AnalysisPeriodicEvent (int force)
{
if (((programStats.ok_to_send == 0 || programStats.line_is_book)
return;
/* Send . command to Crafty to collect stats */
- SendToProgram(".\n", &first);
+ SendToBoth(".\n");
/* Don't send another until we get a response (this makes
us stop sending to old Crafty's which don't understand
}
Boolean
-LoadMultiPV (int x, int y, char *buf, int index, int *start, int *end)
+LoadMultiPV (int x, int y, char *buf, int index, int *start, int *end, int pane)
{
int startPV, multi, lineStart, origIndex = index;
char *p, buf2[MSG_SIZ];
+ ChessProgramState *cps = (pane ? &second : &first);
if(index < 0 || index >= strlen(buf)) return FALSE; // sanity
lastX = x; lastY = y;
do{ while(buf[index] && buf[index] != '\n') index++;
} while(buf[index] == '\n' && buf[index+1] == '\\' && buf[index+2] == ' ' && index++); // join kibitzed PV continuation line
buf[index] = 0;
- if(lineStart == 0 && gameMode == AnalyzeMode && (multi = MultiPV(&first)) >= 0) {
- int n = first.option[multi].value;
+ if(lineStart == 0 && gameMode == AnalyzeMode && (multi = MultiPV(cps)) >= 0) {
+ int n = cps->option[multi].value;
if(origIndex > 17 && origIndex < 24) { if(n>1) n--; } else if(origIndex > index - 6) n++;
snprintf(buf2, MSG_SIZ, "option MultiPV=%d\n", n);
- if(first.option[multi].value != n) SendToProgram(buf2, &first);
- first.option[multi].value = n;
+ if(cps->option[multi].value != n) SendToProgram(buf2, cps);
+ cps->option[multi].value = n;
*start = *end = 0;
return FALSE;
} else if(strstr(buf+lineStart, "exclude:") == buf+lineStart) { // exclude moves clicked
// inform engine
snprintf(buf, MSG_SIZ, "%sclude ", state == '+' ? "in" : "ex");
CoordsToComputerAlgebraic(fromY, fromX, toY, toX, promoChar, buf+8);
- SendToProgram(buf, &first);
+ SendToBoth(buf);
return (state == '+');
}
if(index < 13) { // none: include all
WriteMap(0); // clear map
for(i=0; i<exCnt; i++) exclusionHeader[excluTab[i].mark] = '+'; // and moves
- SendToProgram("include all\n", &first); // and inform engine
+ SendToBoth("include all\n"); // and inform engine
} else if(index > 18) { // tail
if(exclusionHeader[19] == '-') { // tail was excluded
- SendToProgram("include all\n", &first);
+ SendToBoth("include all\n");
WriteMap(0); // clear map completely
// now re-exclude selected moves
for(i=0; i<exCnt; i++) if(exclusionHeader[e[i].mark] == '-')
ExcludeOneMove(e[i].fr, e[i].ff, e[i].tr, e[i].tf, e[i].pc, '-');
} else { // tail was included or in mixed state
- SendToProgram("exclude all\n", &first);
+ SendToBoth("exclude all\n");
WriteMap(0xFF); // fill map completely
// now re-include selected moves
j = 0; // count them
gameMode == MachinePlaysBlack)) {
SendTimeRemaining(&first, gameMode != MachinePlaysBlack);
}
- if (gameMode != EditGame && gameMode != PlayFromGameFile) {
+ if (gameMode != EditGame && gameMode != PlayFromGameFile && gameMode != AnalyzeMode) {
// [HGM] book: if program might be playing, let it use book
bookHit = SendMoveToBookUser(forwardMostMove-1, &first, FALSE);
first.maybeThinking = TRUE;
} else if(fromY == DROP_RANK && fromX == EmptySquare) {
if(!first.useSetboard) SendToProgram("undo\n", &first); // kludge to change stm in engines that do not support setboard
SendBoard(&first, currentMove+1);
- } else SendMoveToProgram(forwardMostMove-1, &first);
+ if(second.analyzing) {
+ if(!second.useSetboard) SendToProgram("undo\n", &second);
+ SendBoard(&second, currentMove+1);
+ }
+ } else {
+ SendMoveToProgram(forwardMostMove-1, &first);
+ if(second.analyzing) SendMoveToProgram(forwardMostMove-1, &second);
+ }
if (currentMove == cmailOldMove + 1) {
cmailMoveType[lastLoadGameNumber - 1] = CMAIL_MOVE;
}
}
int
+CheckPlayers (char *participants)
+{
+ int i;
+ char buf[MSG_SIZ], *p;
+ NamesToList(firstChessProgramNames, command, mnemonic, "all");
+ while(p = strchr(participants, '\n')) {
+ *p = NULLCHAR;
+ for(i=1; mnemonic[i]; i++) if(!strcmp(participants, mnemonic[i])) break;
+ if(!mnemonic[i]) {
+ snprintf(buf, MSG_SIZ, _("No engine %s is installed"), participants);
+ *p = '\n';
+ DisplayError(buf, 0);
+ return 1;
+ }
+ *p = '\n';
+ participants = p + 1;
+ }
+ return 0;
+}
+
+int
CreateTourney (char *name)
{
FILE *f;
DisplayError(_("Not enough participants"), 0);
return 0;
}
+ if(CheckPlayers(appData.participants)) return 0;
ASSIGN(appData.tourneyFile, name);
if(appData.tourneyType < 0) appData.defaultMatchGames = 1; // Swiss forces games/pairing = 1
if((f = WriteTourneyFile("", NULL)) == NULL) return 0;
}
int
+GetEngineLine (char *s, int n)
+{
+ int i;
+ char buf[MSG_SIZ];
+ extern char *icsNames;
+ if(!s || !*s) return 0;
+ NamesToList(n >= 10 ? icsNames : firstChessProgramNames, command, mnemonic, "all");
+ for(i=1; mnemonic[i]; i++) if(!strcmp(s, mnemonic[i])) break;
+ if(!mnemonic[i]) return 0;
+ if(n == 11) return 1; // just testing if there was a match
+ snprintf(buf, MSG_SIZ, "-%s %s", n == 10 ? "icshost" : "fcp", command[i]);
+ if(n == 1) SwapEngines(n);
+ ParseArgsFromString(buf);
+ if(n == 1) SwapEngines(n);
+ if(n == 0 && *appData.secondChessProgram == NULLCHAR) {
+ SwapEngines(1); // set second same as first if not yet set (to suppress WB startup dialog)
+ ParseArgsFromString(buf);
+ }
+ return 1;
+}
+
+int
SetPlayer (int player, char *p)
{ // [HGM] find the engine line of the partcipant given by number, and parse its options.
int i;
}
}
+void
+AnalyzeNextGame()
+{
+ ReloadGame(1); // next game
+}
int
AutoPlayOneMove ()
}
if (currentMove >= forwardMostMove) {
- if(gameMode == AnalyzeFile) { ExitAnalyzeMode(); SendToProgram("force\n", &first); }
+ if(gameMode == AnalyzeFile) {
+ if(appData.loadGameIndex == -1) {
+ GameEnds(EndOfFile, NULL, GE_FILE);
+ ScheduleDelayedEvent(AnalyzeNextGame, 10);
+ } else {
+ ExitAnalyzeMode(); SendToProgram("force\n", &first);
+ }
+ }
// gameMode = EndOfGame;
// ModeHighlight();
gn = 1;
}
else {
+ if(gameMode == AnalyzeFile && appData.loadGameIndex == -1)
+ appData.loadGameIndex = 0; // [HGM] suppress error message if we reach file end after auto-stepping analysis
+ else
DisplayError(_("Game number out of range"), 0);
return FALSE;
}
if (oldGameMode == AnalyzeFile ||
oldGameMode == AnalyzeMode) {
+ appData.loadGameIndex = -1; // [HGM] order auto-stepping through games
+ keepInfo = 1;
AnalyzeFileEvent();
+ keepInfo = 0;
}
if (!matchMode && pos > 0) {
}
void
+ToggleSecond ()
+{
+ if(second.analyzing) {
+ SendToProgram("exit\n", &second);
+ second.analyzing = FALSE;
+ } else {
+ if (second.pr == NoProc) StartChessProgram(&second);
+ InitChessProgram(&second, FALSE);
+ FeedMovesToProgram(&second, currentMove);
+
+ SendToProgram("analyze\n", &second);
+ second.analyzing = TRUE;
+ }
+}
+
+void
AnalyzeModeEvent ()
{
+ if (gameMode == AnalyzeMode) { ToggleSecond(); return; }
if (appData.noChessProgram || gameMode == AnalyzeMode)
return;
DisplayMessage("",_("Close ICS engine analyze..."));
}
if (first.analysisSupport && first.analyzing) {
- SendToProgram("exit\n", &first);
- first.analyzing = FALSE;
+ SendToBoth("exit\n");
+ first.analyzing = second.analyzing = FALSE;
}
thinkOutput[0] = NULLCHAR;
}
gameMode == Training || gameMode == PlayFromGameFile ||
gameMode == AnalyzeFile) {
while (currentMove < target) {
+ if(second.analyzing) SendMoveToProgram(currentMove, &second);
SendMoveToProgram(currentMove++, &first);
}
} else {
if(moveList[i-1][1] == '@' && moveList[i-1][0] == '@') break;
}
SendBoard(&first, i);
- for(currentMove=i; currentMove<target; currentMove++) SendMoveToProgram(currentMove, &first);
+ if(second.analyzing) SendBoard(&second, i);
+ for(currentMove=i; currentMove<target; currentMove++) {
+ SendMoveToProgram(currentMove, &first);
+ if(second.analyzing) SendMoveToProgram(currentMove, &second);
+ }
break;
}
- SendToProgram("undo\n", &first);
+ SendToBoth("undo\n");
currentMove--;
}
} else {
ChessMove r = GameUnfinished;
char *p = NULL;
+ if(keepInfo) return;
+
if(gameMode == EditGame) { // [HGM] vari: do not erase result on EditGame
r = gameInfo.result;
p = gameInfo.resultDetails;