cps->analysisSupport = 2; /* detect */
cps->analyzing = FALSE;
cps->initDone = FALSE;
+ cps->reload = FALSE;
/* New features added by Tord: */
cps->useFEN960 = FALSE;
void
ParseBoard12 (char *string)
{
+#if ZIPPY
+ int i, takeback;
+ char *bookHit = NULL; // [HGM] book
+#endif
GameMode newGameMode;
- int gamenum, newGame, newMove, relation, basetime, increment, ics_flip = 0, i;
- int j, k, n, moveNum, white_stren, black_stren, white_time, black_time, takeback;
+ int gamenum, newGame, newMove, relation, basetime, increment, ics_flip = 0;
+ int j, k, n, moveNum, white_stren, black_stren, white_time, black_time;
int double_push, castle_ws, castle_wl, castle_bs, castle_bl, irrev_count;
char to_play, board_chars[200];
char move_str[MSG_SIZ], str[MSG_SIZ], elapsed_time[MSG_SIZ];
int fromX, fromY, toX, toY;
char promoChar;
int ranks=1, files=0; /* [HGM] ICS80: allow variable board size */
- char *bookHit = NULL; // [HGM] book
Boolean weird = FALSE, reqFlag = FALSE;
fromX = fromY = toX = toY = -1;
boards[forwardMostMove][EP_STATUS] = nrW == nrB ? EP_STALEMATE :
((nrW < nrB) != WhiteOnMove(forwardMostMove) ?
EP_CHECKMATE : EP_WINS);
- else if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantXiangqi)
+ else if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShogi)
boards[forwardMostMove][EP_STATUS] = EP_CHECKMATE; // and in these variants being stalemated loses
}
break;
case MT_CHECKMATE:
reason = "Xboard adjudication: Checkmate";
boards[forwardMostMove][EP_STATUS] = (gameInfo.variant == VariantLosers ? EP_WINS : EP_CHECKMATE);
+ if(gameInfo.variant == VariantShogi) {
+ if(forwardMostMove > backwardMostMove
+ && moveList[forwardMostMove-1][1] == '@'
+ && CharToPiece(ToUpper(moveList[forwardMostMove-1][0])) == WhitePawn) {
+ reason = "XBoard adjudication: pawn-drop mate";
+ boards[forwardMostMove][EP_STATUS] = EP_WINS;
+ }
+ }
break;
}
/* adjudicate after user-specified nr of repeats */
int result = GameIsDrawn;
char *details = "XBoard adjudication: repetition draw";
- if(gameInfo.variant == VariantXiangqi && appData.testLegality) {
+ if((gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShogi) && appData.testLegality) {
// [HGM] xiangqi: check for forbidden perpetuals
int m, ourPerpetual = 1, hisPerpetual = 1;
for(m=forwardMostMove; m>k; m-=2) {
if(hisPerpetual && !ourPerpetual) { // he is checking us, but did not repeat yet
break; // (or we would have caught him before). Abort repetition-checking loop.
} else
+ if(gameInfo.variant == VariantShogi) { // in Shogi other repetitions are draws
+ if(BOARD_HEIGHT == 5 && BOARD_RGHT - BOARD_LEFT == 5) { // but in mini-Shogi gote wins!
+ result = BlackWins;
+ details = "Xboard adjudication: repetition";
+ }
+ } else // it must be XQ
// Now check for perpetual chases
if(!ourPerpetual && !hisPerpetual) { // no perpetual check, test for chase
hisPerpetual = PerpetualChase(k, forwardMostMove);
/* Machine move could not be parsed; ignore it. */
snprintf(buf1, MSG_SIZ*10, _("Illegal move \"%s\" from %s machine"),
machineMove, _(cps->which));
- DisplayError(buf1, 0);
+ DisplayMoveError(buf1);
snprintf(buf1, MSG_SIZ*10, "Xboard: Forfeit due to invalid move: %s (%c%c%c%c) res=%d",
machineMove, fromX+AAA, fromY+ONE, toX+AAA, toY+ONE, moveType);
if (gameMode == TwoMachinesPlay) {
snprintf(buf1, sizeof(buf1), "%swhisper %s\n", ics_prefix, message + 11);
SendToICS(buf1);
}
- }
+ } else if(appData.autoComment) AppendComment (forwardMostMove, message + 11, 1); // in local mode, add as move comment
return;
}
if (!strncmp(message, "tellall ", 8)) {
) {
/* white pawn promotion */
board[toY][toX] = CharToPiece(ToUpper(promoChar));
- if((gameInfo.variant==VariantBughouse || gameInfo.variant==VariantCrazyhouse)
- && PieceToChar(PROMOTED board[toY][toX]) == '~') /* [HGM] use shadow piece (if available) */
+ if(board[toY][toX] < WhiteCannon && PieceToChar(PROMOTED board[toY][toX]) == '~') /* [HGM] use shadow piece (if available) */
board[toY][toX] = (ChessSquare) (PROMOTED board[toY][toX]);
board[fromY][fromX] = EmptySquare;
} else if ((fromY >= BOARD_HEIGHT>>1)
) {
/* black pawn promotion */
board[toY][toX] = CharToPiece(ToLower(promoChar));
- if((gameInfo.variant==VariantBughouse || gameInfo.variant==VariantCrazyhouse)
- && PieceToChar(PROMOTED board[toY][toX]) == '~') /* [HGM] use shadow piece (if available) */
+ if(board[toY][toX] < BlackCannon && PieceToChar(PROMOTED board[toY][toX]) == '~') /* [HGM] use shadow piece (if available) */
board[toY][toX] = (ChessSquare) (PROMOTED board[toY][toX]);
board[fromY][fromX] = EmptySquare;
} else if ((fromY < BOARD_HEIGHT>>1)
void
+ResendOptions (ChessProgramState *cps)
+{ // send the stored value of the options
+ int i;
+ char buf[MSG_SIZ];
+ Option *opt = cps->option;
+ for(i=0; i<cps->nrOptions; i++, opt++) {
+ switch(opt->type) {
+ case Spin:
+ case Slider:
+ case CheckBox:
+ snprintf(buf, MSG_SIZ, "option %s=%d\n", opt->name, opt->value);
+ break;
+ case ComboBox:
+ snprintf(buf, MSG_SIZ, "option %s=%s\n", opt->name, opt->choice[opt->value]);
+ break;
+ default:
+ snprintf(buf, MSG_SIZ, "option %s=%s\n", opt->name, opt->textValue);
+ break;
+ case Button:
+ case SaveButton:
+ continue;
+ }
+ SendToProgram(buf, cps);
+ }
+}
+
+void
StartChessProgram (ChessProgramState *cps)
{
char buf[MSG_SIZ];
cps->isr = AddInputSource(cps->pr, TRUE, ReceiveFromProgram, cps);
if (cps->protocolVersion > 1) {
snprintf(buf, MSG_SIZ, "xboard\nprotover %d\n", cps->protocolVersion);
- cps->nrOptions = 0; // [HGM] options: clear all engine-specific options
- cps->comboCnt = 0; // and values of combo boxes
+ if(!cps->reload) { // do not clear options when reloading because of -xreuse
+ cps->nrOptions = 0; // [HGM] options: clear all engine-specific options
+ cps->comboCnt = 0; // and values of combo boxes
+ }
SendToProgram(buf, cps);
+ if(cps->reload) ResendOptions(cps);
} else {
SendToProgram("xboard\n", cps);
}
TwoMachinesEventIfReady P((void))
{
static int curMess = 0;
- if (first.lastPing != first.lastPong) {
+ if (first.lastPing != first.lastPong || !first.initDone) {
if(curMess != 1) DisplayMessage("", _("Waiting for first chess program")); curMess = 1;
ScheduleDelayedEvent(TwoMachinesEventIfReady, 10); // [HGM] fast: lowered from 1000
return;
fprintf(f, "-loadPositionFile \"%s\"\n", appData.loadPositionFile);
fprintf(f, "-loadPositionIndex %d\n", appData.loadPositionIndex);
fprintf(f, "-rewindIndex %d\n", appData.rewindIndex);
+ fprintf(f, "-usePolyglotBook %s\n", appData.usePolyglotBook ? "true" : "false");
+ fprintf(f, "-polyglotBook %s\n", appData.polyglotBook);
+ fprintf(f, "-bookDepth %d\n", appData.bookDepth);
+ fprintf(f, "-bookVariation %d\n", appData.bookStrength);
fprintf(f, "-discourageOwnBooks %s\n", appData.defNoBook ? "true" : "false");
+ fprintf(f, "-defaultHashSize %d\n", appData.defaultHashSize);
+ fprintf(f, "-defaultCacheSizeEGTB %d\n", appData.defaultCacheSizeEGTB);
+ fprintf(f, "-ponderNextMove %s\n", appData.ponderNextMove ? "true" : "false");
+ fprintf(f, "-smpCores %d\n", appData.smpCores);
if(searchTime > 0)
fprintf(f, "-searchTime \"%d:%02d\"\n", searchTime/60, searchTime%60);
else {
ParseArgsFromString(resetOptions); appData.fenOverride[0] = NULL; appData.pvSAN[0] = FALSE;
appData.firstHasOwnBookUCI = !appData.defNoBook; appData.protocolVersion[0] = PROTOVER;
ParseArgsFromString(buf);
+ } else { // no engine with this nickname is installed!
+ snprintf(buf, MSG_SIZ, _("No engine %s is installed"), engineName);
+ ReserveGame(nextGame, ' '); // unreserve game and drop out of match mode with error
+ matchMode = FALSE; appData.matchGames = matchGame = roundNr = 0;
+ ModeHighlight();
+ DisplayError(buf, 0);
+ return 0;
}
free(engineName);
return i;
NextTourneyGame (int nr, int *swapColors)
{ // !!!major kludge!!! fiddle appData settings to get everything in order for next tourney game
char *p, *q;
- int whitePlayer, blackPlayer, firstBusy=1000000000, syncInterval = 0, nPlayers;
+ int whitePlayer, blackPlayer, firstBusy=1000000000, syncInterval = 0, nPlayers, OK = 1;
FILE *tf;
if(appData.tourneyFile[0] == NULLCHAR) return 1; // no tourney, always allow next game
tf = fopen(appData.tourneyFile, "r");
// redefine engines, engine dir, etc.
NamesToList(firstChessProgramNames, command, mnemonic, "all"); // get mnemonics of installed engines
if(first.pr == NoProc) {
- SetPlayer(whitePlayer, appData.participants); // find white player amongst it, and parse its engine line
+ if(!SetPlayer(whitePlayer, appData.participants)) OK = 0; // find white player amongst it, and parse its engine line
InitEngine(&first, 0); // initialize ChessProgramStates based on new settings.
}
if(second.pr == NoProc) {
SwapEngines(1);
- SetPlayer(blackPlayer, appData.participants); // find black player amongst it, and parse its engine line
+ if(!SetPlayer(blackPlayer, appData.participants)) OK = 0; // find black player amongst it, and parse its engine line
SwapEngines(1); // and make that valid for second engine by swapping
InitEngine(&second, 1);
}
CommonEngineInit(); // after this TwoMachinesEvent will create correct engine processes
UpdateLogos(FALSE); // leave display to ModeHiglight()
- return 1;
+ return OK;
}
void
resultDetails = buf;
}
/* (Claiming a loss is accepted no questions asked!) */
+ } else if(matchMode && result == GameIsDrawn && !strcmp(resultDetails, "Engine Abort Request")) {
+ forwardMostMove = backwardMostMove; // [HGM] delete game to surpress saving
+ result = GameUnfinished;
+ if(!*appData.tourneyFile) matchGame--; // replay even in plain match
}
/* [HGM] bare: don't allow bare King to win */
if((gameInfo.holdingsWidth == 0 || gameInfo.variant == VariantSuper
SendToProgram("quit\n", &first);
DoSleep( appData.delayAfterQuit );
DestroyChildProcess(first.pr, first.useSigterm);
+ first.reload = TRUE;
}
first.pr = NoProc;
}
SendToProgram("quit\n", &second);
DoSleep( appData.delayAfterQuit );
DestroyChildProcess(second.pr, second.useSigterm);
+ second.reload = TRUE;
}
second.pr = NoProc;
}
if (appData.noChessProgram) return 1;
- if(matchMode && appData.tourneyFile[0]) { // [HGM] tourney: make sure we get features after engine replacement. (Should we always do this?)
+ if(matchMode /*&& appData.tourneyFile[0]*/) { // [HGM] tourney: make sure we get features after engine replacement. (Should we always do this?)
if(WaitForEngine(&first, TwoMachinesEventIfReady)) { doInit = 1; return 0; } // request to do init on next visit
if(!doInit) return 1; // this replaces testing first.pr != NoProc, which is true when we get here, but first time no reason to abort
doInit = 0; // we fell through (first time after starting the engine); make sure it doesn't happen again
ScheduleDelayedEvent(cb, val ? 1 : 3600000);
}
cps->initDone = val;
+ if(val) cps->reload = FALSE;
}
/* Parse feature command from engine */
if (BoolFeature(&p, "smp", &cps->maxCores, cps)) continue;
if (StringFeature(&p, "egt", cps->egtFormats, cps)) continue;
if (StringFeature(&p, "option", buf, cps)) {
+ if(cps->reload) continue; // we are reloading because of xreuse
FREE(cps->option[cps->nrOptions].name);
cps->option[cps->nrOptions].name = malloc(MSG_SIZ);
safeStrCpy(cps->option[cps->nrOptions].name, buf, MSG_SIZ);