mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 16:05:44 -07:00
I've changed my mind. For the benefit of users with slower
computers, let's save the Solo and Pattern grids at generation time and regurgitate them when asked to solve, rather than doing all the work over again. [originally from svn r5737]
This commit is contained in:
42
pattern.c
42
pattern.c
@ -472,6 +472,11 @@ static unsigned char *generate_soluble(random_state *rs, int w, int h)
|
|||||||
return grid;
|
return grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct game_aux_info {
|
||||||
|
int w, h;
|
||||||
|
unsigned char *grid;
|
||||||
|
};
|
||||||
|
|
||||||
static char *new_game_seed(game_params *params, random_state *rs,
|
static char *new_game_seed(game_params *params, random_state *rs,
|
||||||
game_aux_info **aux)
|
game_aux_info **aux)
|
||||||
{
|
{
|
||||||
@ -484,6 +489,20 @@ static char *new_game_seed(game_params *params, random_state *rs,
|
|||||||
max = max(params->w, params->h);
|
max = max(params->w, params->h);
|
||||||
rowdata = snewn(max, int);
|
rowdata = snewn(max, int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save the solved game in an aux_info.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
game_aux_info *ai = snew(game_aux_info);
|
||||||
|
|
||||||
|
ai->w = params->w;
|
||||||
|
ai->h = params->h;
|
||||||
|
ai->grid = snewn(ai->w * ai->h, unsigned char);
|
||||||
|
memcpy(ai->grid, grid, ai->w * ai->h);
|
||||||
|
|
||||||
|
*aux = ai;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Seed is a slash-separated list of row contents; each row
|
* Seed is a slash-separated list of row contents; each row
|
||||||
* contents section is a dot-separated list of integers. Row
|
* contents section is a dot-separated list of integers. Row
|
||||||
@ -539,7 +558,8 @@ static char *new_game_seed(game_params *params, random_state *rs,
|
|||||||
|
|
||||||
static void game_free_aux_info(game_aux_info *aux)
|
static void game_free_aux_info(game_aux_info *aux)
|
||||||
{
|
{
|
||||||
assert(!"Shouldn't happen");
|
sfree(aux->grid);
|
||||||
|
sfree(aux);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *validate_seed(game_params *params, char *seed)
|
static char *validate_seed(game_params *params, char *seed)
|
||||||
@ -651,21 +671,25 @@ static void free_game(game_state *state)
|
|||||||
sfree(state);
|
sfree(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static game_state *solve_game(game_state *state, game_aux_info *aux,
|
static game_state *solve_game(game_state *state, game_aux_info *ai,
|
||||||
char **error)
|
char **error)
|
||||||
{
|
{
|
||||||
game_state *ret;
|
game_state *ret;
|
||||||
|
|
||||||
/*
|
|
||||||
* I could have stored the grid I invented in the game_aux_info
|
|
||||||
* and extracted it here where available, but it seems easier
|
|
||||||
* just to run my internal solver in all cases.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ret = dup_game(state);
|
ret = dup_game(state);
|
||||||
ret->completed = ret->cheated = TRUE;
|
ret->completed = ret->cheated = TRUE;
|
||||||
|
|
||||||
{
|
/*
|
||||||
|
* If we already have the solved state in an aux_info, copy it
|
||||||
|
* out.
|
||||||
|
*/
|
||||||
|
if (ai) {
|
||||||
|
|
||||||
|
assert(ret->w == ai->w);
|
||||||
|
assert(ret->h == ai->h);
|
||||||
|
memcpy(ret->grid, ai->grid, ai->w * ai->h);
|
||||||
|
|
||||||
|
} else {
|
||||||
int w = state->w, h = state->h, i, j, done_any, max;
|
int w = state->w, h = state->h, i, j, done_any, max;
|
||||||
unsigned char *matrix, *workspace;
|
unsigned char *matrix, *workspace;
|
||||||
int *rowdata;
|
int *rowdata;
|
||||||
|
58
solo.c
58
solo.c
@ -1351,6 +1351,11 @@ static int symmetries(game_params *params, int x, int y, int *output, int s)
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct game_aux_info {
|
||||||
|
int c, r;
|
||||||
|
digit *grid;
|
||||||
|
};
|
||||||
|
|
||||||
static char *new_game_seed(game_params *params, random_state *rs,
|
static char *new_game_seed(game_params *params, random_state *rs,
|
||||||
game_aux_info **aux)
|
game_aux_info **aux)
|
||||||
{
|
{
|
||||||
@ -1394,6 +1399,18 @@ static char *new_game_seed(game_params *params, random_state *rs,
|
|||||||
assert(ret == 1);
|
assert(ret == 1);
|
||||||
assert(check_valid(c, r, grid));
|
assert(check_valid(c, r, grid));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save the solved grid in the aux_info.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
*aux = ai;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we have a solved grid, start removing things from it
|
* Now we have a solved grid, start removing things from it
|
||||||
* while preserving solubility.
|
* while preserving solubility.
|
||||||
@ -1516,7 +1533,8 @@ static char *new_game_seed(game_params *params, random_state *rs,
|
|||||||
|
|
||||||
static void game_free_aux_info(game_aux_info *aux)
|
static void game_free_aux_info(game_aux_info *aux)
|
||||||
{
|
{
|
||||||
assert(!"Shouldn't happen");
|
sfree(aux->grid);
|
||||||
|
sfree(aux);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *validate_seed(game_params *params, char *seed)
|
static char *validate_seed(game_params *params, char *seed)
|
||||||
@ -1614,31 +1632,37 @@ static void free_game(game_state *state)
|
|||||||
sfree(state);
|
sfree(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static game_state *solve_game(game_state *state, game_aux_info *aux,
|
static game_state *solve_game(game_state *state, game_aux_info *ai,
|
||||||
char **error)
|
char **error)
|
||||||
{
|
{
|
||||||
game_state *ret;
|
game_state *ret;
|
||||||
int c = state->c, r = state->r;
|
int c = state->c, r = state->r, cr = c*r;
|
||||||
int rsolve_ret;
|
int rsolve_ret;
|
||||||
|
|
||||||
/*
|
|
||||||
* I could have stored the grid I invented in the game_aux_info
|
|
||||||
* and extracted it here where available, but it seems easier
|
|
||||||
* just to run my internal solver in all cases.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ret = dup_game(state);
|
ret = dup_game(state);
|
||||||
ret->completed = ret->cheated = TRUE;
|
ret->completed = ret->cheated = TRUE;
|
||||||
|
|
||||||
rsolve_ret = rsolve(c, r, ret->grid, NULL, 2);
|
/*
|
||||||
|
* If we already have the solution in the aux_info, save
|
||||||
|
* ourselves some time.
|
||||||
|
*/
|
||||||
|
if (ai) {
|
||||||
|
|
||||||
if (rsolve_ret != 1) {
|
assert(c == ai->c);
|
||||||
free_game(ret);
|
assert(r == ai->r);
|
||||||
if (rsolve_ret == 0)
|
memcpy(ret->grid, ai->grid, cr * cr * sizeof(digit));
|
||||||
*error = "No solution exists for this puzzle";
|
|
||||||
else
|
} else {
|
||||||
*error = "Multiple solutions exist for this puzzle";
|
rsolve_ret = rsolve(c, r, ret->grid, NULL, 2);
|
||||||
return NULL;
|
|
||||||
|
if (rsolve_ret != 1) {
|
||||||
|
free_game(ret);
|
||||||
|
if (rsolve_ret == 0)
|
||||||
|
*error = "No solution exists for this puzzle";
|
||||||
|
else
|
||||||
|
*error = "Multiple solutions exist for this puzzle";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
Reference in New Issue
Block a user