From ce3d0b2034053b0362762fe3b08048ff7df41cf2 Mon Sep 17 00:00:00 2001 From: H.G. Muller Date: Sat, 31 Aug 2013 23:31:52 +0200 Subject: [PATCH] Allow engine to define its own variant names Non-standard variants will appear in the New Variant menu, and when selected will lead to sending of the engine-defined name in the variant comand to the engine. Which then should report with a setup commandto specify parent variant, board & holdings size, piece-to-char table and iitial position. --- backend.c | 41 ++++++++++++++++++++++++++++++++++++++--- backend.h | 2 ++ dialogs.c | 25 +++++++++++++++++++++++++ winboard/resource.h | 1 + winboard/winboard.rc | 29 +++++++++++++++++++---------- winboard/woptions.c | 14 ++++++++++++++ 6 files changed, 99 insertions(+), 13 deletions(-) diff --git a/backend.c b/backend.c index 94d715d..2da18a9 100644 --- a/backend.c +++ b/backend.c @@ -2006,10 +2006,12 @@ StripHighlight (char *s) return retbuf; } +char engineVariant[MSG_SIZ]; char *variantNames[] = VARIANT_NAMES; char * VariantName (VariantClass v) { + if(v == VariantUnknown) return engineVariant; return variantNames[v]; } @@ -8540,13 +8542,24 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. } if (!strncmp(message, "setup ", 6) && - (!appData.testLegality || gameInfo.variant == VariantFairy || NonStandardBoardSize()) + (!appData.testLegality || gameInfo.variant == VariantFairy || gameInfo.variant == VariantUnknown || NonStandardBoardSize()) ) { // [HGM] allow first engine to define opening position - int dummy, s=6; char buf[MSG_SIZ]; + int dummy, w, h, hand, s=6; char buf[MSG_SIZ], varName[MSG_SIZ]; if(appData.icsActive || forwardMostMove != 0 || cps != &first) return; + *buf = NULLCHAR; 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 + dummy = sscanf(message+s, "%dx%d+%d_%s", &w, &h, &hand, varName); + if(dummy >= 3) { + while(message[s] && message[s++] != ' '); + if(BOARD_HEIGHT != h || BOARD_WIDTH != w + 4*(hand != 0) || gameInfo.holdingsSize != hand || + dummy == 4 && gameInfo.variant != StringToVariant(varName) ) { // engine wants to change board format or variant + appData.NrFiles = w; appData.NrRanks = h; appData.holdingsSize = hand; + if(dummy == 4) gameInfo.variant = StringToVariant(varName); // parent variant + InitPosition(1); // calls InitDrawingSizes to let new parameters take effect + if(*buf) SetCharTable(pieceToChar, buf); // do again, for it was spoiled by InitPosition + } + } ParseFEN(boards[0], &dummy, message+s); DrawPosition(TRUE, boards[0]); startedFromSetupPosition = TRUE; @@ -11226,6 +11239,7 @@ Reset (int redraw, int init) lastHint[0] = NULLCHAR; ClearGameInfo(&gameInfo); gameInfo.variant = StringToVariant(appData.variant); + if(gameInfo.variant == VariantNormal && strcmp(appData.variant, "normal")) gameInfo.variant = VariantUnknown; ics_user_moved = ics_clock_paused = FALSE; ics_getting_history = H_FALSE; ics_gamenum = -1; @@ -16066,6 +16080,27 @@ SendTimeRemaining (ChessProgramState *cps, int machineWhite) SendToProgram(message, cps); } +char * +EngineDefinedVariant (ChessProgramState *cps, int n) +{ // return name of n-th unknown variant that engine supports + static char buf[MSG_SIZ]; + char *p, *s = cps->variants; + if(!s) return NULL; + do { // parse string from variants feature + VariantClass v; + p = strchr(s, ','); + if(p) *p = NULLCHAR; + v = StringToVariant(s); + if(v == VariantNormal && strcmp(s, "normal") && !strstr(s, "_normal")) v = VariantUnknown; // garbage is recognized as normal + if(v == VariantUnknown) { // non-standard variant in list of engine-supported variants + if(--n < 0) safeStrCpy(buf, s, MSG_SIZ); + } + if(p) *p++ = ','; + if(n < 0) return buf; + } while(s = p); + return NULL; +} + int BoolFeature (char **p, char *name, int *loc, ChessProgramState *cps) { diff --git a/backend.h b/backend.h index 6b750df..c82c989 100644 --- a/backend.h +++ b/backend.h @@ -440,6 +440,8 @@ extern int errorExitStatus; extern char *recentEngines; extern char *comboLine; extern Boolean partnerUp, twoBoards; +extern char engineVariant[]; +char *EngineDefinedVariant P((ChessProgramState *cps, int n)); void SettingsPopUp P((ChessProgramState *cps)); // [HGM] really in front-end, but CPS not known in frontend.h int WaitForEngine P((ChessProgramState *cps, DelayedEventCallback x)); void Load P((ChessProgramState *cps, int n)); diff --git a/dialogs.c b/dialogs.c index 05aff38..bfab653 100644 --- a/dialogs.c +++ b/dialogs.c @@ -228,6 +228,7 @@ GenericReadout (Option *opts, int selected) case SaveButton: case Label: case Break: + case -1: break; } if(opts[i].type == EndMark) break; @@ -447,6 +448,13 @@ static Option variantDescriptors[] = { { VariantFairy, 0, 135, NULL, (void*) &Pick, "#BFBFBF", NULL, Button, N_("fairy")}, //{ VariantNormal, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, Button, N_(" ")}, // dummy, to have good alignment { VariantCourier, SAME_ROW,135, NULL, (void*) &Pick, "#BFFFBF", NULL, Button, N_("courier (12x8)")}, +// optional buttons for engine-defined variants +{ VariantUnknown, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL }, +{ VariantUnknown, SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL }, +{ VariantUnknown, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL }, +{ VariantUnknown, SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL }, +{ VariantUnknown, 0, 135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL }, +{ VariantUnknown, SAME_ROW,135, NULL, (void*) &Pick, "#FFFFFF", NULL, -1, NULL }, { 0, NO_OK, 0, NULL, NULL, "", NULL, EndMark , "" } }; @@ -454,6 +462,7 @@ static void Pick (int n) { VariantClass v = variantDescriptors[n].value; + if(v == VariantUnknown) safeStrCpy(engineVariant, variantDescriptors[n].name, MSG_SIZ); if(!appData.noChessProgram) { char *name = VariantName(v), buf[MSG_SIZ]; if (first.protocolVersion > 1 && StrStr(first.variants, name) == NULL) { @@ -486,8 +495,24 @@ Pick (int n) void NewVariantProc () { + static int start; + int i, last; if(appData.noChessProgram) sprintf(warning, _("Only bughouse is not available in viewer mode")); else sprintf(warning, _("All variants not supported by first engine\n(currently %s) are disabled"), first.tidy); + if(!start) while(variantDescriptors[start].type != -1) start++; // locate first spare + last = -1; + for(i=0; i<6; i++) { // create buttons for engine-defined variants + char *v = EngineDefinedVariant(&first, i); + if(v) { + last = i; + ASSIGN(variantDescriptors[start+i].name, v); + variantDescriptors[start+i].type = Button; + } else variantDescriptors[start+i].type = -1; + if(!(last&1)) { // odd number, add filler + ASSIGN(variantDescriptors[start+last+1].name, " "); + variantDescriptors[start+last+1].type = Button; + } + } GenericPopUp(variantDescriptors, _("New Variant"), TransientDlg, BoardWindow, MODAL, 0); } diff --git a/winboard/resource.h b/winboard/resource.h index 62d7406..0cebfcf 100644 --- a/winboard/resource.h +++ b/winboard/resource.h @@ -508,6 +508,7 @@ #define OPT_VariantSpartan 1531 #define OPT_VariantASEAN 1532 #define OPT_VariantGrand 1534 +#define OPT_EngineVariant 1560 #define IDC_Files 1550 #define IDC_Ranks 1551 #define IDC_Holdings 1552 diff --git a/winboard/winboard.rc b/winboard/winboard.rc index 2656e7b..86428cb 100644 --- a/winboard/winboard.rc +++ b/winboard/winboard.rc @@ -757,16 +757,25 @@ BEGIN 10 CONTROL "&xiangqi",OPT_VariantXiangqi,"Button",BS_AUTORADIOBUTTON,154,114,70, 10 - GROUPBOX "Variant",GPB_Variant,4,4,215,125 - LTEXT "Board size:",GPB_Board,10,165,40,8,WS_TABSTOP - LTEXT "ranks",IDC_Height,77,165,38,8 - EDITTEXT IDC_Ranks,60,161,14,14,ES_AUTOHSCROLL - LTEXT "files",IDC_Width,133,165,80,8 - EDITTEXT IDC_Files,116,161,14,14,ES_AUTOHSCROLL - LTEXT "Holdings with room for:",IDC_Hand,10,183,90,8 - EDITTEXT IDC_Holdings,93,179,14,14,ES_AUTOHSCROLL - LTEXT "pieces",IDC_Pieces,110,183,100,8 - LTEXT "('-1' means defaults for selected variant)",IDC_Def,10,201,210,8 + CONTROL "",OPT_EngineVariant+0,"Button",BS_AUTORADIOBUTTON,9,134,70,10 + CONTROL "",OPT_EngineVariant+1,"Button",BS_AUTORADIOBUTTON,80,134,70,10 + CONTROL "",OPT_EngineVariant+2,"Button",BS_AUTORADIOBUTTON,154,134,70,10 + CONTROL "",OPT_EngineVariant+3,"Button",BS_AUTORADIOBUTTON,9,144,70,10 + CONTROL "",OPT_EngineVariant+4,"Button",BS_AUTORADIOBUTTON,80,144,70,10 + CONTROL "",OPT_EngineVariant+5,"Button",BS_AUTORADIOBUTTON,154,144,70,10 + CONTROL "",OPT_EngineVariant+6,"Button",BS_AUTORADIOBUTTON,9,154,70,10 + CONTROL "",OPT_EngineVariant+7,"Button",BS_AUTORADIOBUTTON,80,154,70,10 + CONTROL "",OPT_EngineVariant+8,"Button",BS_AUTORADIOBUTTON,154,154,70,10 + GROUPBOX "Variant",GPB_Variant,4,4,215,165 + LTEXT "Board size:",GPB_Board,10,183,40,8,WS_TABSTOP + LTEXT "ranks",IDC_Height,77,183,38,8 + EDITTEXT IDC_Ranks,60,179,14,14,ES_AUTOHSCROLL + LTEXT "files",IDC_Width,133,183,80,8 + EDITTEXT IDC_Files,116,179,14,14,ES_AUTOHSCROLL + LTEXT "Holdings with room for:",IDC_Hand,10,201,90,8 + EDITTEXT IDC_Holdings,93,197,14,14,ES_AUTOHSCROLL + LTEXT "pieces",IDC_Pieces,110,201,100,8 + LTEXT "('-1' means defaults for selected variant)",IDC_Def,10,217,210,8 DEFPUSHBUTTON "OK",IDOK,114,232,50,14 PUSHBUTTON "Cancel",IDCANCEL,170,232,50,14 END diff --git a/winboard/woptions.c b/winboard/woptions.c index 41f090f..b997fd4 100644 --- a/winboard/woptions.c +++ b/winboard/woptions.c @@ -874,6 +874,12 @@ VariantWhichRadio(HWND hDlg) if(IsDlgButtonChecked(hDlg, j) && (appData.noChessProgram || strstr(first.variants, VariantName(i-1)))) return (VariantClass) i-1; } + for(i=0; i<9; i++) { // check for engine-defined variants + if(IsDlgButtonChecked(hDlg, OPT_EngineVariant+i) ) { + GetDlgItemText(hDlg, OPT_EngineVariant+i, engineVariant, MSG_SIZ); // remember name, so we can resolve it later + return VariantUnknown; + } + } return gameInfo.variant; // If no button checked, keep old } @@ -886,6 +892,13 @@ VariantShowRadio(HWND hDlg) if(j == -1) continue; // no menu button EnableWindow(GetDlgItem(hDlg, j), appData.noChessProgram || strstr(first.variants, VariantName(i-1))); } + for(i=0; i<9; i++) { // initialize engine-defined variants + char *v = EngineDefinedVariant(&first, i); // get name of #i + if(v) { // there is such a variant + EnableWindow(GetDlgItem(hDlg, OPT_EngineVariant+i), TRUE); // and enable the button + SetDlgItemText(hDlg, OPT_EngineVariant+i, v); // put its name on button + } else EnableWindow(GetDlgItem(hDlg, OPT_EngineVariant+i), FALSE); // no such variant; disable button + } } LRESULT CALLBACK @@ -1403,6 +1416,7 @@ IcsOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) UpdateSampleText(hDlg, OPT_SampleSeek, &mca[ColorSeek]); break; + case OPT_ChooseNormalColor: ColorizeTextPopup(hDlg, ColorNormal); UpdateSampleText(hDlg, OPT_SampleNormal, &mca[ColorNormal]); -- 1.7.0.4