Fix for the grid generation in the presence of particularly strange

grid types.

[originally from svn r8750]
This commit is contained in:
Simon Tatham
2009-11-16 21:21:00 +00:00
parent 9c95ea2619
commit 2ac017b62c

63
loopy.c
View File

@ -1309,6 +1309,7 @@ static int can_colour_face(grid *g, char* board, int face_index,
int i, j;
grid_face *test_face = g->faces + face_index;
grid_face *starting_face, *current_face;
grid_dot *starting_dot;
int transitions;
int current_state, s; /* booleans: equal or not-equal to 'colour' */
int found_same_coloured_neighbour = FALSE;
@ -1353,17 +1354,39 @@ static int can_colour_face(grid *g, char* board, int face_index,
* test_face->dots[i]->faces[j]
* We assume dots go clockwise around the test face,
* and faces go clockwise around dots. */
/*
* The end condition is slightly fiddly. In sufficiently strange
* degenerate grids, our test face may be adjacent to the same
* other face multiple times (typically if it's the exterior
* face). Consider this, in particular:
*
* +--+
* | |
* +--+--+
* | | |
* +--+--+
*
* The bottom left face there is adjacent to the exterior face
* twice, so we can't just terminate our iteration when we reach
* the same _face_ we started at. Furthermore, we can't
* condition on having the same (i,j) pair either, because
* several (i,j) pairs identify the bottom left contiguity with
* the exterior face! We canonicalise the (i,j) pair by taking
* one step around before we set the termination tracking.
*/
i = j = 0;
starting_face = test_face->dots[0]->faces[0];
if (starting_face == test_face) {
current_face = test_face->dots[0]->faces[0];
if (current_face == test_face) {
j = 1;
starting_face = test_face->dots[0]->faces[1];
current_face = test_face->dots[0]->faces[1];
}
current_face = starting_face;
transitions = 0;
current_state = (FACE_COLOUR(current_face) == colour);
do {
starting_dot = NULL;
starting_face = NULL;
while (TRUE) {
/* Advance to next face.
* Need to loop here because it might take several goes to
* find it. */
@ -1394,13 +1417,22 @@ static int can_colour_face(grid *g, char* board, int face_index,
/* (i,j) are now advanced to next face */
current_face = test_face->dots[i]->faces[j];
s = (FACE_COLOUR(current_face) == colour);
if (s != current_state) {
++transitions;
current_state = s;
if (transitions > 2)
return FALSE; /* no point in continuing */
if (!starting_dot) {
starting_dot = test_face->dots[i];
starting_face = current_face;
current_state = s;
} else {
if (s != current_state) {
++transitions;
current_state = s;
if (transitions > 2)
break;
}
if (test_face->dots[i] == starting_dot &&
current_face == starting_face)
break;
}
} while (current_face != starting_face);
}
return (transitions == 2) ? TRUE : FALSE;
}
@ -1565,12 +1597,11 @@ static void add_full_clues(game_state *state, random_state *rs)
struct face_score *fs_white, *fs_black;
int c_lightable = count234(lightable_faces_sorted);
int c_darkable = count234(darkable_faces_sorted);
if (c_lightable == 0) {
/* No more lightable faces. Because of how the algorithm
* works, there should be no more darkable faces either. */
assert(c_darkable == 0);
if (c_lightable == 0 && c_darkable == 0) {
/* No more faces we can use at all. */
break;
}
assert(c_lightable != 0 && c_darkable != 0);
fs_white = (struct face_score *)index234(lightable_faces_sorted, 0);
fs_black = (struct face_score *)index234(darkable_faces_sorted, 0);