grid.c: allocate face/edge/dot arrays incrementally.

Previously, the 'faces', 'edges' and 'dots' arrays in a grid structure
were arrays of actual grid_face, grid_edge and grid_dot structures,
physically containing all the data about the grid. But they also
referred to each other by pointers, which meant that they were hard to
realloc larger (you'd have to go through and rewrite all the pointers
whenever the base of an array moved). And _that_ meant that every grid
type had to figure out a reasonably good upper bound on the number of
all those things it was going to need, so that it could allocate those
arrays the right size to begin with, and not have to grow them
painfully later.

For some grid types - particularly the new aperiodic ones - that was
actually a painful part of the job. So I think enough is enough:
counting up how much memory you're going to need before using it is a
mug's game, and we should instead realloc on the fly.

So now g->faces, g->edges and g->dots have an extra level of
indirection. Instead of being arrays of actual structs, they're arrays
of pointers, and each struct in them is individually allocated. Once a
grid_face has been allocated, it never moves again, even if the array
of pointers changes size.

The old code had a common idiom of recovering the array index of a
particular element by subtracting it from the array base, e.g. writing
'f - g->faces' or 'e - g->edges'. To make that lookup remain possible,
I've added an 'index' field to each sub-structure, which is
initialised at the point where we decide what array index it will live
at.

This should involve no functional change, but the code that previously
had to figure out max_faces and max_dots up front for each grid type
is now completely gone, and nobody has to solve those problems in
advance any more.
This commit is contained in:
Simon Tatham
2023-07-06 12:50:49 +01:00
parent 6b5142a7a9
commit e6cdd70df8
6 changed files with 253 additions and 376 deletions

185
loopy.c
View File

