static void ExcludeClick P((int index));
void ToggleSecond P((void));
void PauseEngine P((ChessProgramState *cps));
+static int NonStandardBoardSize P((void));
#ifdef WIN32
extern void ConsoleCreate();
{
dst[ count-1 ] = '\0'; // make sure incomplete copy still null-terminated
if(appData.debugMode)
- fprintf(debugFP, "safeStrCpy: copying %s into %s didn't work, not enough space %d\n",src,dst, (int)count);
+ fprintf(debugFP, "safeStrCpy: copying %s into %s didn't work, not enough space %d\n",src,dst, (int)count);
}
return dst;
cps->sendName = appData.icsActive;
cps->sdKludge = FALSE;
cps->stKludge = FALSE;
+ if(cps->tidy == NULL) cps->tidy = (char*) malloc(MSG_SIZ);
TidyProgramName(cps->program, cps->host, cps->tidy);
cps->matchWins = 0;
- safeStrCpy(cps->variants, appData.variant, MSG_SIZ);
+ ASSIGN(cps->variants, appData.variant);
cps->analysisSupport = 2; /* detect */
cps->analyzing = FALSE;
cps->initDone = FALSE;
cps->supportsNPS = UNKNOWN;
cps->memSize = FALSE;
cps->maxCores = FALSE;
- cps->egtFormats[0] = NULLCHAR;
+ ASSIGN(cps->egtFormats, "");
/* [HGM] options */
cps->optionSettings = appData.engOptions[n];
InitBackEnd2 ()
{
if (appData.debugMode) {
- fprintf(debugFP, "%s\n", programVersion);
+# ifdef __GIT_VERSION
+ fprintf(debugFP, "Version: %s (%s)\n", programVersion, __GIT_VERSION);
+# else
+ fprintf(debugFP, "Version: %s\n", programVersion);
+# endif
}
ASSIGN(currentDebugFile, appData.nameOfDebugFile); // [HGM] debug split: remember initial name in use
}
}
if (appData.debugMode) {
- fprintf(debugFP, _("recognized '%s' (%d) as variant %s\n"),
+ fprintf(debugFP, "recognized '%s' (%d) as variant %s\n",
e, wnum, VariantName(v));
}
return v;
gameInfo.whiteRating = string_to_rating(star_match[1]);
gameInfo.blackRating = string_to_rating(star_match[3]);
if (appData.debugMode)
- fprintf(debugFP, _("Ratings from header: W %d, B %d\n"),
+ fprintf(debugFP, "Ratings from header: W %d, B %d\n",
gameInfo.whiteRating, gameInfo.blackRating);
}
continue;
newGame = FALSE;
if (appData.debugMode)
- fprintf(debugFP, _("Parsing board: %s\n"), string);
+ fprintf(debugFP, "Parsing board: %s\n", string);
move_str[0] = NULLCHAR;
elapsed_time[0] = NULLCHAR;
partnerUp = 0; flipView = !flipView; } // [HGM] dual
snprintf(partnerStatus, MSG_SIZ,"W: %d:%02d B: %d:%02d (%d-%d) %c", white_time*fac/60000, (white_time*fac%60000)/1000,
(black_time*fac/60000), (black_time*fac%60000)/1000, white_stren, black_stren, to_play);
- DisplayMessage(partnerStatus, "");
+ if(!twoBoards) DisplayMessage(partnerStatus, "");
partnerBoardValid = TRUE;
return;
}
to canonical algebraic form. */
if (moveNum > 0) {
if (appData.debugMode) {
- if (appData.debugMode) { int f = forwardMostMove;
- fprintf(debugFP, "parseboard %d, castling = %d %d %d %d %d %d\n", f,
- boards[f][CASTLING][0],boards[f][CASTLING][1],boards[f][CASTLING][2],
- boards[f][CASTLING][3],boards[f][CASTLING][4],boards[f][CASTLING][5]);
- }
+ int f = forwardMostMove;
+ fprintf(debugFP, "parseboard %d, castling = %d %d %d %d %d %d\n", f,
+ boards[f][CASTLING][0],boards[f][CASTLING][1],boards[f][CASTLING][2],
+ boards[f][CASTLING][3],boards[f][CASTLING][4],boards[f][CASTLING][5]);
fprintf(debugFP, "accepted move %s from ICS, parse it.\n", move_str);
fprintf(debugFP, "moveNum = %d\n", moveNum);
fprintf(debugFP, "board = %d-%d x %d\n", BOARD_LEFT, BOARD_RGHT, BOARD_HEIGHT);
}
promoDefaultAltered = FALSE;
MarkTargetSquares(1);
- if(!second || appData.oneClick && !OnlyMove(&x, &y, TRUE)) {
+ if(!(second && appData.oneClick && OnlyMove(&x, &y, TRUE))) {
if (appData.highlightDragging) {
SetHighlights(x, y, -1, -1);
} else {
second = sweepSelecting = 0;
fromX = fromY = -1;
gatingPiece = EmptySquare;
+ MarkTargetSquares(1);
ClearHighlights();
gotPremove = 0;
ClearPremoveHighlights();
case MT_NONE:
default:
break;
+ case MT_STEALMATE:
case MT_STALEMATE:
case MT_STAINMATE:
reason = "Xboard adjudication: Stalemate";
SendToProgram("force\n", cps);
cps->bookSuspend = TRUE; // flag indicating it has to be restarted
}
+ if(bookHit) setboardSpoiledMachineBlack = FALSE; // suppress 'go' in SendMoveToProgram
if(!initial) SendMoveToProgram(moveNr, cps); // with hit on initial position there is no move
// now arrange restart after book miss
if(bookHit) {
return; // [HGM] This return was missing, causing option features to be recognized as non-compliant commands!
}
- if ((!appData.testLegality || gameInfo.variant == VariantFairy) &&
- !strncmp(message, "setup ", 6)) { // [HGM] allow first engine to define opening position
+ if (!strncmp(message, "setup ", 6) &&
+ (!appData.testLegality || gameInfo.variant == VariantFairy || NonStandardBoardSize())
+ ) { // [HGM] allow first engine to define opening position
int dummy, s=6; char buf[MSG_SIZ];
if(appData.icsActive || forwardMostMove != 0 || cps != &first) return;
if(sscanf(message, "setup (%s", buf) == 1) s = 8 + strlen(buf), buf[s-9] = NULLCHAR, SetCharTable(pieceToChar, buf);
if(startedFromSetupPosition) return;
+ if(sscanf(message+s, "%dx%d+%d", &dummy, &dummy, &dummy) == 3) while(message[s] && message[s++] != ' '); // for compatibility with Alien Edition
ParseFEN(boards[0], &dummy, message+s);
DrawPosition(TRUE, boards[0]);
startedFromSetupPosition = TRUE;
}
}
+static int
+NonStandardBoardSize ()
+{
+ /* [HGM] Awkward testing. Should really be a table */
+ int overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;
+ if( gameInfo.variant == VariantXiangqi )
+ overruled = gameInfo.boardWidth != 9 || gameInfo.boardHeight != 10 || gameInfo.holdingsSize != 0;
+ if( gameInfo.variant == VariantShogi )
+ overruled = gameInfo.boardWidth != 9 || gameInfo.boardHeight != 9 || gameInfo.holdingsSize != 7;
+ if( gameInfo.variant == VariantBughouse || gameInfo.variant == VariantCrazyhouse )
+ overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 5;
+ if( gameInfo.variant == VariantCapablanca || gameInfo.variant == VariantCapaRandom ||
+ gameInfo.variant == VariantGothic || gameInfo.variant == VariantFalcon || gameInfo.variant == VariantJanus )
+ overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;
+ if( gameInfo.variant == VariantCourier )
+ overruled = gameInfo.boardWidth != 12 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;
+ if( gameInfo.variant == VariantSuper )
+ overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 8;
+ if( gameInfo.variant == VariantGreat )
+ overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 8;
+ if( gameInfo.variant == VariantSChess )
+ overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 7;
+ if( gameInfo.variant == VariantGrand )
+ overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 10 || gameInfo.holdingsSize != 7;
+ return overruled;
+}
+
void
InitChessProgram (ChessProgramState *cps, int setup)
/* setup needed to setup FRC opening position */
{
- char buf[MSG_SIZ], b[MSG_SIZ]; int overruled;
+ char buf[MSG_SIZ], b[MSG_SIZ];
if (appData.noChessProgram) return;
hintRequested = FALSE;
bookRequested = FALSE;
return;
}
- /* [HGM] make prefix for non-standard board size. Awkward testing... */
- overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;
- if( gameInfo.variant == VariantXiangqi )
- overruled = gameInfo.boardWidth != 9 || gameInfo.boardHeight != 10 || gameInfo.holdingsSize != 0;
- if( gameInfo.variant == VariantShogi )
- overruled = gameInfo.boardWidth != 9 || gameInfo.boardHeight != 9 || gameInfo.holdingsSize != 7;
- if( gameInfo.variant == VariantBughouse || gameInfo.variant == VariantCrazyhouse )
- overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 5;
- if( gameInfo.variant == VariantCapablanca || gameInfo.variant == VariantCapaRandom ||
- gameInfo.variant == VariantGothic || gameInfo.variant == VariantFalcon || gameInfo.variant == VariantJanus )
- overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;
- if( gameInfo.variant == VariantCourier )
- overruled = gameInfo.boardWidth != 12 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0;
- if( gameInfo.variant == VariantSuper )
- overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 8;
- if( gameInfo.variant == VariantGreat )
- overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 8;
- if( gameInfo.variant == VariantSChess )
- overruled = gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 7;
- if( gameInfo.variant == VariantGrand )
- overruled = gameInfo.boardWidth != 10 || gameInfo.boardHeight != 10 || gameInfo.holdingsSize != 7;
-
- if(overruled) {
+ if(NonStandardBoardSize()) { /* [HGM] make prefix for non-standard board size. */
snprintf(b, MSG_SIZ, "%dx%d+%d_%s", gameInfo.boardWidth, gameInfo.boardHeight,
gameInfo.holdingsSize, VariantName(gameInfo.variant)); // cook up sized variant name
/* [HGM] varsize: try first if this defiant size variant is specifically known */
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, "-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");
else
SaveGameToFile(appData.saveGameFile, TRUE);
} else if (appData.autoSaveGames) {
- AutoSaveGame();
+ if(gameMode != IcsObserving || !appData.onlyOwn) AutoSaveGame();
}
if (*appData.savePositionFile != NULLCHAR) {
SavePositionToFile(appData.savePositionFile);
if (gameMode != PlayFromGameFile && gameMode != AnalyzeFile)
return FALSE;
- if (gameMode == AnalyzeFile && currentMove > backwardMostMove) {
+ if (gameMode == AnalyzeFile && currentMove > backwardMostMove && programStats.depth) {
pvInfoList[currentMove].depth = programStats.depth;
pvInfoList[currentMove].score = programStats.score;
pvInfoList[currentMove].time = 0;
if(currentMove < forwardMostMove) AppendComment(currentMove+1, lastPV[0], 2);
+ else { // append analysis of final position as comment
+ char buf[MSG_SIZ];
+ snprintf(buf, MSG_SIZ, "{final score %+4.2f/%d}", programStats.score/100., programStats.depth);
+ AppendComment(currentMove, buf, 3); // the 3 prevents stripping of the score/depth!
+ }
+ programStats.depth = 0;
}
if (currentMove >= forwardMostMove) {
if(gameMode == AnalyzeFile) {
if(appData.loadGameIndex == -1) {
- GameEnds(EndOfFile, NULL, GE_FILE);
+ GameEnds(gameInfo.result, gameInfo.resultDetails ? gameInfo.resultDetails : "", GE_FILE);
ScheduleDelayedEvent(AnalyzeNextGame, 10);
} else {
ExitAnalyzeMode(); SendToProgram("force\n", &first);
PackMove (int fromX, int fromY, int toX, int toY, ChessSquare promoPiece)
{
int sq = fromX + (fromY<<4);
- int piece = quickBoard[sq];
+ int piece = quickBoard[sq], rook;
quickBoard[sq] = 0;
moveDatabase[movePtr].to = pieceList[piece] = sq = toX + (toY<<4);
- if(piece == pieceList[1] && fromY == toY && (toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
+ if(piece == pieceList[1] && fromY == toY) {
+ if((toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
int from = toX>fromX ? BOARD_RGHT-1 : BOARD_LEFT;
moveDatabase[movePtr++].piece = Q_WCASTL;
quickBoard[sq] = piece;
piece = quickBoard[from]; quickBoard[from] = 0;
moveDatabase[movePtr].to = pieceList[piece] = sq = toX>fromX ? sq-1 : sq+1;
+ } else if((rook = quickBoard[sq]) && pieceType[rook] == WhiteRook) { // FRC castling
+ quickBoard[sq] = 0; // remove Rook
+ moveDatabase[movePtr].to = sq = (toX>fromX ? BOARD_RGHT-2 : BOARD_LEFT+2); // King to-square
+ moveDatabase[movePtr++].piece = Q_WCASTL;
+ quickBoard[sq] = pieceList[1]; // put King
+ piece = rook;
+ moveDatabase[movePtr].to = pieceList[rook] = sq = toX>fromX ? sq-1 : sq+1;
+ }
} else
- if(piece == pieceList[2] && fromY == toY && (toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
+ if(piece == pieceList[2] && fromY == toY) {
+ if((toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
int from = (toX>fromX ? BOARD_RGHT-1 : BOARD_LEFT) + (BOARD_HEIGHT-1 <<4);
moveDatabase[movePtr++].piece = Q_BCASTL;
quickBoard[sq] = piece;
piece = quickBoard[from]; quickBoard[from] = 0;
moveDatabase[movePtr].to = pieceList[piece] = sq = toX>fromX ? sq-1 : sq+1;
+ } else if((rook = quickBoard[sq]) && pieceType[rook] == BlackRook) { // FRC castling
+ quickBoard[sq] = 0; // remove Rook
+ moveDatabase[movePtr].to = sq = (toX>fromX ? BOARD_RGHT-2 : BOARD_LEFT+2);
+ moveDatabase[movePtr++].piece = Q_BCASTL;
+ quickBoard[sq] = pieceList[2]; // put King
+ piece = rook;
+ moveDatabase[movePtr].to = pieceList[rook] = sq = toX>fromX ? sq-1 : sq+1;
+ }
} else
if(epOK && (pieceType[piece] == WhitePawn || pieceType[piece] == BlackPawn) && fromX != toX && quickBoard[sq] == 0) {
quickBoard[(fromY<<4)+toX] = 0;
gn = 1;
}
else {
- if(gameMode == AnalyzeFile && appData.loadGameIndex == -1)
+ if(oldGameMode == 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);
HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove-1);
- if (oldGameMode == AnalyzeFile ||
- oldGameMode == AnalyzeMode) {
+ if (oldGameMode == AnalyzeFile) {
appData.loadGameIndex = -1; // [HGM] order auto-stepping through games
AnalyzeFileEvent();
+ } else
+ if (oldGameMode == AnalyzeMode) {
+ AnalyzeFileEvent();
}
if(creatingBook) return TRUE;
/* secure check */
if (appData.icsEngineAnalyze) {
if (appData.debugMode)
- fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
+ fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
ExitAnalyzeMode();
ModeHighlight();
}
}
appData.icsEngineAnalyze = TRUE;
if (appData.debugMode)
- fprintf(debugFP, _("ICS engine analyze starting... \n"));
+ fprintf(debugFP, "ICS engine analyze starting... \n");
}
if (gameMode == AnalyzeMode) { ToggleSecond(); return 0; }
CreateBookEvent ()
{
ListGame * lg = (ListGame *) gameList.head;
- FILE *f;
+ FILE *f, *g;
int nItem;
static int secondTime = FALSE;
return;
}
- if(!secondTime && (f = fopen(appData.polyglotBook, "r"))) {
- fclose(f);
+ if(!secondTime && (g = fopen(appData.polyglotBook, "r"))) {
+ fclose(g);
secondTime++;
DisplayNote(_("Book file exists! Try again for overwrite."));
return;
int oldlen, len;
char *old;
-if(appData.debugMode) fprintf(debugFP, "Append: in='%s' %d\n", text, addBraces); fflush(debugFP);
+if(appData.debugMode) fprintf(debugFP, "Append: in='%s' %d\n", text, addBraces);
+ if(addBraces == 3) addBraces = 0; else // force appending literally
text = GetInfoFromComment( index, text ); /* [HGM] PV time: strip PV info from comment */
CrushCRs(text);
int time = -1, sec = 0, deci;
char * s_eval = FindStr( text, "[%eval " );
char * s_emt = FindStr( text, "[%emt " );
-
+#if 0
if( s_eval != NULL || s_emt != NULL ) {
+#else
+ if(0) { // [HGM] this code is not finished, and could actually be detrimental
+#endif
/* New style */
char delim;
}
p = text;
+ if(!strncmp(p+1, "final score ", 12)) p += 12, index++; else
if(p[1] == '(') { // comment starts with PV
p = strchr(p, ')'); // locate end of PV
if(p == NULL || sep < p+5) return text;
if(sec >= 0) time = 600*time + 10*sec; else
if(deci >= 0) time = 10*time + deci; else time *= 10; // deci-sec
- score = score >= 0 ? score*100 + score_lo : score*100 - score_lo;
+ score = score > 0 || !score & p[1] != '-' ? score*100 + score_lo : score*100 - score_lo;
/* [HGM] PV time: now locate end of PV info */
while( *++sep >= '0' && *sep <= '9'); // strip depth
}
int
-StringFeature (char **p, char *name, char loc[], ChessProgramState *cps)
+StringFeature (char **p, char *name, char **loc, ChessProgramState *cps)
{
char buf[MSG_SIZ];
int len = strlen(name);
if (strncmp((*p), name, len) == 0
&& (*p)[len] == '=' && (*p)[len+1] == '\"') {
(*p) += len + 2;
- sscanf(*p, "%[^\"]", loc);
+ ASSIGN(*loc, *p); // kludge alert: assign rest of line just to be sure allocation is large enough so that sscanf below always fits
+ sscanf(*p, "%[^\"]", *loc);
while (**p && **p != '\"') (*p)++;
if (**p == '\"') (*p)++;
snprintf(buf, MSG_SIZ, "accepted %s\n", name);
ParseFeatures (char *args, ChessProgramState *cps)
{
char *p = args;
- char *q;
+ char *q = NULL;
int val;
char buf[MSG_SIZ];
continue;
}
if (BoolFeature(&p, "analyze", &cps->analysisSupport, cps)) continue;
- if (StringFeature(&p, "myname", cps->tidy, cps)) {
+ if (StringFeature(&p, "myname", &cps->tidy, cps)) {
if (gameMode == TwoMachinesPlay) {
DisplayTwoMachinesTitle();
} else {
}
continue;
}
- if (StringFeature(&p, "variants", cps->variants, cps)) continue;
+ if (StringFeature(&p, "variants", &cps->variants, cps)) continue;
if (BoolFeature(&p, "san", &cps->useSAN, cps)) continue;
if (BoolFeature(&p, "ping", &cps->usePing, cps)) continue;
if (BoolFeature(&p, "playother", &cps->usePlayother, cps)) continue;
if (IntFeature(&p, "level", &cps->maxNrOfSessions, cps)) continue;
if (BoolFeature(&p, "memory", &cps->memSize, cps)) continue;
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
+ if (StringFeature(&p, "egt", &cps->egtFormats, cps)) continue;
+ if (StringFeature(&p, "option", &q, cps)) { // read to freshly allocated temp buffer first
+ if(cps->reload) { FREE(q); q = NULL; 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);
+ cps->option[cps->nrOptions].name = q; q = NULL;
if(!ParseOption(&(cps->option[cps->nrOptions++]), cps)) { // [HGM] options: add option feature
snprintf(buf, MSG_SIZ, "rejected option %s\n", cps->option[--cps->nrOptions].name);
SendToProgram(buf, cps);