#include "puzzles.h"
const char *const game_name = "Fifteen";
+const int game_can_configure = TRUE;
#define TILE_SIZE 48
#define BORDER (TILE_SIZE / 2)
int *tiles;
int gap_pos;
int completed;
+ int movecount;
};
game_params *default_params(void)
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;
* 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
assert(!*p);
assert(state->tiles[state->gap_pos] == 0);
- state->completed = FALSE;
+ state->completed = state->movecount = 0;
return 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;
}
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;
}
}
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)
else
return 0.0F;
}
+
+int game_wants_statusbar(void)
+{
+ return TRUE;
+}