@ -1097,7 +1097,7 @@ static char *game_text_format(const game_state *state)
assert(state->grid_type == 0);
/* Work out the basic size unit */
f = g->faces; /* first face */
f = g->faces[0]; /* first face */
assert(f->order == 4);
/* The dots are ordered clockwise, so the two opposite
* corners are guaranteed to span the square */
@ -1120,7 +1120,7 @@ static char *game_text_format(const game_state *state)
/* Fill in edge info */
for (i = 0; i < g->num_edges; i++) {
grid_edge *e = g->edges + i;
grid_edge *e = g->edges[i];
/* Cell coordinates, from (0,0) to (w-1,h-1) */
int x1 = (e->dot1->x - g->lowest_x) / cell_size;
int x2 = (e->dot2->x - g->lowest_x) / cell_size;
@ -1148,7 +1148,7 @@ static char *game_text_format(const game_state *state)
for (i = 0; i < g->num_faces; i++) {
int x1, x2, y1, y2;
f = g->faces + i;
f = g->faces[i];
assert(f->order == 4);
/* Cell coordinates, from (0,0) to (w-1,h-1) */
x1 = (f->dots[0]->x - g->lowest_x) / cell_size;
@ -1228,26 +1228,26 @@ static bool solver_set_line(solver_state *sstate, int i,
#endif
g = state->game_grid;
e = g->edges + i;
e = g->edges[i];
/* Update the cache for both dots and both faces affected by this. */
if (line_new == LINE_YES) {
sstate->dot_yes_count[e->dot1 - g->dots]++;
sstate->dot_yes_count[e->dot2 - g->dots]++;
sstate->dot_yes_count[e->dot1->index]++;
sstate->dot_yes_count[e->dot2->index]++;
if (e->face1) {
sstate->face_yes_count[e->face1 - g->faces]++;
sstate->face_yes_count[e->face1->index]++;
}
if (e->face2) {
sstate->face_yes_count[e->face2 - g->faces]++;
sstate->face_yes_count[e->face2->index]++;
}
} else {
sstate->dot_no_count[e->dot1 - g->dots]++;
sstate->dot_no_count[e->dot2 - g->dots]++;
sstate->dot_no_count[e->dot1->index]++;
sstate->dot_no_count[e->dot2->index]++;
if (e->face1) {
sstate->face_no_count[e->face1 - g->faces]++;
sstate->face_no_count[e->face1->index]++;
}
if (e->face2) {
sstate->face_no_count[e->face2 - g->faces]++;
sstate->face_no_count[e->face2->index]++;
}
}
@ -1271,10 +1271,10 @@ static bool merge_dots(solver_state *sstate, int edge_index)
{
int i, j, len;
grid *g = sstate->state->game_grid;
grid_edge *e = g->edges + edge_index;
grid_edge *e = g->edges[edge_index];
i = e->dot1 - g->dots;
j = e->dot2 - g->dots;
i = e->dot1->index;
j = e->dot2->index;
i = dsf_canonify(sstate->dotdsf, i);
j = dsf_canonify(sstate->dotdsf, j);
@ -1332,12 +1332,12 @@ static int dot_order(const game_state* state, int dot, char line_type)
{
int n = 0;
grid *g = state->game_grid;
grid_dot *d = g->dots + dot;
grid_dot *d = g->dots[dot];
int i;
for (i = 0; i < d->order; i++) {
grid_edge *e = d->edges[i];
if (state->lines[e - g->edges] == line_type)
if (state->lines[e->index] == line_type)
++n;
}
return n;
@ -1349,12 +1349,12 @@ static int face_order(const game_state* state, int face, char line_type)
{
int n = 0;
grid *g = state->game_grid;
grid_face *f = g->faces + face;
grid_face *f = g->faces[face];
int i;
for (i = 0; i < f->order; i++) {
grid_edge *e = f->edges[i];
if (state->lines[e - g->edges] == line_type)
if (state->lines[e->index] == line_type)
++n;
}
return n;
@ -1375,10 +1375,10 @@ static bool dot_setall(solver_state *sstate, int dot,
return false;
g = state->game_grid;
d = g->dots + dot;
d = g->dots[dot];
for (i = 0; i < d->order; i++) {
int line_index = d->edges[i] - g->edges;
int line_index = d->edges[i]->index;
if (state->lines[line_index] == old_type) {
r = solver_set_line(sstate, line_index, new_type);
assert(r);
@ -1402,10 +1402,10 @@ static bool face_setall(solver_state *sstate, int face,
return false;
g = state->game_grid;
f = g->faces + face;
f = g->faces[face];
for (i = 0; i < f->order; i++) {
int line_index = f->edges[i] - g->edges;
int line_index = f->edges[i]->index;
if (state->lines[line_index] == old_type) {
r = solver_set_line(sstate, line_index, new_type);
assert(r);
@ -1434,7 +1434,7 @@ static void add_full_clues(game_state *state, random_state *rs)
* algorithm does work, and there aren't any GREY faces still there. */
memset(clues, 0, g->num_faces);
for (i = 0; i < g->num_edges; i++) {
grid_edge *e = g->edges + i;
grid_edge *e = g->edges[i];
grid_face *f1 = e->face1;
grid_face *f2 = e->face2;
enum face_colour c1 = FACE_COLOUR(f1);
@ -1442,8 +1442,8 @@ static void add_full_clues(game_state *state, random_state *rs)
assert(c1 != FACE_GREY);
assert(c2 != FACE_GREY);
if (c1 != c2) {
if (f1) clues[f1 - g->faces]++;
if (f2) clues[f2 - g->faces]++;
if (f1) clues[f1->index]++;
if (f2) clues[f2->index]++;
}
}
sfree(board);
@ -1725,8 +1725,8 @@ static bool check_completion(game_state *state)
/* Build the dsf. */
for (i = 0; i < g->num_edges; i++) {
if (state->lines[i] == LINE_YES) {
grid_edge *e = g->edges + i;
int d1 = e->dot1 - g->dots, d2 = e->dot2 - g->dots;
grid_edge *e = g->edges[i];
int d1 = e->dot1->index, d2 = e->dot2->index;
dsf_merge(dsf, d1, d2);
}
}
@ -1751,10 +1751,10 @@ static bool check_completion(game_state *state)
int unknown = dot_order(state, i, LINE_UNKNOWN);
if ((yes == 1 && unknown == 0) || (yes >= 3)) {
/* violation, so mark all YES edges as errors */
grid_dot *d = g->dots + i;
grid_dot *d = g->dots[i];
int j;
for (j = 0; j < d->order; j++) {
int e = d->edges[j] - g->edges;
int e = d->edges[j]->index;
if (state->lines[e] == LINE_YES)
state->line_errors[e] = true;
}
@ -1817,8 +1817,8 @@ static bool check_completion(game_state *state)
*/
for (i = 0; i < g->num_edges; i++) {
if (state->lines[i] == LINE_YES) {
grid_edge *e = g->edges + i;
int d1 = e->dot1 - g->dots; /* either endpoint is good enough */
grid_edge *e = g->edges[i];
int d1 = e->dot1->index; /* either endpoint is good enough */
int comp = dsf_canonify(dsf, d1);
if ((component_state[comp] == COMP_PATH &&
-1 != largest_comp) ||
@ -1916,11 +1916,10 @@ static int dline_index_from_dot(grid *g, grid_dot *d, int i)
if (i2 == d->order) i2 = 0;
e2 = d->edges[i2];
#endif
ret = 2 * (e - g->edges) + ((e->dot1 == d) ? 1 : 0);
ret = 2 * (e->index) + ((e->dot1 == d) ? 1 : 0);
#ifdef DEBUG_DLINES
printf("dline_index_from_dot: d=%d,i=%d, edges [%d,%d] - %d\n",
(int)(d - g->dots), i, (int)(e - g->edges),
(int)(e2 - g->edges), ret);
(int)(d->index), i, (int)(e->index), (int)(e2 ->index), ret);
#endif
return ret;
}
@ -1939,11 +1938,10 @@ static int dline_index_from_face(grid *g, grid_face *f, int i)
if (i2 < 0) i2 += f->order;
e2 = f->edges[i2];
#endif
ret = 2 * (e - g->edges) + ((e->dot1 == d) ? 1 : 0);
ret = 2 * (e->index) + ((e->dot1 == d) ? 1 : 0);
#ifdef DEBUG_DLINES
printf("dline_index_from_face: f=%d,i=%d, edges [%d,%d] - %d\n",
(int)(f - g->faces), i, (int)(e - g->edges),
(int)(e2 - g->edges), ret);
(int)(f->index), i, (int)(e->index), (int)(e2->index), ret);
#endif
return ret;
}
@ -2001,9 +1999,9 @@ static bool dline_set_opp_atleastone(solver_state *sstate,
opp2 = opp + 1;
if (opp2 == N) opp2 = 0;
/* Check if opp, opp2 point to LINE_UNKNOWNs */
if (state->lines[d->edges[opp] - g->edges] != LINE_UNKNOWN)
if (state->lines[d->edges[opp]->index] != LINE_UNKNOWN)
continue;
if (state->lines[d->edges[opp2] - g->edges] != LINE_UNKNOWN)
if (state->lines[d->edges[opp2]->index] != LINE_UNKNOWN)
continue;
/* Found opposite UNKNOWNS and they're next to each other */
opp_dline_index = dline_index_from_dot(g, d, opp);
@ -2025,18 +2023,18 @@ static bool face_setall_identical(solver_state *sstate, int face_index,
bool retval = false;
game_state *state = sstate->state;
grid *g = state->game_grid;
grid_face *f = g->faces + face_index;
grid_face *f = g->faces[face_index];
int N = f->order;
int i, j;
int can1, can2;
bool inv1, inv2;
for (i = 0; i < N; i++) {
int line1_index = f->edges[i] - g->edges;
int line1_index = f->edges[i]->index;
if (state->lines[line1_index] != LINE_UNKNOWN)
continue;
for (j = i + 1; j < N; j++) {
int line2_index = f->edges[j] - g->edges;
int line2_index = f->edges[j]->index;
if (state->lines[line2_index] != LINE_UNKNOWN)
continue;
@ -2060,9 +2058,8 @@ static void find_unknowns(game_state *state,
int *e /* Returned edge indices */)
{
int c = 0;
grid *g = state->game_grid;
while (c < expected_count) {
int line_index = *edge_list - g->edges;
int line_index = (*edge_list)->index;
if (state->lines[line_index] == LINE_UNKNOWN) {
e[c] = line_index;
c++;
@ -2191,7 +2188,7 @@ static int trivial_deductions(solver_state *sstate)
/* Per-face deductions */
for (i = 0; i < g->num_faces; i++) {
grid_face *f = g->faces + i;
grid_face *f = g->faces[i];
if (sstate->face_solved[i])
continue;
@ -2249,22 +2246,22 @@ static int trivial_deductions(solver_state *sstate)
int j, k, e1, e2, e, d;
for (j = 0; j < f->order; j++) {
e1 = f->edges[j] - g->edges;
e2 = f->edges[j+1 < f->order ? j+1 : 0] - g->edges;
e1 = f->edges[j]->index;
e2 = f->edges[j+1 < f->order ? j+1 : 0]->index;
if (g->edges[e1].dot1 == g->edges[e2].dot1 ||
g->edges[e1].dot1 == g->edges[e2].dot2) {
d = g->edges[e1].dot1 - g->dots;
if (g->edges[e1]->dot1 == g->edges[e2]->dot1 ||
g->edges[e1]->dot1 == g->edges[e2]->dot2) {
d = g->edges[e1]->dot1->index;
} else {
assert(g->edges[e1].dot2 == g->edges[e2].dot1 ||
g->edges[e1].dot2 == g->edges[e2].dot2);
d = g->edges[e1].dot2 - g->dots;
assert(g->edges[e1]->dot2 == g->edges[e2]->dot1 ||
g->edges[e1]->dot2 == g->edges[e2]->dot2);
d = g->edges[e1]->dot2->index;
}
if (state->lines[e1] == LINE_UNKNOWN &&
state->lines[e2] == LINE_UNKNOWN) {
for (k = 0; k < g->dots[d].order; k++) {
int e = g->dots[d].edges[k] - g->edges;
for (k = 0; k < g->dots[d]->order; k++) {
int e = g->dots[d]->edges[k]->index;
if (state->lines[e] == LINE_YES)
goto found; /* multi-level break */
}
@ -2278,7 +2275,7 @@ static int trivial_deductions(solver_state *sstate)
* they're e1 and e2.
*/
for (j = 0; j < f->order; j++) {
e = f->edges[j] - g->edges;
e = f->edges[j]->index;
if (state->lines[e] == LINE_UNKNOWN && e != e1 && e != e2) {
bool r = solver_set_line(sstate, e, LINE_YES);
assert(r);
@ -2292,7 +2289,7 @@ static int trivial_deductions(solver_state *sstate)
/* Per-dot deductions */
for (i = 0; i < g->num_dots; i++) {
grid_dot *d = g->dots + i;
grid_dot *d = g->dots[i];
int yes, no, unknown;
if (sstate->dot_solved[i])
@ -2389,7 +2386,7 @@ static int dline_deductions(solver_state *sstate)
for (i = 0; i < g->num_faces; i++) {
int maxs[MAX_FACE_SIZE][MAX_FACE_SIZE];
int mins[MAX_FACE_SIZE][MAX_FACE_SIZE];
grid_face *f = g->faces + i;
grid_face *f = g->faces[i];
int N = f->order;
int j,m;
int clue = state->clues[i];
@ -2400,7 +2397,7 @@ static int dline_deductions(solver_state *sstate)
/* Calculate the (j,j+1) entries */
for (j = 0; j < N; j++) {
int edge_index = f->edges[j] - g->edges;
int edge_index = f->edges[j]->index;
int dline_index;
enum line_state line1 = state->lines[edge_index];
enum line_state line2;
@ -2411,7 +2408,7 @@ static int dline_deductions(solver_state *sstate)
mins[j][k] = (line1 == LINE_YES) ? 1 : 0;
/* Calculate the (j,j+2) entries */
dline_index = dline_index_from_face(g, f, k);
edge_index = f->edges[k] - g->edges;
edge_index = f->edges[k]->index;
line2 = state->lines[edge_index];
k++;
if (k >= N) k = 0;
@ -2456,7 +2453,7 @@ static int dline_deductions(solver_state *sstate)
for (j = 0; j < N; j++) {
int k;
grid_edge *e = f->edges[j];
int line_index = e - g->edges;
int line_index = e->index;
int dline_index;
if (state->lines[line_index] != LINE_UNKNOWN)
@ -2491,7 +2488,7 @@ static int dline_deductions(solver_state *sstate)
if (sstate->diff >= DIFF_TRICKY) {
/* Now see if we can make dline deduction for edges{j,j+1} */
e = f->edges[k];
if (state->lines[e - g->edges] != LINE_UNKNOWN)
if (state->lines[e->index] != LINE_UNKNOWN)
/* Only worth doing this for an UNKNOWN,UNKNOWN pair.
* Dlines where one of the edges is known, are handled in the
* dot-deductions */
@ -2523,7 +2520,7 @@ static int dline_deductions(solver_state *sstate)
/* ------ Dot deductions ------ */
for (i = 0; i < g->num_dots; i++) {
grid_dot *d = g->dots + i;
grid_dot *d = g->dots[i];
int N = d->order;
int yes, no, unknown;
int j;
@ -2541,8 +2538,8 @@ static int dline_deductions(solver_state *sstate)
k = j + 1;
if (k >= N) k = 0;
dline_index = dline_index_from_dot(g, d, j);
line1_index = d->edges[j] - g->edges;
line2_index = d->edges[k] - g->edges;
line1_index = d->edges[j]->index;
line2_index = d->edges[k] ->index;
line1 = state->lines[line1_index];
line2 = state->lines[line2_index];
@ -2639,7 +2636,7 @@ static int dline_deductions(solver_state *sstate)
int opp_index;
if (opp == j || opp == k)
continue;
opp_index = d->edges[opp] - g->edges;
opp_index = d->edges[opp]->index;
if (state->lines[opp_index] == LINE_UNKNOWN) {
solver_set_line(sstate, opp_index,
LINE_YES);
@ -2690,7 +2687,7 @@ static int linedsf_deductions(solver_state *sstate)
if (clue < 0)
continue;
N = g->faces[i].order;
N = g->faces[i]->order;
yes = sstate->face_yes_count[i];
if (yes + 1 == clue) {
if (face_setall_identical(sstate, i, LINE_NO))
@ -2708,14 +2705,14 @@ static int linedsf_deductions(solver_state *sstate)
/* Deductions with small number of LINE_UNKNOWNs, based on overall
* parity of lines. */
diff_tmp = parity_deductions(sstate, g->faces[i].edges,
diff_tmp = parity_deductions(sstate, g->faces[i]->edges,
(clue - yes) % 2, unknown);
diff = min(diff, diff_tmp);
}
/* ------ Dot deductions ------ */
for (i = 0; i < g->num_dots; i++) {
grid_dot *d = g->dots + i;
grid_dot *d = g->dots[i];
int N = d->order;
int j;
int yes, no, unknown;
@ -2728,12 +2725,12 @@ static int linedsf_deductions(solver_state *sstate)
int can1, can2;
bool inv1, inv2;
int j2;
line1_index = d->edges[j] - g->edges;
line1_index = d->edges[j]->index;
if (state->lines[line1_index] != LINE_UNKNOWN)
continue;
j2 = j + 1;
if (j2 == N) j2 = 0;
line2_index = d->edges[j2] - g->edges;
line2_index = d->edges[j2]->index;
if (state->lines[line2_index] != LINE_UNKNOWN)
continue;
/* Infer dline flags from linedsf */
@ -2855,9 +2852,9 @@ static int loop_deductions(solver_state *sstate)
* loop it would create is a solution.
*/
for (i = 0; i < g->num_edges; i++) {
grid_edge *e = g->edges + i;
int d1 = e->dot1 - g->dots;
int d2 = e->dot2 - g->dots;
grid_edge *e = g->edges[i];
int d1 = e->dot1->index;
int d2 = e->dot2->index;
int eqclass, val;
if (state->lines[i] != LINE_UNKNOWN)
continue;
@ -2894,13 +2891,13 @@ static int loop_deductions(solver_state *sstate)
*/
sm1_nearby = 0;
if (e->face1) {
int f = e->face1 - g->faces;
int f = e->face1->index;
int c = state->clues[f];
if (c >= 0 && sstate->face_yes_count[f] == c - 1)
sm1_nearby++;
}
if (e->face2) {
int f = e->face2 - g->faces;
int f = e->face2->index;
int c = state->clues[f];
if (c >= 0 && sstate->face_yes_count[f] == c - 1)
sm1_nearby++;
@ -3065,7 +3062,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
if (e == NULL)
return NULL;
i = e - g->edges;
i = e->index;
/* I think it's only possible to play this game with mouse clicks, sorry */
/* Maybe will add mouse drag support some time */
@ -3126,7 +3123,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
for (j = n_found = 0; j < dot->order; j++) {
grid_edge *e_candidate = dot->edges[j];
int i_candidate = e_candidate - g->edges;
int i_candidate = e_candidate->index;
if (e_candidate != e_this &&
(ui->autofollow == AF_FIXED ||
state->lines[i] == LINE_NO ||
@ -3137,7 +3134,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
}
if (n_found != 1 ||
state->lines[e_next - g->edges] != state->lines[i])
state->lines[e_next->index] != state->lines[i])
break;
if (e_next == e) {
@ -3164,7 +3161,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
}
e_this = e_next;
movelen += sprintf(movebuf+movelen, "%d%c",
(int)(e_this - g->edges), button_char);
(int)(e_this->index), button_char);
}
autofollow_done:;
}
@ -3237,7 +3234,7 @@ static void grid_to_screen(const game_drawstate *ds, const grid *g,
static void face_text_pos(const game_drawstate *ds, const grid *g,
grid_face *f, int *xret, int *yret)
{
int faceindex = f - g->faces;
int faceindex = f->index;
/*
* Return the cached position for this face, if we've already
@ -3280,7 +3277,7 @@ static void game_redraw_clue(drawing *dr, game_drawstate *ds,
const game_state *state, int i)
{
grid *g = state->game_grid;
grid_face *f = g->faces + i;
grid_face *f = g->faces[i];
int x, y;
char c[20];
@ -3345,7 +3342,7 @@ static void game_redraw_line(drawing *dr, game_drawstate *ds,const game_ui *ui,
const game_state *state, int i, int phase)
{
grid *g = state->game_grid;
grid_edge *e = g->edges + i;
grid_edge *e = g->edges[i];
int x1, x2, y1, y2;
int line_colour;
@ -3384,7 +3381,7 @@ static void game_redraw_dot(drawing *dr, game_drawstate *ds,
const game_state *state, int i)
{
grid *g = state->game_grid;
grid_dot *d = g->dots + i;
grid_dot *d = g->dots[i];
int x, y;
grid_to_screen(ds, g, d->x, d->y, &x, &y);
@ -3415,20 +3412,20 @@ static void game_redraw_in_rect(drawing *dr, game_drawstate *ds,
for (i = 0; i < g->num_faces; i++) {
if (state->clues[i] >= 0) {
face_text_bbox(ds, g, &g->faces[i], &bx, &by, &bw, &bh);
face_text_bbox(ds, g, g->faces[i], &bx, &by, &bw, &bh);
if (boxes_intersect(x, y, w, h, bx, by, bw, bh))
game_redraw_clue(dr, ds, state, i);
}
}
for (phase = 0; phase < NPHASES; phase++) {
for (i = 0; i < g->num_edges; i++) {
edge_bbox(ds, g, &g->edges[i], &bx, &by, &bw, &bh);
edge_bbox(ds, g, g->edges[i], &bx, &by, &bw, &bh);
if (boxes_intersect(x, y, w, h, bx, by, bw, bh))
game_redraw_line(dr, ds, ui, state, i, phase);
}
}
for (i = 0; i < g->num_dots; i++) {
dot_bbox(ds, g, &g->dots[i], &bx, &by, &bw, &bh);
dot_bbox(ds, g, g->dots[i], &bx, &by, &bw, &bh);
if (boxes_intersect(x, y, w, h, bx, by, bw, bh))
game_redraw_dot(dr, ds, state, i);
}
@ -3488,7 +3485,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
/* First, trundle through the faces. */
for (i = 0; i < g->num_faces; i++) {
grid_face *f = g->faces + i;
grid_face *f = g->faces[i];
int sides = f->order;
int yes_order, no_order;
bool clue_mistake;
@ -3588,7 +3585,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
/* Right. Now we roll up our sleeves. */
for (i = 0; i < nfaces; i++) {
grid_face *f = g->faces + faces[i];
grid_face *f = g->faces[faces[i]];
int x, y, w, h;
face_text_bbox(ds, g, f, &x, &y, &w, &h);
@ -3596,7 +3593,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
}
for (i = 0; i < nedges; i++) {
grid_edge *e = g->edges + edges[i];
grid_edge *e = g->edges[edges[i]];
int x, y, w, h;
edge_bbox(ds, g, e, &x, &y, &w, &h);
@ -3660,7 +3657,7 @@ static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
for (i = 0; i < g->num_dots; i++) {
int x, y;
grid_to_screen(ds, g, g->dots[i].x, g->dots[i].y, &x, &y);
grid_to_screen(ds, g, g->dots[i]->x, g->dots[i]->y, &x, &y);
draw_circle(dr, x, y, ds->tilesize / 15, ink, ink);
}
@ -3668,7 +3665,7 @@ static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
* Clues.
*/
for (i = 0; i < g->num_faces; i++) {
grid_face *f = g->faces + i;
grid_face *f = g->faces[i];
int clue = state->clues[i];
if (clue >= 0) {
char c[20];
@ -3686,7 +3683,7 @@ static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
*/
for (i = 0; i < g->num_edges; i++) {
int thickness = (state->lines[i] == LINE_YES) ? 30 : 150;
grid_edge *e = g->edges + i;
grid_edge *e = g->edges[i];
int x1, y1, x2, y2;
grid_to_screen(ds, g, e->dot1->x, e->dot1->y, &x1, &y1);
grid_to_screen(ds, g, e->dot2->x, e->dot2->y, &x2, &y2);