COL_HIGHLIGHT,
COL_MISTAKE,
COL_SATISFIED,
+ COL_FAINT,
NCOLOURS
};
ret[COL_SATISFIED * 3 + 1] = 0.0F;
ret[COL_SATISFIED * 3 + 2] = 0.0F;
+ /* We want the faint lines to be a bit darker than the background.
+ * Except if the background is pretty dark already; then it ought to be a
+ * bit lighter. Oy vey.
+ */
+ ret[COL_FAINT * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.9F;
+ ret[COL_FAINT * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 0.9F;
+ ret[COL_FAINT * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 0.9F;
+
*ncolours = NCOLOURS;
return ret;
}
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;
* 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. */
/* (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;
}
face_scores = snewn(num_faces, struct face_score);
for (i = 0; i < num_faces; i++) {
face_scores[i].random = random_bits(rs, 31);
+ face_scores[i].black_score = face_scores[i].white_score = 0;
}
/* Colour a random, finite face white. The infinite face is implicitly
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);
button_char = 'y';
break;
case LINE_YES:
+#ifdef STYLUS_BASED
+ button_char = 'n';
+ break;
+#endif
case LINE_NO:
button_char = 'u';
break;
button_char = 'n';
break;
case LINE_NO:
+#ifdef STYLUS_BASED
+ button_char = 'y';
+ break;
+#endif
case LINE_YES:
button_char = 'u';
break;
while (*move) {
i = atoi(move);
+ if (i < 0 || i >= newstate->game_grid->num_edges)
+ goto fail;
move += strspn(move, "1234567890");
switch (*(move++)) {
case 'y':
else if (state->lines[i] == LINE_UNKNOWN)
line_colour = COL_LINEUNKNOWN;
else if (state->lines[i] == LINE_NO)
- line_colour = COL_BACKGROUND;
+ line_colour = COL_FAINT;
else if (ds->flashing)
line_colour = COL_HIGHLIGHT;
else
ymin = min(y1, y2);
ymax = max(y1, y2);
- if (line_colour != COL_BACKGROUND) {
+ if (line_colour == COL_FAINT) {
+ static int draw_faint_lines = -1;
+ if (draw_faint_lines < 0) {
+ char *env = getenv("LOOPY_FAINT_LINES");
+ draw_faint_lines = (!env || (env[0] == 'y' ||
+ env[0] == 'Y'));
+ }
+ if (draw_faint_lines)
+ draw_line(dr, x1, y1, x2, y2, line_colour);
+ } else {
/* (dx, dy) points roughly from (x1, y1) to (x2, y2).
* The line is then "fattened" in a (roughly) perpendicular
* direction to create a thin rectangle. */
game_drawstate ads, *ds = &ads;
grid *g = state->game_grid;
- game_set_size(dr, ds, NULL, tilesize);
+ ds->tilesize = tilesize;
for (i = 0; i < g->num_dots; i++) {
int x, y;