static void ExcludeClick P((int index));
void ToggleSecond P((void));
void PauseEngine P((ChessProgramState *cps));
-static int NonStandardBoardSize P((void));
+static int NonStandardBoardSize P((VariantClass v, int w, int h, int s));
#ifdef WIN32
extern void ConsoleCreate();
ChessSquare promoSweep = EmptySquare, defaultPromoChoice;
int promoDefaultAltered;
int keepInfo = 0; /* [HGM] to protect PGN tags in auto-step game analysis */
+static int initPing = -1;
/* States for ics_getting_history */
#define H_FALSE 0
}
if (!strncmp(message, "setup ", 6) &&
- (!appData.testLegality || gameInfo.variant == VariantFairy || gameInfo.variant == VariantUnknown || NonStandardBoardSize())
+ (!appData.testLegality || gameInfo.variant == VariantFairy || gameInfo.variant == VariantUnknown ||
+ NonStandardBoardSize(gameInfo.variant, gameInfo.boardWidth, gameInfo.boardHeight, gameInfo.holdingsSize))
) { // [HGM] allow first engine to define opening position
int dummy, w, h, hand, s=6; char buf[MSG_SIZ], varName[MSG_SIZ];
if(appData.icsActive || forwardMostMove != 0 || cps != &first) return;
}
}
if (sscanf(message, "pong %d", &cps->lastPong) == 1) {
+ if(initPing == cps->lastPong) {
+ if(gameInfo.variant == VariantUnknown) {
+ DisplayError(_("Engine did not send setup for non-standard variant"), 0);
+ *engineVariant = NULLCHAR; appData.variant = VariantNormal; // back to normal as error recovery?
+ GameEnds(GameUnfinished, NULL, GE_XBOARD);
+ }
+ initPing = -1;
+ }
return;
}
if(!strncmp(message, "highlight ", 10)) {
}
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 == VariantUnknown || *engineVariant) return 0; // engine-defined name never needs prefix
- 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( gameInfo.variant == VariantChu )
- overruled = gameInfo.boardWidth != 12 || gameInfo.boardHeight != 12 || gameInfo.holdingsSize != 0;
- return overruled;
+NonStandardBoardSize (VariantClass v, int boardWidth, int boardHeight, int holdingsSize)
+{
+ int width = 8, height = 8, holdings = 0; // most common sizes
+ if( v == VariantUnknown || *engineVariant) return 0; // engine-defined name never needs prefix
+ // correct the deviations default for each variant
+ if( v == VariantXiangqi ) width = 9, height = 10;
+ if( v == VariantShogi ) width = 9, height = 9, holdings = 7;
+ if( v == VariantBughouse || v == VariantCrazyhouse) holdings = 5;
+ if( v == VariantCapablanca || v == VariantCapaRandom ||
+ v == VariantGothic || v == VariantFalcon || v == VariantJanus )
+ width = 10;
+ if( v == VariantCourier ) width = 12;
+ if( v == VariantSuper ) holdings = 8;
+ if( v == VariantGreat ) width = 10, holdings = 8;
+ if( v == VariantSChess ) holdings = 7;
+ if( v == VariantGrand ) width = 10, height = 10, holdings = 7;
+ if( v == VariantChu ) width = 12, height = 12;
+ return boardWidth >= 0 && boardWidth != width || // -1 is default,
+ boardHeight >= 0 && boardHeight != height || // and thus by definition OK
+ holdingsSize >= 0 && holdingsSize != holdings;
+}
+
+char variantError[MSG_SIZ];
+
+char *
+SupportedVariant (char *list, VariantClass v, int boardWidth, int boardHeight, int holdingsSize, int proto, char *engine)
+{ // returns error message (recognizable by upper-case) if engine does not support the variant
+ char *p, *variant = VariantName(v);
+ static char b[MSG_SIZ];
+ if(NonStandardBoardSize(v, boardWidth, boardHeight, holdingsSize)) { /* [HGM] make prefix for non-standard board size. */
+ snprintf(b, MSG_SIZ, "%dx%d+%d_%s", boardWidth, boardHeight,
+ holdingsSize, variant); // cook up sized variant name
+ /* [HGM] varsize: try first if this deviant size variant is specifically known */
+ if(StrStr(list, b) == NULL) {
+ // specific sized variant not known, check if general sizing allowed
+ if(proto != 1 && StrStr(list, "boardsize") == NULL) {
+ snprintf(variantError, MSG_SIZ, "Board size %dx%d+%d not supported by %s",
+ boardWidth, boardHeight, holdingsSize, engine);
+ return NULL;
+ }
+ /* [HGM] here we really should compare with the maximum supported board size */
+ }
+ } else snprintf(b, MSG_SIZ,"%s", variant);
+ if(proto == 1) return b; // for protocol 1 we cannot check and hope for the best
+ p = StrStr(list, b);
+ while(p && (p != list && p[-1] != ',' || p[strlen(b)] && p[strlen(b)] != ',') ) p = StrStr(p+1, b);
+ if(p == NULL) {
+ // occurs not at all in list, or only as sub-string
+ snprintf(variantError, MSG_SIZ, _("Variant %s not supported by %s"), b, engine);
+ if(p = StrStr(list, b)) { // handle requesting parent variant when only size-overridden is supported
+ int l = strlen(variantError);
+ char *q;
+ while(p != list && p[-1] != ',') p--;
+ q = strchr(p, ',');
+ if(q) *q = NULLCHAR;
+ snprintf(variantError + l, MSG_SIZ - l, _(", but %s is"), p);
+ if(q) *q= ',';
+ }
+ return NULL;
+ }
+ return b;
}
void
InitChessProgram (ChessProgramState *cps, int setup)
/* setup needed to setup FRC opening position */
{
- char buf[MSG_SIZ], b[MSG_SIZ];
+ char buf[MSG_SIZ], *b;
if (appData.noChessProgram) return;
hintRequested = FALSE;
bookRequested = FALSE;
if (gameInfo.variant != VariantNormal &&
gameInfo.variant != VariantLoadable
/* [HGM] also send variant if board size non-standard */
- || gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0
- ) {
- char *v = VariantName(gameInfo.variant);
- if (cps->protocolVersion != 1 && StrStr(cps->variants, v) == NULL) {
- /* [HGM] in protocol 1 we have to assume all variants valid */
- snprintf(buf, MSG_SIZ, _("Variant %s not supported by %s"), v, cps->tidy);
- DisplayFatalError(buf, 0, 1);
+ || gameInfo.boardWidth != 8 || gameInfo.boardHeight != 8 || gameInfo.holdingsSize != 0) {
+
+ b = SupportedVariant(cps->variants, gameInfo.variant, gameInfo.boardWidth,
+ gameInfo.boardHeight, gameInfo.holdingsSize, cps->protocolVersion, cps->tidy);
+ if (b == NULL) {
+ DisplayFatalError(variantError, 0, 1);
return;
}
- 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 */
- if(StrStr(cps->variants, b) == NULL) {
- // specific sized variant not known, check if general sizing allowed
- if (cps->protocolVersion != 1) { // for protocol 1 we cannot check and hope for the best
- if(StrStr(cps->variants, "boardsize") == NULL) {
- snprintf(buf, MSG_SIZ, "Board size %dx%d+%d not supported by %s",
- gameInfo.boardWidth, gameInfo.boardHeight, gameInfo.holdingsSize, cps->tidy);
- DisplayFatalError(buf, 0, 1);
- return;
- }
- /* [HGM] here we really should compare with the maximum supported board size */
- }
- }
- } else snprintf(b, MSG_SIZ,"%s", VariantName(gameInfo.variant));
snprintf(buf, MSG_SIZ, "variant %s\n", b);
SendToProgram(buf, cps);
}
SendToProgram("easy\n", cps);
}
if (cps->usePing) {
- snprintf(buf, MSG_SIZ, "ping %d\n", ++cps->lastPing);
+ snprintf(buf, MSG_SIZ, "ping %d\n", initPing = ++cps->lastPing);
SendToProgram(buf, cps);
}
cps->initDone = TRUE;
if(currentlyInitializedVariant != gameInfo.variant) {
char buf[MSG_SIZ];
// [HGM] variantswitch: make engine aware of new variant
- if(cps->protocolVersion > 1 && StrStr(cps->variants, VariantName(gameInfo.variant)) == NULL)
+ if(!SupportedVariant(cps->variants, gameInfo.variant, gameInfo.boardWidth,
+ gameInfo.boardHeight, gameInfo.holdingsSize, cps->protocolVersion, ""))
return; // [HGM] refrain from feeding moves altogether if variant is unsupported!
snprintf(buf, MSG_SIZ, "variant %s\n", VariantName(gameInfo.variant));
SendToProgram(buf, cps);
}
if(WaitForEngine(&second, TwoMachinesEventIfReady)) return; // (if needed:) started up second engine, so wait for features
- if(second.protocolVersion >= 2 && !strstr(second.variants, VariantName(gameInfo.variant))) {
+ if(!SupportedVariant(second.variants, gameInfo.variant, gameInfo.boardWidth,
+ gameInfo.boardHeight, gameInfo.holdingsSize, second.protocolVersion, second.tidy)) {
startingEngine = FALSE;
DisplayError("second engine does not play this", 0);
return;
if(x < opts[i].min) x = opts[i].min;
if(opts[i].type == Fractional)
*(float*) opts[i].target = x; // engines never have float options!
- else if(opts[i].value != x) {
- opts[i].value = x;
+ else {
if(currentCps) {
+ if(opts[i].value != x) { // only to engine if changed
snprintf(buf, MSG_SIZ, "option %s=%.0f\n", opts[i].name, x);
SendToProgram(buf, currentCps);
+ }
} else *(int*) opts[i].target = x;
+ opts[i].value = x;
}
break;
case CheckBox:
static void Pick P((int n));
static char warning[MSG_SIZ];
+static int ranksTmp, filesTmp, sizeTmp;
static Option variantDescriptors[] = {
{ VariantNormal, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("Normal")},
{ VariantAtomic, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("Atomic")},
{ VariantTwoKings,SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_("Two kings")},
{ 0, 0, 0, NULL, NULL, NULL, NULL, Label, N_("Board size (-1 = default for selected variant):")},
-{ 0, -1, BOARD_RANKS-1, NULL, (void*) &appData.NrRanks, "", NULL, Spin, N_("Number of Board Ranks:") },
-{ 0, -1, BOARD_FILES, NULL, (void*) &appData.NrFiles, "", NULL, Spin, N_("Number of Board Files:") },
-{ 0, -1, BOARD_RANKS-1, NULL, (void*) &appData.holdingsSize, "", NULL, Spin, N_("Holdings Size:") },
+{ 0, -1, BOARD_RANKS-1, NULL, (void*) &ranksTmp, "", NULL, Spin, N_("Number of Board Ranks:") },
+{ 0, -1, BOARD_FILES, NULL, (void*) &filesTmp, "", NULL, Spin, N_("Number of Board Files:") },
+{ 0, -1, BOARD_RANKS-1, NULL, (void*) &sizeTmp, "", NULL, Spin, N_("Holdings Size:") },
{ 0, 0, 275, NULL, NULL, NULL, NULL, Label, warning },
{ 0, 0, 275, NULL, NULL, NULL, NULL, Label, N_("Variants marked with * can only be played\nwith legality testing off.")},
{ 0, SAME_ROW, 0, NULL, NULL, NULL, NULL, Break, ""},
{
VariantClass v = variantDescriptors[n].value;
if(v == VariantUnknown) safeStrCpy(engineVariant, variantDescriptors[n].name, MSG_SIZ); else *engineVariant = NULLCHAR;
+ GenericReadout(variantDescriptors, -1); // read new ranks and file settings
if(!appData.noChessProgram) {
- char *name = VariantName(v), buf[MSG_SIZ];
- if (first.protocolVersion > 1 && StrStr(first.variants, name) == NULL) {
- /* [HGM] in protocol 2 we check if variant is suported by engine */
- snprintf(buf, MSG_SIZ, _("Variant %s not supported by %s"), name, first.tidy);
- DisplayError(buf, 0);
+ char buf[MSG_SIZ];
+ if (!SupportedVariant(first.variants, v, filesTmp, ranksTmp, sizeTmp, first.protocolVersion, first.tidy)) {
+ DisplayError(variantError, 0);
return; /* ignore OK if first engine does not support it */
} else
- if (second.initDone && second.protocolVersion > 1 && StrStr(second.variants, name) == NULL) {
- snprintf(buf, MSG_SIZ, _("Warning: second engine (%s) does not support this!"), second.tidy);
+ if (second.initDone &&
+ !SupportedVariant(second.variants, v, filesTmp, ranksTmp, sizeTmp, second.protocolVersion, second.tidy)) {
+ snprintf(buf, MSG_SIZ, _("Warning: second engine (%s) does not support this!"), second.tidy);
DisplayError(buf, 0); /* use of second engine is optional; only warn user */
}
}
- GenericReadout(variantDescriptors, -1); // make sure ranks and file settings are read
-
gameInfo.variant = v;
appData.variant = VariantName(v);
shuffleOpenings = FALSE; /* [HGM] shuffle: possible shuffle reset when we switch */
startedFromPositionFile = FALSE; /* [HGM] loadPos: no longer valid in new variant */
+ appData.NrRanks = ranksTmp;
+ appData.NrFiles = filesTmp;
+ appData.holdingsSize = sizeTmp;
appData.pieceToCharTable = NULL;
appData.pieceNickNames = "";
appData.colorNickNames = "";
{
static int start;
int i, last;
+ char buf[MSG_SIZ];
+ ranksTmp = filesTmp = sizeTmp = -1; // prefer defaults over actual settings
if(appData.noChessProgram) sprintf(warning, _("Only bughouse is not available in viewer mode.")); else
sprintf(warning, _("All variants not supported by the first engine\n(currently %s) are disabled."), first.tidy);
if(!start) while(variantDescriptors[start].type != -1) start++; // locate first spare
ASSIGN(variantDescriptors[start+last+1].name, " ");
variantDescriptors[start+last+1].type = Button;
}
+ safeStrCpy(buf, engineVariant, MSG_SIZ); *engineVariant = NULLCHAR; // yeghh...
GenericPopUp(variantDescriptors, _("New Variant"), TransientDlg, BoardWindow, MODAL, 0);
+ safeStrCpy(engineVariant, buf, MSG_SIZ); // must temporarily clear to avoid enabling all variant buttons
}
//------------------------------------------- Common Engine Options -------------------------------------