mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 08:01:30 -07:00
Stop putting dsfs in existing scratch int arrays.
I'm going to work towards turning 'dsf' into an opaque type, so that I can improve its implementation without breaking clients. The first step is to deal manually with puzzles that currently reuse a single array of ints for multiple purposes, some of which are dsf and some are not. In divvy_rectangle_attempt, 'tmp' was used as an int array and later a dsf, and I've made a new 'tmpdsf' to be the latter. In Dominosa, solver->pc_scratch2 was sometimes a dsf, and now there's a new solver->dsf_scratch. In Map, parse_edge_list() needed a dsf internally and then never exported it; it expected to be passed an array of 2*w*h ints and used the second half as a dsf. Now it expects only w*h ints, and allocates its own dsf internally, freeing it again before returning. And in Tents, find_errors() was allocating a single block of 2*w*h ints and using the second half of it as a dsf, apparently just to save one malloc. Now we malloc and free the dsf separately.
This commit is contained in:
12
divvy.c
12
divvy.c
@ -262,7 +262,7 @@ static bool addremcommon(int w, int h, int x, int y, int *own, int val)
|
|||||||
*/
|
*/
|
||||||
int *divvy_rectangle_attempt(int w, int h, int k, random_state *rs)
|
int *divvy_rectangle_attempt(int w, int h, int k, random_state *rs)
|
||||||
{
|
{
|
||||||
int *order, *queue, *tmp, *own, *sizes, *addable, *retdsf;
|
int *order, *queue, *tmp, *own, *sizes, *addable, *retdsf, *tmpdsf;
|
||||||
bool *removable;
|
bool *removable;
|
||||||
int wh = w*h;
|
int wh = w*h;
|
||||||
int i, j, n, x, y, qhead, qtail;
|
int i, j, n, x, y, qhead, qtail;
|
||||||
@ -277,6 +277,7 @@ int *divvy_rectangle_attempt(int w, int h, int k, random_state *rs)
|
|||||||
queue = snewn(n, int);
|
queue = snewn(n, int);
|
||||||
addable = snewn(wh*4, int);
|
addable = snewn(wh*4, int);
|
||||||
removable = snewn(wh, bool);
|
removable = snewn(wh, bool);
|
||||||
|
retdsf = tmpdsf = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Permute the grid squares into a random order, which will be
|
* Permute the grid squares into a random order, which will be
|
||||||
@ -619,18 +620,18 @@ int *divvy_rectangle_attempt(int w, int h, int k, random_state *rs)
|
|||||||
* the ominoes really are k-ominoes and we haven't
|
* the ominoes really are k-ominoes and we haven't
|
||||||
* accidentally split one into two disconnected pieces.
|
* accidentally split one into two disconnected pieces.
|
||||||
*/
|
*/
|
||||||
dsf_init(tmp, wh);
|
tmpdsf = snew_dsf(wh);
|
||||||
for (y = 0; y < h; y++)
|
for (y = 0; y < h; y++)
|
||||||
for (x = 0; x+1 < w; x++)
|
for (x = 0; x+1 < w; x++)
|
||||||
if (own[y*w+x] == own[y*w+(x+1)])
|
if (own[y*w+x] == own[y*w+(x+1)])
|
||||||
dsf_merge(tmp, y*w+x, y*w+(x+1));
|
dsf_merge(tmpdsf, y*w+x, y*w+(x+1));
|
||||||
for (x = 0; x < w; x++)
|
for (x = 0; x < w; x++)
|
||||||
for (y = 0; y+1 < h; y++)
|
for (y = 0; y+1 < h; y++)
|
||||||
if (own[y*w+x] == own[(y+1)*w+x])
|
if (own[y*w+x] == own[(y+1)*w+x])
|
||||||
dsf_merge(tmp, y*w+x, (y+1)*w+x);
|
dsf_merge(tmpdsf, y*w+x, (y+1)*w+x);
|
||||||
for (i = 0; i < wh; i++) {
|
for (i = 0; i < wh; i++) {
|
||||||
j = dsf_canonify(retdsf, i);
|
j = dsf_canonify(retdsf, i);
|
||||||
assert(dsf_canonify(tmp, j) == dsf_canonify(tmp, i));
|
assert(dsf_canonify(tmpdsf, j) == dsf_canonify(tmpdsf, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -640,6 +641,7 @@ int *divvy_rectangle_attempt(int w, int h, int k, random_state *rs)
|
|||||||
*/
|
*/
|
||||||
sfree(order);
|
sfree(order);
|
||||||
sfree(tmp);
|
sfree(tmp);
|
||||||
|
sfree(tmpdsf);
|
||||||
sfree(own);
|
sfree(own);
|
||||||
sfree(sizes);
|
sfree(sizes);
|
||||||
sfree(queue);
|
sfree(queue);
|
||||||
|
14
dominosa.c
14
dominosa.c
@ -350,7 +350,7 @@ struct solver_scratch {
|
|||||||
struct solver_square **squares_by_number;
|
struct solver_square **squares_by_number;
|
||||||
struct findloopstate *fls;
|
struct findloopstate *fls;
|
||||||
bool squares_by_number_initialised;
|
bool squares_by_number_initialised;
|
||||||
int *wh_scratch, *pc_scratch, *pc_scratch2, *dc_scratch;
|
int *wh_scratch, *pc_scratch, *pc_scratch2, *dc_scratch, *dsf_scratch;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct solver_scratch *solver_make_scratch(int n)
|
static struct solver_scratch *solver_make_scratch(int n)
|
||||||
@ -482,6 +482,7 @@ static struct solver_scratch *solver_make_scratch(int n)
|
|||||||
sc->wh_scratch = NULL;
|
sc->wh_scratch = NULL;
|
||||||
sc->pc_scratch = sc->pc_scratch2 = NULL;
|
sc->pc_scratch = sc->pc_scratch2 = NULL;
|
||||||
sc->dc_scratch = NULL;
|
sc->dc_scratch = NULL;
|
||||||
|
sc->dsf_scratch = NULL;
|
||||||
|
|
||||||
return sc;
|
return sc;
|
||||||
}
|
}
|
||||||
@ -509,6 +510,7 @@ static void solver_free_scratch(struct solver_scratch *sc)
|
|||||||
sfree(sc->pc_scratch);
|
sfree(sc->pc_scratch);
|
||||||
sfree(sc->pc_scratch2);
|
sfree(sc->pc_scratch2);
|
||||||
sfree(sc->dc_scratch);
|
sfree(sc->dc_scratch);
|
||||||
|
sfree(sc->dsf_scratch);
|
||||||
sfree(sc);
|
sfree(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1425,19 +1427,21 @@ static bool deduce_forcing_chain(struct solver_scratch *sc)
|
|||||||
sc->pc_scratch2 = snewn(sc->pc, int);
|
sc->pc_scratch2 = snewn(sc->pc, int);
|
||||||
if (!sc->dc_scratch)
|
if (!sc->dc_scratch)
|
||||||
sc->dc_scratch = snewn(sc->dc, int);
|
sc->dc_scratch = snewn(sc->dc, int);
|
||||||
|
if (!sc->dsf_scratch)
|
||||||
|
sc->dsf_scratch = snew_dsf(sc->pc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start by identifying chains of placements which must all occur
|
* Start by identifying chains of placements which must all occur
|
||||||
* together if any of them occurs. We do this by making
|
* together if any of them occurs. We do this by making
|
||||||
* pc_scratch2 an edsf binding the placements into an equivalence
|
* dsf_scratch an edsf binding the placements into an equivalence
|
||||||
* class for each entire forcing chain, with the two possible sets
|
* class for each entire forcing chain, with the two possible sets
|
||||||
* of dominoes for the chain listed as inverses.
|
* of dominoes for the chain listed as inverses.
|
||||||
*/
|
*/
|
||||||
dsf_init(sc->pc_scratch2, sc->pc);
|
dsf_init(sc->dsf_scratch, sc->pc);
|
||||||
for (si = 0; si < sc->wh; si++) {
|
for (si = 0; si < sc->wh; si++) {
|
||||||
struct solver_square *sq = &sc->squares[si];
|
struct solver_square *sq = &sc->squares[si];
|
||||||
if (sq->nplacements == 2)
|
if (sq->nplacements == 2)
|
||||||
edsf_merge(sc->pc_scratch2,
|
edsf_merge(sc->dsf_scratch,
|
||||||
sq->placements[0]->index,
|
sq->placements[0]->index,
|
||||||
sq->placements[1]->index, true);
|
sq->placements[1]->index, true);
|
||||||
}
|
}
|
||||||
@ -1452,7 +1456,7 @@ static bool deduce_forcing_chain(struct solver_scratch *sc)
|
|||||||
*/
|
*/
|
||||||
for (pi = 0; pi < sc->pc; pi++) {
|
for (pi = 0; pi < sc->pc; pi++) {
|
||||||
bool inv;
|
bool inv;
|
||||||
int c = edsf_canonify(sc->pc_scratch2, pi, &inv);
|
int c = edsf_canonify(sc->dsf_scratch, pi, &inv);
|
||||||
sc->pc_scratch[pi] = c * 2 + (inv ? 1 : 0);
|
sc->pc_scratch[pi] = c * 2 + (inv ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
39
map.c
39
map.c
@ -1724,8 +1724,8 @@ static const char *parse_edge_list(const game_params *params,
|
|||||||
int i, k, pos;
|
int i, k, pos;
|
||||||
bool state;
|
bool state;
|
||||||
const char *p = *desc;
|
const char *p = *desc;
|
||||||
|
const char *err = NULL;
|
||||||
dsf_init(map+wh, wh);
|
int *dsf = snew_dsf(wh);
|
||||||
|
|
||||||
pos = -1;
|
pos = -1;
|
||||||
state = false;
|
state = false;
|
||||||
@ -1736,8 +1736,10 @@ static const char *parse_edge_list(const game_params *params,
|
|||||||
* pairs of squares whenever the edge list shows a non-edge).
|
* pairs of squares whenever the edge list shows a non-edge).
|
||||||
*/
|
*/
|
||||||
while (*p && *p != ',') {
|
while (*p && *p != ',') {
|
||||||
if (*p < 'a' || *p > 'z')
|
if (*p < 'a' || *p > 'z') {
|
||||||
return "Unexpected character in edge list";
|
err = "Unexpected character in edge list";
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
if (*p == 'z')
|
if (*p == 'z')
|
||||||
k = 25;
|
k = 25;
|
||||||
else
|
else
|
||||||
@ -1760,10 +1762,12 @@ static const char *parse_edge_list(const game_params *params,
|
|||||||
y = (pos - w*(h-1)) % h;
|
y = (pos - w*(h-1)) % h;
|
||||||
dx = 1;
|
dx = 1;
|
||||||
dy = 0;
|
dy = 0;
|
||||||
} else
|
} else {
|
||||||
return "Too much data in edge list";
|
err = "Too much data in edge list";
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
if (!state)
|
if (!state)
|
||||||
dsf_merge(map+wh, y*w+x, (y+dy)*w+(x+dx));
|
dsf_merge(dsf, y*w+x, (y+dy)*w+(x+dx));
|
||||||
|
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
@ -1772,8 +1776,10 @@ static const char *parse_edge_list(const game_params *params,
|
|||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
assert(pos <= 2*wh-w-h);
|
assert(pos <= 2*wh-w-h);
|
||||||
if (pos < 2*wh-w-h)
|
if (pos < 2*wh-w-h) {
|
||||||
return "Too little data in edge list";
|
err = "Too little data in edge list";
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now go through again and allocate region numbers.
|
* Now go through again and allocate region numbers.
|
||||||
@ -1782,17 +1788,22 @@ static const char *parse_edge_list(const game_params *params,
|
|||||||
for (i = 0; i < wh; i++)
|
for (i = 0; i < wh; i++)
|
||||||
map[i] = -1;
|
map[i] = -1;
|
||||||
for (i = 0; i < wh; i++) {
|
for (i = 0; i < wh; i++) {
|
||||||
k = dsf_canonify(map+wh, i);
|
k = dsf_canonify(dsf, i);
|
||||||
if (map[k] < 0)
|
if (map[k] < 0)
|
||||||
map[k] = pos++;
|
map[k] = pos++;
|
||||||
map[i] = map[k];
|
map[i] = map[k];
|
||||||
}
|
}
|
||||||
if (pos != n)
|
if (pos != n) {
|
||||||
return "Edge list defines the wrong number of regions";
|
err = "Edge list defines the wrong number of regions";
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
*desc = p;
|
*desc = p;
|
||||||
|
err = NULL; /* no error */
|
||||||
|
|
||||||
return NULL;
|
out:
|
||||||
|
sfree(dsf);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *validate_desc(const game_params *params, const char *desc)
|
static const char *validate_desc(const game_params *params, const char *desc)
|
||||||
@ -1802,7 +1813,7 @@ static const char *validate_desc(const game_params *params, const char *desc)
|
|||||||
int *map;
|
int *map;
|
||||||
const char *ret;
|
const char *ret;
|
||||||
|
|
||||||
map = snewn(2*wh, int);
|
map = snewn(wh, int);
|
||||||
ret = parse_edge_list(params, &desc, map);
|
ret = parse_edge_list(params, &desc, map);
|
||||||
sfree(map);
|
sfree(map);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
5
tents.c
5
tents.c
@ -2006,7 +2006,7 @@ static int *find_errors(const game_state *state, char *grid)
|
|||||||
{
|
{
|
||||||
int w = state->p.w, h = state->p.h;
|
int w = state->p.w, h = state->p.h;
|
||||||
int *ret = snewn(w*h + w + h, int);
|
int *ret = snewn(w*h + w + h, int);
|
||||||
int *tmp = snewn(w*h*2, int), *dsf = tmp + w*h;
|
int *tmp = snewn(w*h, int), *dsf;
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2223,7 +2223,7 @@ static int *find_errors(const game_state *state, char *grid)
|
|||||||
* all the tents in any component which has a smaller tree
|
* all the tents in any component which has a smaller tree
|
||||||
* count.
|
* count.
|
||||||
*/
|
*/
|
||||||
dsf_init(dsf, w*h);
|
dsf = snew_dsf(w*h);
|
||||||
/* Construct the equivalence classes. */
|
/* Construct the equivalence classes. */
|
||||||
for (y = 0; y < h; y++) {
|
for (y = 0; y < h; y++) {
|
||||||
for (x = 0; x < w-1; x++) {
|
for (x = 0; x < w-1; x++) {
|
||||||
@ -2302,6 +2302,7 @@ static int *find_errors(const game_state *state, char *grid)
|
|||||||
#undef TENT
|
#undef TENT
|
||||||
|
|
||||||
sfree(tmp);
|
sfree(tmp);
|
||||||
|
sfree(dsf);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user