X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/315e47b99f087aa874c1ea094c73947696e7e3c2..80e7e37cd954d03f10a6a69f857c9033d05d1809:/loopy.c diff --git a/loopy.c b/loopy.c index a52065e..afa362c 100644 --- a/loopy.c +++ b/loopy.c @@ -102,6 +102,7 @@ enum { COL_HIGHLIGHT, COL_MISTAKE, COL_SATISFIED, + COL_FAINT, NCOLOURS }; @@ -844,6 +845,14 @@ static float *game_colours(frontend *fe, int *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; } @@ -1300,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; @@ -1344,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. */ @@ -1385,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; } @@ -1504,6 +1545,7 @@ static void add_full_clues(game_state *state, random_state *rs) 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 @@ -1555,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); @@ -3181,6 +3222,10 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds, button_char = 'y'; break; case LINE_YES: +#ifdef STYLUS_BASED + button_char = 'n'; + break; +#endif case LINE_NO: button_char = 'u'; break; @@ -3195,6 +3240,10 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds, button_char = 'n'; break; case LINE_NO: +#ifdef STYLUS_BASED + button_char = 'y'; + break; +#endif case LINE_YES: button_char = 'u'; break; @@ -3223,6 +3272,8 @@ static game_state *execute_move(game_state *state, char *move) while (*move) { i = atoi(move); + if (i < 0 || i >= newstate->game_grid->num_edges) + goto fail; move += strspn(move, "1234567890"); switch (*(move++)) { case 'y': @@ -3467,7 +3518,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate, 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 @@ -3482,7 +3533,16 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate, 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. */