From: simon Date: Tue, 28 Jun 2005 11:14:09 +0000 (+0000) Subject: More serialisation changes: the game_aux_info structure has now been X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/commitdiff_plain/c566778e388091cbcdcf4be8c34ec317dde0ffad 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). git-svn-id: svn://svn.tartarus.org/sgt/puzzles@6029 cda61777-01e9-0310-a592-d414129be87e --- diff --git a/cube.c b/cube.c index 57246e4..0145062 100644 --- a/cube.c +++ b/cube.c @@ -586,7 +586,7 @@ static void classify_grid_square_callback(void *ctx, struct grid_square *sq) } 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 @@ static char *new_game_desc(game_params *params, random_state *rs, 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 void free_game(game_state *state) } 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 @@ const struct game thegame = { TRUE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game, diff --git a/fifteen.c b/fifteen.c index ad7381c..d7a0c45 100644 --- a/fifteen.c +++ b/fifteen.c @@ -152,7 +152,7 @@ static int perm_parity(int *perm, int n) } 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 @@ static char *new_game_desc(game_params *params, random_state *rs, 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 void free_game(game_state *state) } 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 @@ const struct game thegame = { TRUE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game, diff --git a/flip.c b/flip.c index 1d7fa17..ce8202c 100644 --- a/flip.c +++ b/flip.c @@ -347,7 +347,7 @@ static void addneighbours(tree234 *t, int w, int h, int cx, int cy, } 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 @@ static char *new_game_desc(game_params *params, random_state *rs, 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 void rowxor(unsigned char *row1, unsigned char *row2, int len) } 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 @@ const struct game thegame = { TRUE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game, diff --git a/gtk.c b/gtk.c index 05d7ad4..88f4a0a 100644 --- a/gtk.c +++ b/gtk.c @@ -1500,12 +1500,11 @@ int main(int argc, char **argv) } 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; diff --git a/guess.c b/guess.c index e681d16..613bc59 100644 --- a/guess.c +++ b/guess.c @@ -264,7 +264,7 @@ static void free_pegrow(pegrow pegs) } 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 @@ newcol: 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 void free_game(game_state *state) } 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 @@ const struct game thegame = { TRUE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game, diff --git a/midend.c b/midend.c index e545841..a6d2d40 100644 --- a/midend.c +++ b/midend.c @@ -48,7 +48,7 @@ struct midend_data { * 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 @@ void midend_free(midend_data *me) 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 @@ void midend_new_game(midend_data *me) 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 *midend_colours(midend_data *me, int *ncolours) 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 @@ static char *midend_game_id_int(midend_data *me, char *id, int defmode) 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; } diff --git a/mines.c b/mines.c index f9f714b..157c0ea 100644 --- a/mines.c +++ b/mines.c @@ -1946,7 +1946,7 @@ static char *new_mine_layout(int w, int h, int n, int x, int y, int unique, } 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 char *new_game_desc(game_params *params, random_state *rs, } } -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 void free_game(game_state *state) } 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 @@ const struct game thegame = { TRUE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game, diff --git a/net.c b/net.c index 3b1339a..7c14f6f 100644 --- a/net.c +++ b/net.c @@ -77,11 +77,6 @@ struct game_params { 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 void perturb(int w, int h, unsigned char *tiles, int wrapping, } 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 @@ static char *new_game_desc(game_params *params, random_state *rs, } /* - * 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 @@ static char *new_game_desc(game_params *params, random_state *rs, 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 void free_game(game_state *state) } 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 @@ static char *solve_game(game_state *state, game_state *currstate, ret[retlen] = '\0'; ret = sresize(ret, retlen+1, char); + sfree(tiles); + return ret; } @@ -2747,7 +2745,6 @@ const struct game thegame = { TRUE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game, diff --git a/netslide.c b/netslide.c index b2b50e8..397508e 100644 --- a/netslide.c +++ b/netslide.c @@ -82,11 +82,6 @@ struct game_params { 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 *validate_params(game_params *params) */ 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,19 +530,22 @@ static char *new_game_desc(game_params *params, random_state *rs, } /* - * 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; + + /* + * String format is exactly the same as a solve move, so we + * can just dupstr this in solve_game(). + */ - 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 + 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 @@ static char *new_game_desc(game_params *params, random_state *rs, 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 void free_game(game_state *state) } 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 @@ const struct game thegame = { TRUE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game, diff --git a/nullgame.c b/nullgame.c index 46f903f..26307e1 100644 --- a/nullgame.c +++ b/nullgame.c @@ -84,16 +84,11 @@ static char *validate_params(game_params *params) } 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 void free_game(game_state *state) } 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 @@ const struct game thegame = { FALSE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game, diff --git a/pattern.c b/pattern.c index 115e813..671b56f 100644 --- a/pattern.c +++ b/pattern.c @@ -466,13 +466,8 @@ static unsigned char *generate_soluble(random_state *rs, int w, int h) 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,14 +479,22 @@ static char *new_game_desc(game_params *params, random_state *rs, 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); + + /* + * String format is exactly the same as a solve move, so we + * can just dupstr this in solve_game(). + */ - ai->w = params->w; - ai->h = params->h; - ai->grid = grid; + 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 @@ static char *new_game_desc(game_params *params, random_state *rs, 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 void free_game(game_state *state) } 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); - - 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); + if (ai) + return dupstr(ai); - memset(matrix, 0, w*h); + matrix = snewn(w*h, unsigned char); + max = max(w, h); + workspace = snewn(max*3, unsigned char); + rowdata = snewn(max+1, int); - do { - done_any = 0; - for (i=0; irowdata + 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; irowdata + 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); + memset(matrix, 0, w*h); - sfree(workspace); - sfree(rowdata); + do { + done_any = 0; + for (i=0; irowdata + 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; irowdata + 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); - 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; - } - } + sfree(workspace); + sfree(rowdata); - 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 @@ const struct game thegame = { TRUE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game, diff --git a/puzzles.h b/puzzles.h index 17b0b00..5ee391b 100644 --- a/puzzles.h +++ b/puzzles.h @@ -70,7 +70,6 @@ typedef struct midend_data midend_data; 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,15 +261,14 @@ struct game { 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); 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); diff --git a/rect.c b/rect.c index ca8c04b..f4ce74b 100644 --- a/rect.c +++ b/rect.c @@ -1117,14 +1117,8 @@ static void display_grid(game_params *params, int *grid, int *numbers, int all) } #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,26 +1673,31 @@ static char *new_game_desc(game_params *params, random_state *rs, } /* - * 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; + + len = 2 + (params->w-1)*params->h + (params->h-1)*params->w; + ai = snewn(len, char); + + ai[0] = 'S'; - 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); + 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 @@ static char *new_game_desc(game_params *params, random_state *rs, 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 void free_game(game_state *state) } 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; - - /* - * 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++; - - 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++; - } + if (ai) + return dupstr(ai); - assert(j == n); + /* + * Attempt the in-built solver. + */ - 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; + /* 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); + + 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++; + } - rect_solver(state->w, state->h, n, nd, hedge, vedge, NULL); + assert(j == n); - /* - * 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; - } + 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); + + /* + * 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,18 +1900,16 @@ static char *solve_game(game_state *state, game_state *currstate, 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'; *p++ = '\0'; assert(p - ret == len); - if (edges_need_freeing) { - sfree(vedge); - sfree(hedge); - } + sfree(vedge); + sfree(hedge); return ret; } @@ -2799,7 +2781,6 @@ const struct game thegame = { TRUE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game, diff --git a/samegame.c b/samegame.c index 18e461e..163a959 100644 --- a/samegame.c +++ b/samegame.c @@ -240,7 +240,7 @@ static char *validate_params(game_params *params) */ 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 @@ static char *new_game_desc(game_params *params, random_state *rs, 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 void free_game(game_state *state) } 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 @@ const struct game thegame = { TRUE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game, diff --git a/sixteen.c b/sixteen.c index a7e6efb..ea544c9 100644 --- a/sixteen.c +++ b/sixteen.c @@ -195,7 +195,7 @@ static int perm_parity(int *perm, int n) } 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,11 +398,6 @@ static char *new_game_desc(game_params *params, random_state *rs, 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) { @@ -511,7 +506,7 @@ static void free_game(game_state *state) } 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 @@ const struct game thegame = { TRUE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game, diff --git a/solo.c b/solo.c index 20e6c07..0abed8c 100644 --- a/solo.c +++ b/solo.c @@ -1419,13 +1419,51 @@ static int symmetries(game_params *params, int x, int y, int *output, int s) 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 @@ static char *new_game_desc(game_params *params, random_state *rs, 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 @@ static char *new_game_desc(game_params *params, random_state *rs, 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,81 +1786,36 @@ static void free_game(game_state *state) } 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) { - - assert(c == ai->c); - assert(r == ai->r); - grid = ai->grid; - grid_needs_freeing = FALSE; + if (ai) + return dupstr(ai); - } 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 = snewn(cr*cr, digit); + memcpy(grid, state->grid, cr*cr); + rsolve_ret = rsolve(c, r, grid, NULL, 2); - 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 */ - - /* - * 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); + ret = encode_solve_move(cr, grid); - if (grid_needs_freeing) - sfree(grid); + sfree(grid); return ret; } @@ -2420,7 +2401,6 @@ const struct game thegame = { TRUE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game, diff --git a/twiddle.c b/twiddle.c index 02b1d79..06dbaed 100644 --- a/twiddle.c +++ b/twiddle.c @@ -307,7 +307,7 @@ static int grid_complete(int *grid, int wh, int orientable) } 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 @@ static char *new_game_desc(game_params *params, random_state *rs, 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 int compare_int(const void *av, const void *bv) } 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 @@ const struct game thegame = { TRUE, game_configure, custom_params, validate_params, new_game_desc, - game_free_aux_info, validate_desc, new_game, dup_game,