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:
Simon Tatham
2023-04-20 13:13:47 +01:00
parent 6c02b72d76
commit 16f997d34c
4 changed files with 44 additions and 26 deletions

39
map.c
View File

@ -1724,8 +1724,8 @@ static const char *parse_edge_list(const game_params *params,
int i, k, pos;
bool state;
const char *p = *desc;
dsf_init(map+wh, wh);
const char *err = NULL;
int *dsf = snew_dsf(wh);
pos = -1;
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).
*/
while (*p && *p != ',') {
if (*p < 'a' || *p > 'z')
return "Unexpected character in edge list";
if (*p < 'a' || *p > 'z') {
err = "Unexpected character in edge list";
goto out;
}
if (*p == 'z')
k = 25;
else
@ -1760,10 +1762,12 @@ static const char *parse_edge_list(const game_params *params,
y = (pos - w*(h-1)) % h;
dx = 1;
dy = 0;
} else
return "Too much data in edge list";
} else {
err = "Too much data in edge list";
goto out;
}
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++;
}
@ -1772,8 +1776,10 @@ static const char *parse_edge_list(const game_params *params,
p++;
}
assert(pos <= 2*wh-w-h);
if (pos < 2*wh-w-h)
return "Too little data in edge list";
if (pos < 2*wh-w-h) {
err = "Too little data in edge list";
goto out;
}
/*
* 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++)
map[i] = -1;
for (i = 0; i < wh; i++) {
k = dsf_canonify(map+wh, i);
k = dsf_canonify(dsf, i);
if (map[k] < 0)
map[k] = pos++;
map[i] = map[k];
}
if (pos != n)
return "Edge list defines the wrong number of regions";
if (pos != n) {
err = "Edge list defines the wrong number of regions";
goto out;
}
*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)
@ -1802,7 +1813,7 @@ static const char *validate_desc(const game_params *params, const char *desc)
int *map;
const char *ret;
map = snewn(2*wh, int);
map = snewn(wh, int);
ret = parse_edge_list(params, &desc, map);
sfree(map);
if (ret)