diff --git a/cube.c b/cube.c index 2ce7a4f..afd2ebd 100644 --- a/cube.c +++ b/cube.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "puzzles.h" @@ -276,6 +277,37 @@ game_params *dup_params(game_params *params) return ret; } +game_params *decode_params(char const *string) +{ + game_params *ret = default_params(); + + switch (*string) { + case 't': ret->solid = TETRAHEDRON; string++; break; + case 'c': ret->solid = CUBE; string++; break; + case 'o': ret->solid = OCTAHEDRON; string++; break; + case 'i': ret->solid = ICOSAHEDRON; string++; break; + default: break; + } + ret->d1 = ret->d2 = atoi(string); + while (*string && isdigit(*string)) string++; + if (*string == 'x') { + string++; + ret->d2 = atoi(string); + } + + return ret; +} + +char *encode_params(game_params *params) +{ + char data[256]; + + assert(params->solid >= 0 && params->solid < 4); + sprintf(data, "%c%dx%d", "tcoi"[params->solid], params->d1, params->d2); + + return dupstr(data); +} + static void enum_grid_squares(game_params *params, void (*callback)(void *, struct grid_square *), void *ctx) @@ -653,7 +685,7 @@ char *new_game_seed(game_params *params, random_state *rs) /* * Choose a non-blue square for the polyhedron. */ - sprintf(p, ":%d", data.gridptrs[0][random_upto(rs, m)]); + sprintf(p, ",%d", data.gridptrs[0][random_upto(rs, m)]); sfree(data.gridptrs[0]); sfree(flags); @@ -824,13 +856,13 @@ char *validate_seed(game_params *params, char *seed) /* NB if seed[j]=='\0' that will also be caught here, so we're safe */ } - if (seed[i] != ':') - return "Expected ':' after hex digits"; + if (seed[i] != ',') + return "Expected ',' after hex digits"; i++; do { if (seed[i] < '0' || seed[i] > '9') - return "Expected decimal integer after ':'"; + return "Expected decimal integer after ','"; i++; } while (seed[i]); @@ -883,7 +915,7 @@ game_state *new_game(game_params *params, char *seed) j = 8; } - if (*p == ':') + if (*p == ',') p++; state->current = atoi(p); diff --git a/fifteen.c b/fifteen.c index 78060f5..2788604 100644 --- a/fifteen.c +++ b/fifteen.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "puzzles.h" @@ -72,6 +73,29 @@ game_params *dup_params(game_params *params) return ret; } +game_params *decode_params(char const *string) +{ + game_params *ret = default_params(); + + ret->w = ret->h = atoi(string); + while (*string && isdigit(*string)) string++; + if (*string == 'x') { + string++; + ret->h = atoi(string); + } + + return ret; +} + +char *encode_params(game_params *params) +{ + char data[256]; + + sprintf(data, "%dx%d", params->w, params->h); + + return dupstr(data); +} + config_item *game_configure(game_params *params) { config_item *ret; diff --git a/midend.c b/midend.c index 63ba193..6a93856 100644 --- a/midend.c +++ b/midend.c @@ -333,7 +333,7 @@ int midend_wants_statusbar(midend_data *me) config_item *midend_get_config(midend_data *me, int which, char **wintitle) { - char *titlebuf; + char *titlebuf, *parstr; config_item *ret; titlebuf = snewn(40 + strlen(game_name), char); @@ -352,7 +352,15 @@ config_item *midend_get_config(midend_data *me, int which, char **wintitle) ret[0].type = C_STRING; ret[0].name = "Game ID"; ret[0].ival = 0; - ret[0].sval = dupstr(me->seed); + /* + * The text going in here will be a string encoding of the + * parameters, plus a colon, plus the game seed. This is a + * full game ID. + */ + parstr = encode_params(me->params); + ret[0].sval = snewn(strlen(parstr) + strlen(me->seed) + 2, char); + sprintf(ret[0].sval, "%s:%s", parstr, me->seed); + sfree(parstr); ret[1].type = C_END; ret[1].name = ret[1].sval = NULL; @@ -367,7 +375,7 @@ config_item *midend_get_config(midend_data *me, int which, char **wintitle) char *midend_set_config(midend_data *me, int which, config_item *cfg) { - char *error; + char *error, *p; game_params *params; switch (which) { @@ -385,12 +393,34 @@ char *midend_set_config(midend_data *me, int which, config_item *cfg) break; case CFG_SEED: - error = validate_seed(me->params, cfg[0].sval); + + /* + * The game ID will often (in fact, mostly) have a prefix + * containing a string-encoded parameter specification + * followed by a colon. So first find the colon, and then + * split the string up. + */ + p = strchr(cfg[0].sval, ':'); + + if (p) { + *p++ = '\0'; /* p now points to game seed */ + params = decode_params(cfg[0].sval); + error = validate_params(params); + if (error) { + free_params(params); + return error; + } + free_params(me->params); + me->params = params; + } else + p = cfg[0].sval; + + error = validate_seed(me->params, p); if (error) return error; sfree(me->seed); - me->seed = dupstr(cfg[0].sval); + me->seed = dupstr(p); me->fresh_seed = TRUE; break; diff --git a/net.c b/net.c index d616d03..3c3f971 100644 --- a/net.c +++ b/net.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "puzzles.h" @@ -183,6 +184,44 @@ game_params *dup_params(game_params *params) return ret; } +game_params *decode_params(char const *string) +{ + game_params *ret = default_params(); + char const *p = string; + + ret->width = atoi(p); + while (*p && isdigit(*p)) p++; + if (*p == 'x') { + p++; + ret->height = atoi(p); + while (*p && isdigit(*p)) p++; + if ( (ret->wrapping = (*p == 'w')) != 0 ) + p++; + if (*p == 'b') + ret->barrier_probability = atof(p+1); + } else { + ret->height = ret->width; + } + + return ret; +} + +char *encode_params(game_params *params) +{ + char ret[400]; + int len; + + len = sprintf(ret, "%dx%d", params->width, params->height); + if (params->wrapping) + ret[len++] = 'w'; + if (params->barrier_probability) + len += sprintf(ret+len, "b%g", params->barrier_probability); + assert(len < lenof(ret)); + ret[len] = '\0'; + + return dupstr(ret); +} + config_item *game_configure(game_params *params) { config_item *ret; diff --git a/nullgame.c b/nullgame.c index 32e6e2c..67982b9 100644 --- a/nullgame.c +++ b/nullgame.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "puzzles.h" @@ -61,6 +62,20 @@ game_params *dup_params(game_params *params) return ret; } +game_params *decode_params(char const *string) +{ + game_params *ret = snew(game_params); + + ret->FIXME = 0; + + return ret; +} + +char *encode_params(game_params *params) +{ + return dupstr("FIXME"); +} + config_item *game_configure(game_params *params) { return NULL; diff --git a/puzzles.h b/puzzles.h index 46c0f15..37c190a 100644 --- a/puzzles.h +++ b/puzzles.h @@ -162,6 +162,8 @@ extern const char *const game_name; const int game_can_configure; game_params *default_params(void); int game_fetch_preset(int i, char **name, game_params **params); +game_params *decode_params(char const *string); +char *encode_params(game_params *); void free_params(game_params *params); game_params *dup_params(game_params *params); config_item *game_configure(game_params *params); diff --git a/rect.c b/rect.c index dcd8ef7..9b7816c 100644 --- a/rect.c +++ b/rect.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include "puzzles.h" @@ -129,6 +130,29 @@ game_params *dup_params(game_params *params) return ret; } +game_params *decode_params(char const *string) +{ + game_params *ret = default_params(); + + ret->w = ret->h = atoi(string); + while (*string && isdigit(*string)) string++; + if (*string == 'x') { + string++; + ret->h = atoi(string); + } + + return ret; +} + +char *encode_params(game_params *params) +{ + char data[256]; + + sprintf(data, "%dx%d", params->w, params->h); + + return dupstr(data); +} + config_item *game_configure(game_params *params) { config_item *ret; diff --git a/sixteen.c b/sixteen.c index cce11d9..5b7b98e 100644 --- a/sixteen.c +++ b/sixteen.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "puzzles.h" @@ -92,6 +93,29 @@ game_params *dup_params(game_params *params) return ret; } +game_params *decode_params(char const *string) +{ + game_params *ret = default_params(); + + ret->w = ret->h = atoi(string); + while (*string && isdigit(*string)) string++; + if (*string == 'x') { + string++; + ret->h = atoi(string); + } + + return ret; +} + +char *encode_params(game_params *params) +{ + char data[256]; + + sprintf(data, "%dx%d", params->w, params->h); + + return dupstr(data); +} + config_item *game_configure(game_params *params) { config_item *ret;