ref: 89fdc09c29f1219a7660ad6d1839cc914a009c02
parent: 6c9beb697bd61c7e8d0eac8b7fce54cde134d9c9
author: Simon Tatham <anakin@pobox.com>
date: Tue Jun 28 07:14:09 EDT 2005
More serialisation changes: the game_aux_info structure has now been retired, and replaced with a simple string. Most of the games which use it simply encode the string in the same way that the Solve move will also be encoded, i.e. solve_game() simply returns dupstr(aux_info). Again, this is a better approach than writing separate game_aux_info serialise/deserialise functions because doing it this way is self-testing (the strings are created and parsed during the course of any Solve operation at all). [originally from svn r6029]
--- a/cube.c
+++ b/cube.c
@@ -586,7 +586,7 @@
}
static char *new_game_desc(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive)
+ char **aux, int interactive)
{
struct grid_data data;
int i, j, k, m, area, facesperclass;
@@ -687,11 +687,6 @@
return desc;
}
-static void game_free_aux_info(game_aux_info *aux)
-{
- assert(!"Shouldn't happen");
-}
-
static void add_grid_square_callback(void *ctx, struct grid_square *sq)
{
game_state *state = (game_state *)ctx;
@@ -985,7 +980,7 @@
}
static char *solve_game(game_state *state, game_state *currstate,
- game_aux_info *aux, char **error)
+ char *aux, char **error)
{
return NULL;
}
@@ -1714,7 +1709,6 @@
TRUE, game_configure, custom_params,
validate_params,
new_game_desc,
- game_free_aux_info,
validate_desc,
new_game,
dup_game,
--- a/fifteen.c
+++ b/fifteen.c
@@ -152,7 +152,7 @@
}
static char *new_game_desc(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive)
+ char **aux, int interactive)
{
int gap, n, i, x;
int x1, x2, p1, p2, parity;
@@ -267,11 +267,6 @@
return ret;
}
-static void game_free_aux_info(game_aux_info *aux)
-{
- assert(!"Shouldn't happen");
-}
-
static char *validate_desc(game_params *params, char *desc)
{
char *p, *err;
@@ -380,7 +375,7 @@
}
static char *solve_game(game_state *state, game_state *currstate,
- game_aux_info *aux, char **error)
+ char *aux, char **error)
{
return dupstr("S");
}
@@ -882,7 +877,6 @@
TRUE, game_configure, custom_params,
validate_params,
new_game_desc,
- game_free_aux_info,
validate_desc,
new_game,
dup_game,
--- a/flip.c
+++ b/flip.c
@@ -347,7 +347,7 @@
}
static char *new_game_desc(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive)
+ char **aux, int interactive)
{
int w = params->w, h = params->h, wh = w * h;
int i, j;
@@ -595,11 +595,6 @@
return ret;
}
-static void game_free_aux_info(game_aux_info *aux)
-{
- assert(!"Shouldn't happen");
-}
-
static char *validate_desc(game_params *params, char *desc)
{
int w = params->w, h = params->h, wh = w * h;
@@ -676,7 +671,7 @@
}
static char *solve_game(game_state *state, game_state *currstate,
- game_aux_info *aux, char **error)
+ char *aux, char **error)
{
int w = state->w, h = state->h, wh = w * h;
unsigned char *equations, *solution, *shortest;
@@ -1229,7 +1224,6 @@
TRUE, game_configure, custom_params,
validate_params,
new_game_desc,
- game_free_aux_info,
validate_desc,
new_game,
dup_game,
--- a/gtk.c
+++ b/gtk.c
@@ -1500,12 +1500,11 @@
}
while (n-- > 0) {
- game_aux_info *aux = NULL;
+ char *aux = NULL;
char *desc = thegame.new_desc(par, rs, &aux, FALSE);
printf("%s:%s\n", parstr, desc);
sfree(desc);
- if (aux)
- thegame.free_aux_info(aux);
+ sfree(aux);
}
return 0;
--- a/guess.c
+++ b/guess.c
@@ -264,7 +264,7 @@
}
static char *new_game_desc(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive)
+ char **aux, int interactive)
{
unsigned char *bmp = snewn(params->npegs, unsigned char);
char *ret;
@@ -286,11 +286,6 @@
return ret;
}
-static void game_free_aux_info(game_aux_info *aux)
-{
- assert(!"Shouldn't happen");
-}
-
static char *validate_desc(game_params *params, char *desc)
{
unsigned char *bmp;
@@ -365,7 +360,7 @@
}
static char *solve_game(game_state *state, game_state *currstate,
- game_aux_info *aux, char **error)
+ char *aux, char **error)
{
return dupstr("S");
}
@@ -1260,7 +1255,6 @@
TRUE, game_configure, custom_params,
validate_params,
new_game_desc,
- game_free_aux_info,
validate_desc,
new_game,
dup_game,
--- a/midend.c
+++ b/midend.c
@@ -48,7 +48,7 @@
* may also be typed directly into Mines if you like.)
*/
char *desc, *privdesc, *seedstr;
- game_aux_info *aux_info;
+ char *aux_info;
enum { GOT_SEED, GOT_DESC, GOT_NOTHING } genmode;
int nstates, statesize, statepos;
@@ -140,8 +140,7 @@
sfree(me->states);
sfree(me->desc);
sfree(me->seedstr);
- if (me->aux_info)
- me->ourgame->free_aux_info(me->aux_info);
+ sfree(me->aux_info);
me->ourgame->free_params(me->params);
if (me->npresets) {
for (i = 0; i < me->npresets; i++) {
@@ -235,8 +234,7 @@
sfree(me->desc);
sfree(me->privdesc);
- if (me->aux_info)
- me->ourgame->free_aux_info(me->aux_info);
+ sfree(me->aux_info);
me->aux_info = NULL;
rs = random_init(me->seedstr, strlen(me->seedstr));
@@ -634,13 +632,12 @@
float *ret;
if (me->nstates == 0) {
- game_aux_info *aux = NULL;
+ char *aux = NULL;
char *desc = me->ourgame->new_desc(me->params, me->random,
&aux, TRUE);
state = me->ourgame->new_game(me, me->params, desc);
sfree(desc);
- if (aux)
- me->ourgame->free_aux_info(aux);
+ sfree(aux);
} else
state = me->states[0].state;
@@ -925,8 +922,7 @@
me->desc = dupstr(desc);
me->genmode = GOT_DESC;
- if (me->aux_info)
- me->ourgame->free_aux_info(me->aux_info);
+ sfree(me->aux_info);
me->aux_info = NULL;
}
--- a/mines.c
+++ b/mines.c
@@ -1946,7 +1946,7 @@
}
static char *new_game_desc(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive)
+ char **aux, int interactive)
{
/*
* We generate the coordinates of an initial click even if they
@@ -1984,11 +1984,6 @@
}
}
-static void game_free_aux_info(game_aux_info *aux)
-{
- assert(!"Shouldn't happen");
-}
-
static char *validate_desc(game_params *params, char *desc)
{
int wh = params->w * params->h;
@@ -2298,7 +2293,7 @@
}
static char *solve_game(game_state *state, game_state *currstate,
- game_aux_info *aux, char **error)
+ char *aux, char **error)
{
if (!state->layout->mines) {
*error = "Game has not been started yet";
@@ -3045,7 +3040,6 @@
TRUE, game_configure, custom_params,
validate_params,
new_game_desc,
- game_free_aux_info,
validate_desc,
new_game,
dup_game,
--- a/net.c
+++ b/net.c
@@ -77,11 +77,6 @@
float barrier_probability;
};
-struct game_aux_info {
- int width, height;
- unsigned char *tiles;
-};
-
struct game_state {
int width, height, wrapping, completed;
int last_rotate_x, last_rotate_y, last_rotate_dir;
@@ -1139,7 +1134,7 @@
}
static char *new_game_desc(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive)
+ char **aux, int interactive)
{
tree234 *possibilities, *barriertree;
int w, h, x, y, cx, cy, nbarriers;
@@ -1401,16 +1396,16 @@
}
/*
- * Save the unshuffled grid in an aux_info.
+ * Save the unshuffled grid in aux.
*/
{
- game_aux_info *solution;
+ char *solution;
+ int i;
- solution = snew(game_aux_info);
- solution->width = w;
- solution->height = h;
- solution->tiles = snewn(w * h, unsigned char);
- memcpy(solution->tiles, tiles, w * h);
+ solution = snewn(w * h + 1, char);
+ for (i = 0; i < w * h; i++)
+ solution[i] = "0123456789abcdef"[tiles[i] & 0xF];
+ solution[w*h] = '\0';
*aux = solution;
}
@@ -1515,12 +1510,6 @@
return desc;
}
-static void game_free_aux_info(game_aux_info *aux)
-{
- sfree(aux->tiles);
- sfree(aux);
-}
-
static char *validate_desc(game_params *params, char *desc)
{
int w = params->width, h = params->height;
@@ -1667,27 +1656,34 @@
}
static char *solve_game(game_state *state, game_state *currstate,
- game_aux_info *aux, char **error)
+ char *aux, char **error)
{
unsigned char *tiles;
char *ret;
int retlen, retsize;
int i;
- int tiles_need_freeing;
+ tiles = snewn(state->width * state->height, unsigned char);
+
if (!aux) {
/*
* Run the internal solver on the provided grid. This might
* not yield a complete solution.
*/
- tiles = snewn(state->width * state->height, unsigned char);
memcpy(tiles, state->tiles, state->width * state->height);
net_solver(state->width, state->height, tiles,
state->barriers, state->wrapping);
- tiles_need_freeing = TRUE;
} else {
- tiles = aux->tiles;
- tiles_need_freeing = FALSE;
+ for (i = 0; i < state->width * state->height; i++) {
+ int c = aux[i];
+
+ if (c >= '0' && c <= '9')
+ tiles[i] = c - '0';
+ else if (c >= 'a' && c <= 'f')
+ tiles[i] = c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ tiles[i] = c - 'A' + 10;
+ }
}
/*
@@ -1747,6 +1743,8 @@
ret[retlen] = '\0';
ret = sresize(ret, retlen+1, char);
+ sfree(tiles);
+
return ret;
}
@@ -2747,7 +2745,6 @@
TRUE, game_configure, custom_params,
validate_params,
new_game_desc,
- game_free_aux_info,
validate_desc,
new_game,
dup_game,
--- a/netslide.c
+++ b/netslide.c
@@ -82,11 +82,6 @@
int movetarget;
};
-struct game_aux_info {
- int width, height;
- unsigned char *tiles;
-};
-
struct game_state {
int width, height, cx, cy, wrapping, completed;
int used_solve, just_used_solve;
@@ -330,7 +325,7 @@
*/
static char *new_game_desc(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive)
+ char **aux, int interactive)
{
tree234 *possibilities, *barriertree;
int w, h, x, y, cx, cy, nbarriers;
@@ -535,20 +530,23 @@
}
/*
- * Save the unshuffled grid. We do this using a separate
- * reference-counted structure since it's a large chunk of
- * memory which we don't want to have to replicate in every
- * game state while playing.
+ * Save the unshuffled grid in aux.
*/
{
- game_aux_info *solution;
+ char *solution;
+ int i;
- solution = snew(game_aux_info);
- solution->width = w;
- solution->height = h;
- solution->tiles = snewn(w * h, unsigned char);
- memcpy(solution->tiles, tiles, w * h);
+ /*
+ * String format is exactly the same as a solve move, so we
+ * can just dupstr this in solve_game().
+ */
+ solution = snewn(w * h + 2, char);
+ solution[0] = 'S';
+ for (i = 0; i < w * h; i++)
+ solution[i+1] = "0123456789abcdef"[tiles[i] & 0xF];
+ solution[w*h+1] = '\0';
+
*aux = solution;
}
@@ -698,12 +696,6 @@
return desc;
}
-static void game_free_aux_info(game_aux_info *aux)
-{
- sfree(aux->tiles);
- sfree(aux);
-}
-
static char *validate_desc(game_params *params, char *desc)
{
int w = params->width, h = params->height;
@@ -894,24 +886,14 @@
}
static char *solve_game(game_state *state, game_state *currstate,
- game_aux_info *aux, char **error)
+ char *aux, char **error)
{
- char *ret;
- int i;
-
if (!aux) {
*error = "Solution not known for this puzzle";
return NULL;
}
- assert(aux->width == state->width);
- assert(aux->height == state->height);
- ret = snewn(aux->width * aux->height + 2, char);
- ret[0] = 'S';
- for (i = 0; i < aux->width * aux->height; i++)
- ret[i+1] = "0123456789abcdef"[aux->tiles[i] & 0xF];
- ret[i+1] = '\0';
- return ret;
+ return dupstr(aux);
}
static char *game_text_format(game_state *state)
@@ -1822,7 +1804,6 @@
TRUE, game_configure, custom_params,
validate_params,
new_game_desc,
- game_free_aux_info,
validate_desc,
new_game,
dup_game,
--- a/nullgame.c
+++ b/nullgame.c
@@ -84,16 +84,11 @@
}
static char *new_game_desc(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive)
+ char **aux, int interactive)
{
return dupstr("FIXME");
}
-static void game_free_aux_info(game_aux_info *aux)
-{
- assert(!"Shouldn't happen");
-}
-
static char *validate_desc(game_params *params, char *desc)
{
return NULL;
@@ -123,7 +118,7 @@
}
static char *solve_game(game_state *state, game_state *currstate,
- game_aux_info *aux, char **error)
+ char *aux, char **error)
{
return NULL;
}
@@ -255,7 +250,6 @@
FALSE, game_configure, custom_params,
validate_params,
new_game_desc,
- game_free_aux_info,
validate_desc,
new_game,
dup_game,
--- a/pattern.c
+++ b/pattern.c
@@ -466,13 +466,8 @@
return grid;
}
-struct game_aux_info {
- int w, h;
- unsigned char *grid;
-};
-
static char *new_game_desc(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive)
+ char **aux, int interactive)
{
unsigned char *grid;
int i, j, max, rowlen, *rowdata;
@@ -484,15 +479,23 @@
rowdata = snewn(max, int);
/*
- * Save the solved game in an aux_info.
+ * Save the solved game in aux.
*/
{
- game_aux_info *ai = snew(game_aux_info);
+ char *ai = snewn(params->w * params->h + 2, char);
- ai->w = params->w;
- ai->h = params->h;
- ai->grid = grid;
+ /*
+ * String format is exactly the same as a solve move, so we
+ * can just dupstr this in solve_game().
+ */
+ ai[0] = 'S';
+
+ for (i = 0; i < params->w * params->h; i++)
+ ai[i+1] = grid[i] ? '1' : '0';
+
+ ai[params->w * params->h + 1] = '\0';
+
*aux = ai;
}
@@ -549,12 +552,6 @@
return desc;
}
-static void game_free_aux_info(game_aux_info *aux)
-{
- sfree(aux->grid);
- sfree(aux);
-}
-
static char *validate_desc(game_params *params, char *desc)
{
int i, n, rowspace;
@@ -665,81 +662,66 @@
}
static char *solve_game(game_state *state, game_state *currstate,
- game_aux_info *ai, char **error)
+ char *ai, char **error)
{
unsigned char *matrix;
- int matrix_needs_freeing;
- int full, empty;
int w = state->w, h = state->h;
int i;
char *ret;
+ int done_any, max;
+ unsigned char *workspace;
+ int *rowdata;
/*
- * If we already have the solved state in an aux_info, copy it
- * out.
+ * If we already have the solved state in ai, copy it out.
*/
- if (ai) {
- assert(ai->w == w && ai->h == h);
+ if (ai)
+ return dupstr(ai);
- matrix = ai->grid;
- matrix_needs_freeing = FALSE;
- full = GRID_FULL;
- empty = GRID_EMPTY;
- } else {
- int done_any, max;
- unsigned char *workspace;
- int *rowdata;
+ matrix = snewn(w*h, unsigned char);
+ max = max(w, h);
+ workspace = snewn(max*3, unsigned char);
+ rowdata = snewn(max+1, int);
- matrix = snewn(w*h, unsigned char);
- max = max(w, h);
- workspace = snewn(max*3, unsigned char);
- rowdata = snewn(max+1, int);
+ memset(matrix, 0, w*h);
- memset(matrix, 0, w*h);
+ do {
+ done_any = 0;
+ for (i=0; i<h; i++) {
+ memcpy(rowdata, state->rowdata + state->rowsize*(w+i),
+ max*sizeof(int));
+ rowdata[state->rowlen[w+i]] = 0;
+ done_any |= do_row(workspace, workspace+max, workspace+2*max,
+ matrix+i*w, w, 1, rowdata);
+ }
+ for (i=0; i<w; i++) {
+ memcpy(rowdata, state->rowdata + state->rowsize*i, max*sizeof(int));
+ rowdata[state->rowlen[i]] = 0;
+ done_any |= do_row(workspace, workspace+max, workspace+2*max,
+ matrix+i, h, w, rowdata);
+ }
+ } while (done_any);
- do {
- done_any = 0;
- for (i=0; i<h; i++) {
- memcpy(rowdata, state->rowdata + state->rowsize*(w+i),
- max*sizeof(int));
- rowdata[state->rowlen[w+i]] = 0;
- done_any |= do_row(workspace, workspace+max, workspace+2*max,
- matrix+i*w, w, 1, rowdata);
- }
- for (i=0; i<w; i++) {
- memcpy(rowdata, state->rowdata + state->rowsize*i, max*sizeof(int));
- rowdata[state->rowlen[i]] = 0;
- done_any |= do_row(workspace, workspace+max, workspace+2*max,
- matrix+i, h, w, rowdata);
- }
- } while (done_any);
+ sfree(workspace);
+ sfree(rowdata);
- sfree(workspace);
- sfree(rowdata);
-
- for (i = 0; i < w*h; i++) {
- if (matrix[i] != BLOCK && matrix[i] != DOT) {
- sfree(matrix);
- *error = "Solving algorithm cannot complete this puzzle";
- return NULL;
- }
- }
-
- matrix_needs_freeing = TRUE;
- full = BLOCK;
- empty = DOT;
+ for (i = 0; i < w*h; i++) {
+ if (matrix[i] != BLOCK && matrix[i] != DOT) {
+ sfree(matrix);
+ *error = "Solving algorithm cannot complete this puzzle";
+ return NULL;
+ }
}
ret = snewn(w*h+2, char);
ret[0] = 'S';
for (i = 0; i < w*h; i++) {
- assert(matrix[i] == full || matrix[i] == empty);
- ret[i+1] = (matrix[i] == full ? '1' : '0');
+ assert(matrix[i] == BLOCK || matrix[i] == DOT);
+ ret[i+1] = (matrix[i] == BLOCK ? '1' : '0');
}
ret[w*h+1] = '\0';
- if (matrix_needs_freeing)
- sfree(matrix);
+ sfree(matrix);
return ret;
}
@@ -1194,7 +1176,6 @@
TRUE, game_configure, custom_params,
validate_params,
new_game_desc,
- game_free_aux_info,
validate_desc,
new_game,
dup_game,
--- a/puzzles.h
+++ b/puzzles.h
@@ -70,7 +70,6 @@
typedef struct random_state random_state;
typedef struct game_params game_params;
typedef struct game_state game_state;
-typedef struct game_aux_info game_aux_info;
typedef struct game_ui game_ui;
typedef struct game_drawstate game_drawstate;
typedef struct game game;
@@ -262,8 +261,7 @@
game_params *(*custom_params)(config_item *cfg);
char *(*validate_params)(game_params *params);
char *(*new_desc)(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive);
- void (*free_aux_info)(game_aux_info *aux);
+ char **aux, int interactive);
char *(*validate_desc)(game_params *params, char *desc);
game_state *(*new_game)(midend_data *me, game_params *params, char *desc);
game_state *(*dup_game)(game_state *state);
@@ -270,7 +268,7 @@
void (*free_game)(game_state *state);
int can_solve;
char *(*solve)(game_state *orig, game_state *curr,
- game_aux_info *aux, char **error);
+ char *aux, char **error);
int can_format_as_text;
char *(*text_format)(game_state *state);
game_ui *(*new_ui)(game_state *state);
--- a/rect.c
+++ b/rect.c
@@ -1117,14 +1117,8 @@
}
#endif
-struct game_aux_info {
- int w, h;
- unsigned char *vedge; /* (w+1) x h */
- unsigned char *hedge; /* w x (h+1) */
-};
-
static char *new_game_desc(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive)
+ char **aux, int interactive)
{
int *grid, *numbers = NULL;
int x, y, y2, y2last, yx, run, i, nsquares;
@@ -1679,27 +1673,32 @@
}
/*
- * Store the rectangle data in the game_aux_info.
+ * Store the solution in aux.
*/
{
- game_aux_info *ai = snew(game_aux_info);
+ char *ai;
+ int len;
- ai->w = params->w;
- ai->h = params->h;
- ai->vedge = snewn(ai->w * ai->h, unsigned char);
- ai->hedge = snewn(ai->w * ai->h, unsigned char);
+ len = 2 + (params->w-1)*params->h + (params->h-1)*params->w;
+ ai = snewn(len, char);
+ ai[0] = 'S';
+
+ p = ai+1;
+
for (y = 0; y < params->h; y++)
- for (x = 1; x < params->w; x++) {
- vedge(ai, x, y) =
- index(params, grid, x, y) != index(params, grid, x-1, y);
- }
+ for (x = 1; x < params->w; x++)
+ *p++ = (index(params, grid, x, y) !=
+ index(params, grid, x-1, y) ? '1' : '0');
+
for (y = 1; y < params->h; y++)
- for (x = 0; x < params->w; x++) {
- hedge(ai, x, y) =
- index(params, grid, x, y) != index(params, grid, x, y-1);
- }
+ for (x = 0; x < params->w; x++)
+ *p++ = (index(params, grid, x, y) !=
+ index(params, grid, x, y-1) ? '1' : '0');
+ assert(p - ai == len-1);
+ *p = '\0';
+
*aux = ai;
}
@@ -1746,13 +1745,6 @@
return desc;
}
-static void game_free_aux_info(game_aux_info *ai)
-{
- sfree(ai->vedge);
- sfree(ai->hedge);
- sfree(ai);
-}
-
static char *validate_desc(game_params *params, char *desc)
{
int area = params->w * params->h;
@@ -1854,61 +1846,53 @@
}
static char *solve_game(game_state *state, game_state *currstate,
- game_aux_info *ai, char **error)
+ char *ai, char **error)
{
unsigned char *vedge, *hedge;
- int edges_need_freeing;
int x, y, len;
char *ret, *p;
+ int i, j, n;
+ struct numberdata *nd;
- if (!ai) {
- int i, j, n;
- struct numberdata *nd;
+ if (ai)
+ return dupstr(ai);
- /*
- * Attempt the in-built solver.
- */
+ /*
+ * Attempt the in-built solver.
+ */
- /* Set up each number's (very short) candidate position list. */
- for (i = n = 0; i < state->h * state->w; i++)
- if (state->grid[i])
- n++;
+ /* Set up each number's (very short) candidate position list. */
+ for (i = n = 0; i < state->h * state->w; i++)
+ if (state->grid[i])
+ n++;
- nd = snewn(n, struct numberdata);
+ nd = snewn(n, struct numberdata);
- for (i = j = 0; i < state->h * state->w; i++)
- if (state->grid[i]) {
- nd[j].area = state->grid[i];
- nd[j].npoints = 1;
- nd[j].points = snewn(1, struct point);
- nd[j].points[0].x = i % state->w;
- nd[j].points[0].y = i / state->w;
- j++;
- }
+ for (i = j = 0; i < state->h * state->w; i++)
+ if (state->grid[i]) {
+ nd[j].area = state->grid[i];
+ nd[j].npoints = 1;
+ nd[j].points = snewn(1, struct point);
+ nd[j].points[0].x = i % state->w;
+ nd[j].points[0].y = i / state->w;
+ j++;
+ }
- assert(j == n);
+ assert(j == n);
- vedge = snewn(state->w * state->h, unsigned char);
- hedge = snewn(state->w * state->h, unsigned char);
- memset(vedge, 0, state->w * state->h);
- memset(hedge, 0, state->w * state->h);
- edges_need_freeing = TRUE;
+ vedge = snewn(state->w * state->h, unsigned char);
+ hedge = snewn(state->w * state->h, unsigned char);
+ memset(vedge, 0, state->w * state->h);
+ memset(hedge, 0, state->w * state->h);
- rect_solver(state->w, state->h, n, nd, hedge, vedge, NULL);
+ rect_solver(state->w, state->h, n, nd, hedge, vedge, NULL);
- /*
- * Clean up.
- */
- for (i = 0; i < n; i++)
- sfree(nd[i].points);
- sfree(nd);
- } else {
- assert(state->w == ai->w);
- assert(state->h == ai->h);
- vedge = ai->vedge;
- hedge = ai->hedge;
- edges_need_freeing = FALSE;
- }
+ /*
+ * Clean up.
+ */
+ for (i = 0; i < n; i++)
+ sfree(nd[i].points);
+ sfree(nd);
len = 2 + (state->w-1)*state->h + (state->h-1)*state->w;
ret = snewn(len, char);
@@ -1916,8 +1900,8 @@
p = ret;
*p++ = 'S';
for (y = 0; y < state->h; y++)
- for (x = 1; x < state->w; x++)
- *p++ = vedge[y*state->w+x] ? '1' : '0';
+ for (x = 1; x < state->w; x++)
+ *p++ = vedge[y*state->w+x] ? '1' : '0';
for (y = 1; y < state->h; y++)
for (x = 0; x < state->w; x++)
*p++ = hedge[y*state->w+x] ? '1' : '0';
@@ -1924,10 +1908,8 @@
*p++ = '\0';
assert(p - ret == len);
- if (edges_need_freeing) {
- sfree(vedge);
- sfree(hedge);
- }
+ sfree(vedge);
+ sfree(hedge);
return ret;
}
@@ -2799,7 +2781,6 @@
TRUE, game_configure, custom_params,
validate_params,
new_game_desc,
- game_free_aux_info,
validate_desc,
new_game,
dup_game,
--- a/samegame.c
+++ b/samegame.c
@@ -240,7 +240,7 @@
*/
static char *new_game_desc(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive)
+ char **aux, int interactive)
{
char *ret;
int n, i, j, c, retlen, *tiles;
@@ -282,11 +282,6 @@
return ret;
}
-static void game_free_aux_info(game_aux_info *aux)
-{
- assert(!"Shouldn't happen");
-}
-
static char *validate_desc(game_params *params, char *desc)
{
int area = params->w * params->h, i;
@@ -356,7 +351,7 @@
}
static char *solve_game(game_state *state, game_state *currstate,
- game_aux_info *aux, char **error)
+ char *aux, char **error)
{
return NULL;
}
@@ -999,7 +994,6 @@
TRUE, game_configure, custom_params,
validate_params,
new_game_desc,
- game_free_aux_info,
validate_desc,
new_game,
dup_game,
--- a/sixteen.c
+++ b/sixteen.c
@@ -195,7 +195,7 @@
}
static char *new_game_desc(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive)
+ char **aux, int interactive)
{
int stop, n, i, x;
int x1, x2, p1, p2;
@@ -398,12 +398,7 @@
return ret;
}
-static void game_free_aux_info(game_aux_info *aux)
-{
- assert(!"Shouldn't happen");
-}
-
static char *validate_desc(game_params *params, char *desc)
{
char *p, *err;
@@ -511,7 +506,7 @@
}
static char *solve_game(game_state *state, game_state *currstate,
- game_aux_info *aux, char **error)
+ char *aux, char **error)
{
return dupstr("S");
}
@@ -1060,7 +1055,6 @@
TRUE, game_configure, custom_params,
validate_params,
new_game_desc,
- game_free_aux_info,
validate_desc,
new_game,
dup_game,
--- a/solo.c
+++ b/solo.c
@@ -1419,13 +1419,51 @@
return i;
}
-struct game_aux_info {
- int c, r;
- digit *grid;
-};
+static char *encode_solve_move(int cr, digit *grid)
+{
+ int i, len;
+ char *ret, *p, *sep;
+ /*
+ * It's surprisingly easy to work out _exactly_ how long this
+ * string needs to be. To decimal-encode all the numbers from 1
+ * to n:
+ *
+ * - every number has a units digit; total is n.
+ * - all numbers above 9 have a tens digit; total is max(n-9,0).
+ * - all numbers above 99 have a hundreds digit; total is max(n-99,0).
+ * - and so on.
+ */
+ len = 0;
+ for (i = 1; i <= cr; i *= 10)
+ len += max(cr - i + 1, 0);
+ len += cr; /* don't forget the commas */
+ len *= cr; /* there are cr rows of these */
+
+ /*
+ * Now len is one bigger than the total size of the
+ * comma-separated numbers (because we counted an
+ * additional leading comma). We need to have a leading S
+ * and a trailing NUL, so we're off by one in total.
+ */
+ len++;
+
+ ret = snewn(len, char);
+ p = ret;
+ *p++ = 'S';
+ sep = "";
+ for (i = 0; i < cr*cr; i++) {
+ p += sprintf(p, "%s%d", sep, grid[i]);
+ sep = ",";
+ }
+ *p++ = '\0';
+ assert(p - ret == len);
+
+ return ret;
+}
+
static char *new_game_desc(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive)
+ char **aux, int interactive)
{
int c = params->c, r = params->r, cr = c*r;
int area = cr*cr;
@@ -1493,25 +1531,19 @@
assert(check_valid(c, r, grid));
/*
- * Save the solved grid in the aux_info.
+ * Save the solved grid in aux.
*/
{
- game_aux_info *ai = snew(game_aux_info);
- ai->c = c;
- ai->r = r;
- ai->grid = snewn(cr * cr, digit);
- memcpy(ai->grid, grid, cr * cr * sizeof(digit));
/*
* We might already have written *aux the last time we
* went round this loop, in which case we should free
- * the old aux_info before overwriting it with the new
- * one.
+ * the old aux before overwriting it with the new one.
*/
if (*aux) {
- sfree((*aux)->grid);
sfree(*aux);
}
- *aux = ai;
+
+ *aux = encode_solve_move(cr, grid);
}
/*
@@ -1652,12 +1684,6 @@
return desc;
}
-static void game_free_aux_info(game_aux_info *aux)
-{
- sfree(aux->grid);
- sfree(aux);
-}
-
static char *validate_desc(game_params *params, char *desc)
{
int area = params->r * params->r * params->c * params->c;
@@ -1760,82 +1786,37 @@
}
static char *solve_game(game_state *state, game_state *currstate,
- game_aux_info *ai, char **error)
+ char *ai, char **error)
{
int c = state->c, r = state->r, cr = c*r;
- int i, len;
- char *ret, *p, *sep;
+ char *ret;
digit *grid;
- int grid_needs_freeing;
+ int rsolve_ret;
/*
- * If we already have the solution in the aux_info, save
- * ourselves some time.
+ * If we already have the solution in ai, save ourselves some
+ * time.
*/
- if (ai) {
+ if (ai)
+ return dupstr(ai);
- assert(c == ai->c);
- assert(r == ai->r);
- grid = ai->grid;
- grid_needs_freeing = FALSE;
+ grid = snewn(cr*cr, digit);
+ memcpy(grid, state->grid, cr*cr);
+ rsolve_ret = rsolve(c, r, grid, NULL, 2);
- } else {
- int rsolve_ret;
-
- grid = snewn(cr*cr, digit);
- memcpy(grid, state->grid, cr*cr);
- rsolve_ret = rsolve(c, r, grid, NULL, 2);
-
- if (rsolve_ret != 1) {
- sfree(grid);
- if (rsolve_ret == 0)
- *error = "No solution exists for this puzzle";
- else
- *error = "Multiple solutions exist for this puzzle";
- return NULL;
- }
-
- grid_needs_freeing = TRUE;
+ if (rsolve_ret != 1) {
+ sfree(grid);
+ if (rsolve_ret == 0)
+ *error = "No solution exists for this puzzle";
+ else
+ *error = "Multiple solutions exist for this puzzle";
+ return NULL;
}
- /*
- * It's surprisingly easy to work out _exactly_ how long this
- * string needs to be. To decimal-encode all the numbers from 1
- * to n:
- *
- * - every number has a units digit; total is n.
- * - all numbers above 9 have a tens digit; total is max(n-9,0).
- * - all numbers above 99 have a hundreds digit; total is max(n-99,0).
- * - and so on.
- */
- len = 0;
- for (i = 1; i <= cr; i *= 10)
- len += max(cr - i + 1, 0);
- len += cr; /* don't forget the commas */
- len *= cr; /* there are cr rows of these */
+ ret = encode_solve_move(cr, grid);
- /*
- * Now len is one bigger than the total size of the
- * comma-separated numbers (because we counted an
- * additional leading comma). We need to have a leading S
- * and a trailing NUL, so we're off by one in total.
- */
- len++;
+ sfree(grid);
- ret = snewn(len, char);
- p = ret;
- *p++ = 'S';
- sep = "";
- for (i = 0; i < cr*cr; i++) {
- p += sprintf(p, "%s%d", sep, grid[i]);
- sep = ",";
- }
- *p++ = '\0';
- assert(p - ret == len);
-
- if (grid_needs_freeing)
- sfree(grid);
-
return ret;
}
@@ -2420,7 +2401,6 @@
TRUE, game_configure, custom_params,
validate_params,
new_game_desc,
- game_free_aux_info,
validate_desc,
new_game,
dup_game,
--- a/twiddle.c
+++ b/twiddle.c
@@ -307,7 +307,7 @@
}
static char *new_game_desc(game_params *params, random_state *rs,
- game_aux_info **aux, int interactive)
+ char **aux, int interactive)
{
int *grid;
int w = params->w, h = params->h, n = params->n, wh = w*h;
@@ -430,11 +430,6 @@
return ret;
}
-static void game_free_aux_info(game_aux_info *aux)
-{
- assert(!"Shouldn't happen");
-}
-
static char *validate_desc(game_params *params, char *desc)
{
char *p, *err;
@@ -547,7 +542,7 @@
}
static char *solve_game(game_state *state, game_state *currstate,
- game_aux_info *aux, char **error)
+ char *aux, char **error)
{
return dupstr("S");
}
@@ -1224,7 +1219,6 @@
TRUE, game_configure, custom_params,
validate_params,
new_game_desc,
- game_free_aux_info,
validate_desc,
new_game,
dup_game,