Introduce VariantFamily PGN tag
authorH.G.Muller <hgm@hgm-xboard.(none)>
Mon, 4 Jul 2022 17:03:45 +0000 (19:03 +0200)
committerH.G.Muller <hgm@hgm-xboard.(none)>
Mon, 4 Jul 2022 17:03:45 +0000 (19:03 +0200)
For engine-defined variants this indicates the parent variant.
When a game with this tag is loaded a variant switch is always forced.

backend.c
pgntags.c

index b6eea66..766838c 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -13381,7 +13381,7 @@ LoadGame (FILE *f, int gameNumber, char *title, int useList)
     int err, pos = -1;
     GameMode oldGameMode;
     VariantClass v, oldVariant = gameInfo.variant; /* [HGM] PGNvariant */
-    char oldName[MSG_SIZ];
+    char oldName[MSG_SIZ], vs = 0;
 
     safeStrCpy(oldName, engineVariant, MSG_SIZ); v = oldVariant;
 
@@ -13600,11 +13600,12 @@ LoadGame (FILE *f, int gameNumber, char *title, int useList)
        if (!err) numPGNTags++;
 
         /* [HGM] PGNvariant: automatically switch to variant given in PGN tag */
-        if(gameInfo.variant != oldVariant && (gameInfo.variant != VariantNormal || gameInfo.variantName == NULL || *gameInfo.variantName == NULLCHAR)) {
+        if(gameInfo.variant != oldVariant && gameInfo.variant != VariantUnknown &&
+          (gameInfo.variant != VariantNormal || gameInfo.variantName == NULL || *gameInfo.variantName == NULLCHAR) || vs) {
             startedFromPositionFile = FALSE; /* [HGM] loadPos: variant switch likely makes position invalid */
            ResetFrontEnd(); // [HGM] might need other bitmaps. Cannot use Reset() because it clears gameInfo :-(
            InitPosition(TRUE);
-            oldVariant = gameInfo.variant;
+            oldVariant = gameInfo.variant; vs++; // force obeying second variant switch
            if (appData.debugMode)
              fprintf(debugFP, "New variant %d\n", (int) oldVariant);
         }
index 9833d10..2321837 100644 (file)
--- a/pgntags.c
+++ b/pgntags.c
@@ -115,9 +115,14 @@ ParsePGNTag (char *tag, GameInfo *gameInfo)
        success = TRUE;
     } else if (StrCaseCmp(name, "Variant") == 0) {
         /* xboard-defined extension */
+        int oldVariant = gameInfo->variant;
        success = StrSavePtr(value, &gameInfo->variantName) != NULL;
         if(*value && strcmp(value, engineVariant)) // keep current engine-defined variant if it matches
             gameInfo->variant = StringToVariant(value);
+        if(oldVariant != VariantNormal) safeStrCpy(engineVariant, value, MSG_SIZ);
+    } else if (StrCaseCmp(name, "VariantFamily") == 0) {
+        /* xboard-defined extension */
+        gameInfo->variant = StringToVariant(value);
     } else if (StrCaseCmp(name, "VariantMen") == 0) {
         success = LoadPieceDesc(value);
     } else if (StrCaseCmp(name, PGN_OUT_OF_BOOK) == 0) {
@@ -162,8 +167,15 @@ PrintPGNTags (FILE *fp, GameInfo *gameInfo)
        fprintf(fp, "[BlackElo \"%d\"]\n", gameInfo->blackRating);
     if (gameInfo->timeControl)
        fprintf(fp, "[TimeControl \"%s\"]\n", gameInfo->timeControl);
-    if (gameInfo->variant != VariantNormal)
+    if (gameInfo->variant != VariantNormal) {
+       char c = *engineVariant;
         fprintf(fp, "[Variant \"%s\"]\n", VariantName(gameInfo->variant));
+       if(c) {
+           *engineVariant = NULLCHAR;
+           fprintf(fp, "[VariantFamily \"%s\"]\n", VariantName(gameInfo->variant));
+            *engineVariant = c;
+        }
+    }
     if (*(p = CollectPieceDescriptors()))
         fprintf(fp, "[VariantMen \"%s\"]\n", p);
     if (gameInfo->extraTags)
@@ -192,7 +204,7 @@ PGNTags (GameInfo *gameInfo)
     if (gameInfo->whiteRating >= 0) len += 40;
     if (gameInfo->blackRating >= 0) len += 40;
     if (gameInfo->timeControl) len += strlen(gameInfo->timeControl) + 20;
-    if (gameInfo->variant != VariantNormal) len += 50;
+    if (gameInfo->variant != VariantNormal) len += strlen(engineVariant) + 150;
     if (gameInfo->extraTags) len += strlen(gameInfo->extraTags);
 
     buf = malloc(len);
@@ -213,8 +225,15 @@ PGNTags (GameInfo *gameInfo)
        p += sprintf(p, "[BlackElo \"%d\"]\n", gameInfo->blackRating);
     if (gameInfo->timeControl)
        p += sprintf(p, "[TimeControl \"%s\"]\n", gameInfo->timeControl);
-    if (gameInfo->variant != VariantNormal)
-        p += sprintf(p, "[Variant \"%s\"]\n", VariantName(gameInfo->variant));
+    if (gameInfo->variant != VariantNormal) {
+       char c = *engineVariant;
+       p += sprintf(p, "[Variant \"%s\"]\n", VariantName(gameInfo->variant));
+       if(c) {
+           *engineVariant = NULLCHAR;
+           p += sprintf(p, "[VariantFamily \"%s\"]\n", VariantName(gameInfo->variant));
+            *engineVariant = c;
+        }
+    }
     if (gameInfo->extraTags)
        strcpy(p, gameInfo->extraTags);
     return buf;