`Fifteen' was getting the parity wrong on any size of board where
[sgt/puzzles] / fifteen.c
index 9357d65..04a8f75 100644 (file)
--- a/fifteen.c
+++ b/fifteen.c
@@ -11,6 +11,7 @@
 #include "puzzles.h"
 
 const char *const game_name = "Fifteen";
+const int game_can_configure = TRUE;
 
 #define TILE_SIZE 48
 #define BORDER    (TILE_SIZE / 2)
@@ -42,6 +43,7 @@ struct game_state {
     int *tiles;
     int gap_pos;
     int completed;
+    int movecount;
 };
 
 game_params *default_params(void)
@@ -70,6 +72,51 @@ game_params *dup_params(game_params *params)
     return ret;
 }
 
+config_item *game_configure(game_params *params)
+{
+    config_item *ret;
+    char buf[80];
+
+    ret = snewn(3, config_item);
+
+    ret[0].name = "Width";
+    ret[0].type = C_STRING;
+    sprintf(buf, "%d", params->w);
+    ret[0].sval = dupstr(buf);
+    ret[0].ival = 0;
+
+    ret[1].name = "Height";
+    ret[1].type = C_STRING;
+    sprintf(buf, "%d", params->h);
+    ret[1].sval = dupstr(buf);
+    ret[1].ival = 0;
+
+    ret[2].name = NULL;
+    ret[2].type = C_END;
+    ret[2].sval = NULL;
+    ret[2].ival = 0;
+
+    return ret;
+}
+
+game_params *custom_params(config_item *cfg)
+{
+    game_params *ret = snew(game_params);
+
+    ret->w = atoi(cfg[0].sval);
+    ret->h = atoi(cfg[1].sval);
+
+    return ret;
+}
+
+char *validate_params(game_params *params)
+{
+    if (params->w < 2 && params->h < 2)
+       return "Width and height must both be at least two";
+
+    return NULL;
+}
+
 int perm_parity(int *perm, int n)
 {
     int i, j, ret;
@@ -152,15 +199,16 @@ char *new_game_seed(game_params *params)
      * Determine the required parity of the overall permutation.
      * This is the XOR of:
      * 
-     *  - The chessboard parity ((x^y)&1) of the gap square. The
-     *    bottom right, and therefore also the top left, count as
-     *    even.
+     *         - The chessboard parity ((x^y)&1) of the gap square. The
+     *           bottom right counts as even.
      * 
      *  - The parity of n. (The target permutation is 1,...,n-1,0
      *    rather than 0,...,n-1; this is a cyclic permutation of
      *    the starting point and hence is odd iff n is even.)
      */
-    parity = (X(params, gap) ^ Y(params, gap) ^ (n+1)) & 1;
+    parity = ((X(params, gap) - (params->w-1)) ^
+             (Y(params, gap) - (params->h-1)) ^
+             (n+1)) & 1;
 
     /*
      * Try the last two tiles one way round. If that fails, swap
@@ -224,7 +272,7 @@ game_state *new_game(game_params *params, char *seed)
     assert(!*p);
     assert(state->tiles[state->gap_pos] == 0);
 
-    state->completed = FALSE;
+    state->completed = state->movecount = 0;
 
     return state;
 }
@@ -240,6 +288,7 @@ game_state *dup_game(game_state *state)
     memcpy(ret->tiles, state->tiles, state->w * state->h * sizeof(int));
     ret->gap_pos = state->gap_pos;
     ret->completed = state->completed;
+    ret->movecount = state->movecount;
 
     return ret;
 }
@@ -297,16 +346,17 @@ game_state *make_move(game_state *from, int x, int y, int button)
     for (p = from->gap_pos; p != ret->gap_pos; p += up) {
         assert(p >= 0 && p < from->n);
         ret->tiles[p] = from->tiles[p + up];
+       ret->movecount++;
     }
 
     /*
      * See if the game has been completed.
      */
     if (!ret->completed) {
-        ret->completed = TRUE;
+        ret->completed = ret->movecount;
         for (p = 0; p < ret->n; p++)
             if (ret->tiles[p] != (p < ret->n-1 ? p+1 : 0))
-                ret->completed = FALSE;
+                ret->completed = 0;
     }
 
     return ret;
@@ -544,6 +594,26 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
         }
     }
     ds->bgcolour = bgcolour;
+
+    /*
+     * Update the status bar.
+     */
+    {
+       char statusbuf[256];
+
+        /*
+         * Don't show the new status until we're also showing the
+         * new _state_ - after the game animation is complete.
+         */
+        if (oldstate)
+            state = oldstate;
+
+       sprintf(statusbuf, "%sMoves: %d",
+               (state->completed ? "COMPLETED! " : ""),
+               (state->completed ? state->completed : state->movecount));
+
+       status_bar(fe, statusbuf);
+    }
 }
 
 float game_anim_length(game_state *oldstate, game_state *newstate)
@@ -558,3 +628,8 @@ float game_flash_length(game_state *oldstate, game_state *newstate)
     else
         return 0.0F;
 }
+
+int game_wants_statusbar(void)
+{
+    return TRUE;
+}