chiark / gitweb /
Fix completion checking in Killer Solo.
[sgt-puzzles.git] / midend.c
index c36127467b864bb6bc81241d4c4b1efcf01f553b..190840af62531cdc08de4f8c642c474327aff7c6 100644 (file)
--- a/midend.c
+++ b/midend.c
@@ -355,6 +355,7 @@ void midend_force_redraw(midend *me)
 
 void midend_new_game(midend *me)
 {
+    midend_stop_anim(me);
     midend_free_game(me);
 
     assert(me->nstates == 0);
@@ -445,55 +446,6 @@ void midend_new_game(midend *me)
        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++;
@@ -502,6 +454,8 @@ void midend_new_game(midend *me)
                                               me->states[0].state);
     midend_size_new_drawstate(me);
     me->elapsed = 0.0F;
+    me->flash_pos = me->flash_time = 0.0F;
+    me->anim_pos = me->anim_time = 0.0F;
     if (me->ui)
         me->ourgame->free_ui(me->ui);
     me->ui = me->ourgame->new_ui(me->states[0].state);
@@ -595,8 +549,6 @@ void midend_restart_game(midend *me)
 {
     game_state *s;
 
-    midend_stop_anim(me);
-
     assert(me->statepos >= 1);
     if (me->statepos == 1)
         return;                        /* no point doing anything at all! */
@@ -624,7 +576,7 @@ void midend_restart_game(midend *me)
         me->ourgame->changed_state(me->ui,
                                    me->states[me->statepos-2].state,
                                    me->states[me->statepos-1].state);
-    me->anim_time = 0.0;
+    me->flash_pos = me->flash_time = 0.0F;
     midend_finish_move(me);
     midend_redraw(me);
     midend_set_timer(me);
@@ -645,11 +597,10 @@ static int midend_really_process_key(midend *me, int x, int y, int button)
 
     if (!movestr) {
        if (button == 'n' || button == 'N' || button == '\x0E') {
-           midend_stop_anim(me);
            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;
@@ -1228,7 +1179,45 @@ static char *midend_game_id_int(midend *me, char *id, int defmode)
     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) {