Allow engine to define its own variant names
authorH.G. Muller <h.g.muller@hccnet.nl>
Sat, 31 Aug 2013 21:31:52 +0000 (23:31 +0200)
committerH.G. Muller <h.g.muller@hccnet.nl>
Sat, 31 Aug 2013 21:31:52 +0000 (23:31 +0200)
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
backend.h
dialogs.c
winboard/resource.h
winboard/winboard.rc
winboard/woptions.c

index 94d715d..2da18a9 100644 (file)
--- 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)
 {
index 6b750df..c82c989 100644 (file)
--- 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));
index 05aff38..bfab653 100644 (file)
--- 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);
 }
 
index 62d7406..0cebfcf 100644 (file)
 #define OPT_VariantSpartan              1531\r
 #define OPT_VariantASEAN                1532\r
 #define OPT_VariantGrand                1534\r
+#define OPT_EngineVariant               1560\r
 #define IDC_Files                       1550\r
 #define IDC_Ranks                       1551\r
 #define IDC_Holdings                    1552\r
index 2656e7b..86428cb 100644 (file)
@@ -757,16 +757,25 @@ BEGIN
                     10\r
     CONTROL         "&xiangqi",OPT_VariantXiangqi,"Button",BS_AUTORADIOBUTTON,154,114,70,\r
                     10\r
-    GROUPBOX        "Variant",GPB_Variant,4,4,215,125\r
-    LTEXT           "Board size:",GPB_Board,10,165,40,8,WS_TABSTOP\r
-    LTEXT           "ranks",IDC_Height,77,165,38,8\r
-    EDITTEXT        IDC_Ranks,60,161,14,14,ES_AUTOHSCROLL\r
-    LTEXT           "files",IDC_Width,133,165,80,8\r
-    EDITTEXT        IDC_Files,116,161,14,14,ES_AUTOHSCROLL\r
-    LTEXT           "Holdings with room for:",IDC_Hand,10,183,90,8\r
-    EDITTEXT        IDC_Holdings,93,179,14,14,ES_AUTOHSCROLL\r
-    LTEXT           "pieces",IDC_Pieces,110,183,100,8\r
-    LTEXT           "('-1' means defaults for selected variant)",IDC_Def,10,201,210,8\r
+    CONTROL         "",OPT_EngineVariant+0,"Button",BS_AUTORADIOBUTTON,9,134,70,10\r
+    CONTROL         "",OPT_EngineVariant+1,"Button",BS_AUTORADIOBUTTON,80,134,70,10\r
+    CONTROL         "",OPT_EngineVariant+2,"Button",BS_AUTORADIOBUTTON,154,134,70,10\r
+    CONTROL         "",OPT_EngineVariant+3,"Button",BS_AUTORADIOBUTTON,9,144,70,10\r
+    CONTROL         "",OPT_EngineVariant+4,"Button",BS_AUTORADIOBUTTON,80,144,70,10\r
+    CONTROL         "",OPT_EngineVariant+5,"Button",BS_AUTORADIOBUTTON,154,144,70,10\r
+    CONTROL         "",OPT_EngineVariant+6,"Button",BS_AUTORADIOBUTTON,9,154,70,10\r
+    CONTROL         "",OPT_EngineVariant+7,"Button",BS_AUTORADIOBUTTON,80,154,70,10\r
+    CONTROL         "",OPT_EngineVariant+8,"Button",BS_AUTORADIOBUTTON,154,154,70,10\r
+    GROUPBOX        "Variant",GPB_Variant,4,4,215,165\r
+    LTEXT           "Board size:",GPB_Board,10,183,40,8,WS_TABSTOP\r
+    LTEXT           "ranks",IDC_Height,77,183,38,8\r
+    EDITTEXT        IDC_Ranks,60,179,14,14,ES_AUTOHSCROLL\r
+    LTEXT           "files",IDC_Width,133,183,80,8\r
+    EDITTEXT        IDC_Files,116,179,14,14,ES_AUTOHSCROLL\r
+    LTEXT           "Holdings with room for:",IDC_Hand,10,201,90,8\r
+    EDITTEXT        IDC_Holdings,93,197,14,14,ES_AUTOHSCROLL\r
+    LTEXT           "pieces",IDC_Pieces,110,201,100,8\r
+    LTEXT           "('-1' means defaults for selected variant)",IDC_Def,10,217,210,8\r
     DEFPUSHBUTTON   "OK",IDOK,114,232,50,14\r
     PUSHBUTTON      "Cancel",IDCANCEL,170,232,50,14\r
 END\r
index 41f090f..b997fd4 100644 (file)
@@ -874,6 +874,12 @@ VariantWhichRadio(HWND hDlg)
        if(IsDlgButtonChecked(hDlg, j) &&\r
           (appData.noChessProgram || strstr(first.variants, VariantName(i-1)))) return (VariantClass) i-1;\r
   }\r
+  for(i=0; i<9; i++) { // check for engine-defined variants\r
+    if(IsDlgButtonChecked(hDlg, OPT_EngineVariant+i) ) {\r
+       GetDlgItemText(hDlg, OPT_EngineVariant+i, engineVariant, MSG_SIZ); // remember name, so we can resolve it later\r
+       return VariantUnknown;\r
+    }\r
+  }\r
   return gameInfo.variant; // If no button checked, keep old\r
 }\r
 \r
@@ -886,6 +892,13 @@ VariantShowRadio(HWND hDlg)
        if(j == -1) continue; // no menu button\r
        EnableWindow(GetDlgItem(hDlg, j), appData.noChessProgram || strstr(first.variants, VariantName(i-1)));\r
   }\r
+  for(i=0; i<9; i++) { // initialize engine-defined variants\r
+    char *v = EngineDefinedVariant(&first, i); // get name of #i\r
+    if(v) { // there is such a variant\r
+       EnableWindow(GetDlgItem(hDlg, OPT_EngineVariant+i), TRUE);     // and enable the button\r
+       SetDlgItemText(hDlg, OPT_EngineVariant+i, v);                  // put its name on button\r
+    } else EnableWindow(GetDlgItem(hDlg, OPT_EngineVariant+i), FALSE); // no such variant; disable button\r
+  }\r
 }\r
 \r
 LRESULT CALLBACK\r
@@ -1403,6 +1416,7 @@ IcsOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       UpdateSampleText(hDlg, OPT_SampleSeek, &mca[ColorSeek]);\r
       break;\r
 \r
+\r
     case OPT_ChooseNormalColor:\r
       ColorizeTextPopup(hDlg, ColorNormal);\r
       UpdateSampleText(hDlg, OPT_SampleNormal, &mca[ColorNormal]);\r