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]
This commit is contained in:
Simon Tatham
2005-06-28 11:14:09 +00:00
parent 6c9beb697b
commit 89fdc09c29
17 changed files with 244 additions and 385 deletions

10
cube.c
View File

@ -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,

View File

@ -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,

10
flip.c
View File

@ -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,

5
gtk.c
View File

@ -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;

10
guess.c
View File

@ -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,

View File

@ -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;
}

10
mines.c
View File

@ -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,

49
net.c
View File

@ -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,

View File

@ -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;
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 @@ 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,

View File

@ -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,

125
pattern.c
View File

@ -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);
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 @@ 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);
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 @@ const struct game thegame = {
TRUE, game_configure, custom_params,
validate_params,
new_game_desc,
game_free_aux_info,
validate_desc,
new_game,
dup_game,

View File

@ -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);

135
rect.c
View File

@ -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;
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 @@ 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;
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,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,

View File

@ -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,

View File

@ -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,

152
solo.c
View File

@ -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) {
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++;
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);
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,

View File

@ -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,