} \
} while (0)
+void midend_reset_tilesize(midend *me)
+{
+ me->preferred_tilesize = me->ourgame->preferred_tilesize;
+ {
+ /*
+ * Allow an environment-based override for the default tile
+ * size by defining a variable along the lines of
+ * `NET_TILESIZE=15'.
+ */
+
+ char buf[80], *e;
+ int j, k, ts;
+
+ sprintf(buf, "%s_TILESIZE", me->ourgame->name);
+ for (j = k = 0; buf[j]; j++)
+ if (!isspace((unsigned char)buf[j]))
+ buf[k++] = toupper((unsigned char)buf[j]);
+ buf[k] = '\0';
+ if ((e = getenv(buf)) != NULL && sscanf(e, "%d", &ts) == 1 && ts > 0)
+ me->preferred_tilesize = ts;
+ }
+}
+
midend *midend_new(frontend *fe, const game *ourgame,
const drawing_api *drapi, void *drhandle)
{
else
me->drawing = NULL;
- me->preferred_tilesize = ourgame->preferred_tilesize;
- {
- /*
- * Allow an environment-based override for the default tile
- * size by defining a variable along the lines of
- * `NET_TILESIZE=15'.
- */
-
- char buf[80], *e;
- int j, k, ts;
-
- sprintf(buf, "%s_TILESIZE", me->ourgame->name);
- for (j = k = 0; buf[j]; j++)
- if (!isspace((unsigned char)buf[j]))
- buf[k++] = toupper((unsigned char)buf[j]);
- buf[k] = '\0';
- if ((e = getenv(buf)) != NULL && sscanf(e, "%d", &ts) == 1 && ts > 0)
- me->preferred_tilesize = ts;
- }
+ midend_reset_tilesize(me);
sfree(randseed);
sfree(movestr);
}
- /*
- * Soak test, enabled by setting <gamename>_TESTSOLVE in the
- * environment. This causes an immediate attempt to re-solve the
- * game without benefit of aux_info. The effect is that (at least
- * on Unix) you can run 'FOO_TESTSOLVE=1 foo --generate 10000
- * <params>#12345' and it will generate a lot of game ids and
- * instantly pass each one back to the solver.
- *
- * (It's worth putting in an explicit seed in any such test, so
- * you can repeat it to diagnose a problem if one comes up!)
- */
- {
- char buf[80];
- int j, k;
- static int doing_test_solve = -1;
- if (doing_test_solve < 0) {
- sprintf(buf, "%s_TESTSOLVE", me->ourgame->name);
- for (j = k = 0; buf[j]; j++)
- if (!isspace((unsigned char)buf[j]))
- buf[k++] = toupper((unsigned char)buf[j]);
- buf[k] = '\0';
- if (getenv(buf)) {
- /*
- * Since this is used for correctness testing, it's
- * helpful to have a visual acknowledgment that the
- * user hasn't mistyped the environment variable name.
- */
- fprintf(stderr, "Running solver soak tests\n");
- doing_test_solve = TRUE;
- } else {
- doing_test_solve = FALSE;
- }
- }
- if (doing_test_solve) {
- game_state *s;
- char *msg, *movestr;
-
- msg = NULL;
- movestr = me->ourgame->solve(me->states[0].state,
- me->states[0].state,
- NULL, &msg);
- assert(movestr && !msg);
- s = me->ourgame->execute_move(me->states[0].state, movestr);
- assert(s);
- me->ourgame->free_game(s);
- sfree(movestr);
- }
- }
-
me->states[me->nstates].movestr = NULL;
me->states[me->nstates].movetype = NEWGAME;
me->nstates++;
midend_new_game(me);
midend_redraw(me);
goto done; /* never animate */
- } else if (button == 'u' || button == 'u' ||
+ } else if (button == 'u' || button == 'U' ||
button == '\x1A' || button == '\x1F') {
midend_stop_anim(me);
type = me->states[me->statepos-1].movetype;
newcurparams = newparams = oldparams1 = oldparams2 = NULL;
if (par) {
- newcurparams = me->ourgame->dup_params(me->params);
+ /*
+ * The params string may underspecify the game parameters, so
+ * we must first initialise newcurparams with a full set of
+ * params from somewhere else before we decode_params the
+ * input string over the top.
+ *
+ * But which set? It depends on what other data we have.
+ *
+ * If we've been given a _descriptive_ game id, then that may
+ * well underspecify by design, e.g. Solo game descriptions
+ * often start just '3x3:' without specifying one of Solo's
+ * difficulty settings, because it isn't necessary once a game
+ * has been generated (and you might not even know it, if
+ * you're manually transcribing a game description). In that
+ * situation, I've always felt that the best thing to set the
+ * difficulty to (for use if the user hits 'New Game' after
+ * pasting in that game id) is whatever it was previously set
+ * to. That is, we use whatever is already in me->params as
+ * the basis for our decoding of this input string.
+ *
+ * A random-seed based game id, however, should use the real,
+ * built-in default params, and not even check the
+ * <game>_DEFAULT environment setting, because when people
+ * paste each other random seeds - whether it's two users
+ * arranging to generate the same game at the same time to
+ * race solving them, or a user sending a bug report upstream
+ * - the whole point is for the random game id to always be
+ * interpreted the same way, even if it does underspecify.
+ *
+ * A parameter string typed in on its own, with no seed _or_
+ * description, gets treated the same way as a random seed,
+ * because again I think the most likely reason for doing that
+ * is to have a portable representation of a set of params.
+ */
+ if (desc) {
+ newcurparams = me->ourgame->dup_params(me->params);
+ } else {
+ newcurparams = me->ourgame->default_params();
+ }
me->ourgame->decode_params(newcurparams, par);
error = me->ourgame->validate_params(newcurparams, desc == NULL);
if (error) {