ret[COL_FOREGROUND * 3 + 1] = 0.0F;
ret[COL_FOREGROUND * 3 + 2] = 0.0F;
- ret[COL_LINEUNKNOWN * 3 + 0] = 0.8F;
- ret[COL_LINEUNKNOWN * 3 + 1] = 0.8F;
+ /*
+ * We want COL_LINEUNKNOWN to be a yellow which is a bit darker
+ * than the background. (I previously set it to 0.8,0.8,0, but
+ * found that this went badly with the 0.8,0.8,0.8 favoured as a
+ * background by the Java frontend.)
+ */
+ ret[COL_LINEUNKNOWN * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.9F;
+ ret[COL_LINEUNKNOWN * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 0.9F;
ret[COL_LINEUNKNOWN * 3 + 2] = 0.0F;
ret[COL_HIGHLIGHT * 3 + 0] = 1.0F;
grid *g;
game_state *state = snew(game_state);
game_state *state_new;
- int count = 0;
params_generate_grid(params);
state->game_grid = g = params->game_grid;
g->refcount++;
* preventing games smaller than 4x4 seems to stop this happening */
do {
add_full_clues(state, rs);
- if (++count%100 == 0) printf("tried %d times to make a unique board\n", count);
} while (!game_has_unique_soln(state, params->diff));
state_new = remove_clues(state, rs, params->diff);
if (state->clues[i] < 0)
continue;
+ /*
+ * This code checks whether the numeric clue on a face is so
+ * large as to permit all its remaining LINE_UNKNOWNs to be
+ * filled in as LINE_YES, or alternatively so small as to
+ * permit them all to be filled in as LINE_NO.
+ */
+
if (state->clues[i] < current_yes) {
sstate->solver_status = SOLVER_MISTAKE;
return DIFF_EASY;
sstate->face_solved[i] = TRUE;
continue;
}
+
+ if (f->order - state->clues[i] == current_no + 1 &&
+ f->order - current_yes - current_no > 2) {
+ /*
+ * One small refinement to the above: we also look for any
+ * adjacent pair of LINE_UNKNOWNs around the face with
+ * some LINE_YES incident on it from elsewhere. If we find
+ * one, then we know that pair of LINE_UNKNOWNs can't
+ * _both_ be LINE_YES, and hence that pushes us one line
+ * closer to being able to determine all the rest.
+ */
+ 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;
+
+ if (g->edges[e1].dot1 == g->edges[e2].dot1 ||
+ g->edges[e1].dot1 == g->edges[e2].dot2) {
+ d = g->edges[e1].dot1 - g->dots;
+ } 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;
+ }
+
+ 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;
+ if (state->lines[e] == LINE_YES)
+ goto found; /* multi-level break */
+ }
+ }
+ }
+ continue;
+
+ found:
+ /*
+ * If we get here, we've found such a pair of edges, and
+ * they're e1 and e2.
+ */
+ for (j = 0; j < f->order; j++) {
+ e = f->edges[j] - g->edges;
+ if (state->lines[e] == LINE_UNKNOWN && e != e1 && e != e2) {
+ int r = solver_set_line(sstate, e, LINE_YES);
+ assert(r);
+ diff = min(diff, DIFF_EASY);
+ }
+ }
+ }
}
check_caches(sstate);
/* Returns (into x,y) position of centre of face for rendering the text clue.
*/
static void face_text_pos(const game_drawstate *ds, const grid *g,
- const grid_face *f, int *xret, int *yret)
+ grid_face *f, int *xret, int *yret)
{
- int x, y, x0, y0, x1, y1, xbest, ybest, i, shift;
- long bestdist;
int faceindex = f - g->faces;
/*
}
/*
- * Otherwise, try to find the point in the polygon with the
- * maximum distance to any edge or corner.
- *
- * Start by working out the face's bounding box, in grid
- * coordinates.
+ * Otherwise, use the incentre computed by grid.c and convert it
+ * to screen coordinates.
*/
- x0 = x1 = f->dots[0]->x;
- y0 = y1 = f->dots[0]->y;
- for (i = 1; i < f->order; i++) {
- if (x0 > f->dots[i]->x) x0 = f->dots[i]->x;
- if (x1 < f->dots[i]->x) x1 = f->dots[i]->x;
- if (y0 > f->dots[i]->y) y0 = f->dots[i]->y;
- if (y1 < f->dots[i]->y) y1 = f->dots[i]->y;
- }
-
- /*
- * If the grid is at excessive resolution, decide on a scaling
- * factor to bring it within reasonable bounds so we don't have to
- * think too hard or suffer integer overflow.
- */
- shift = 0;
- while (x1 - x0 > 128 || y1 - y0 > 128) {
- shift++;
- x0 >>= 1;
- x1 >>= 1;
- y0 >>= 1;
- y1 >>= 1;
- }
-
- /*
- * Now iterate over every point in that bounding box.
- */
- xbest = ybest = -1;
- bestdist = -1;
- for (y = y0; y <= y1; y++) {
- for (x = x0; x <= x1; x++) {
- /*
- * First, disqualify the point if it's not inside the
- * polygon, which we work out by counting the edges to the
- * right of the point. (For tiebreaking purposes when
- * edges start or end on our y-coordinate or go right
- * through it, we consider our point to be offset by a
- * small _positive_ epsilon in both the x- and
- * y-direction.)
- */
- int in = 0;
- for (i = 0; i < f->order; i++) {
- int xs = f->edges[i]->dot1->x >> shift;
- int xe = f->edges[i]->dot2->x >> shift;
- int ys = f->edges[i]->dot1->y >> shift;
- int ye = f->edges[i]->dot2->y >> shift;
- if ((y >= ys && y < ye) || (y >= ye && y < ys)) {
- /*
- * The line goes past our y-position. Now we need
- * to know if its x-coordinate when it does so is
- * to our right.
- *
- * The x-coordinate in question is mathematically
- * (y - ys) * (xe - xs) / (ye - ys), and we want
- * to know whether (x - xs) >= that. Of course we
- * avoid the division, so we can work in integers;
- * to do this we must multiply both sides of the
- * inequality by ye - ys, which means we must
- * first check that's not negative.
- */
- int num = xe - xs, denom = ye - ys;
- if (denom < 0) {
- num = -num;
- denom = -denom;
- }
- if ((x - xs) * denom >= (y - ys) * num)
- in ^= 1;
- }
- }
-
- if (in) {
- long mindist = LONG_MAX;
-
- /*
- * This point is inside the polygon, so now we check
- * its minimum distance to every edge and corner.
- * First the corners ...
- */
- for (i = 0; i < f->order; i++) {
- int xp = f->dots[i]->x >> shift;
- int yp = f->dots[i]->y >> shift;
- int dx = x - xp, dy = y - yp;
- long dist = (long)dx*dx + (long)dy*dy;
- if (mindist > dist)
- mindist = dist;
- }
-
- /*
- * ... and now also check the perpendicular distance
- * to every edge, if the perpendicular lies between
- * the edge's endpoints.
- */
- for (i = 0; i < f->order; i++) {
- int xs = f->edges[i]->dot1->x >> shift;
- int xe = f->edges[i]->dot2->x >> shift;
- int ys = f->edges[i]->dot1->y >> shift;
- int ye = f->edges[i]->dot2->y >> shift;
-
- /*
- * If s and e are our endpoints, and p our
- * candidate circle centre, the foot of a
- * perpendicular from p to the line se lies
- * between s and e if and only if (p-s).(e-s) lies
- * strictly between 0 and (e-s).(e-s).
- */
- int edx = xe - xs, edy = ye - ys;
- int pdx = x - xs, pdy = y - ys;
- long pde = (long)pdx * edx + (long)pdy * edy;
- long ede = (long)edx * edx + (long)edy * edy;
- if (0 < pde && pde < ede) {
- /*
- * Yes, the nearest point on this edge is
- * closer than either endpoint, so we must
- * take it into account by measuring the
- * perpendicular distance to the edge and
- * checking its square against mindist.
- */
-
- long pdre = (long)pdx * edy - (long)pdy * edx;
- long sqlen = pdre * pdre / ede;
-
- if (mindist > sqlen)
- mindist = sqlen;
- }
- }
-
- /*
- * Right. Now we know the biggest circle around this
- * point, so we can check it against bestdist.
- */
- if (bestdist < mindist) {
- bestdist = mindist;
- xbest = x;
- ybest = y;
- }
- }
- }
- }
-
- assert(bestdist >= 0);
-
- /* convert to screen coordinates */
- grid_to_screen(ds, g, xbest << shift, ybest << shift,
+ grid_find_incentre(f);
+ grid_to_screen(ds, g, f->ix, f->iy,
&ds->textx[faceindex], &ds->texty[faceindex]);
*xret = ds->textx[faceindex];
draw_rect(dr, x, y, w, h, COL_BACKGROUND);
for (i = 0; i < g->num_faces; i++) {
- 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);
+ if (state->clues[i] >= 0) {
+ 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++) {
return 0.0F;
}
+static int game_is_solved(game_state *state)
+{
+ return state->solved;
+}
+
static void game_print_size(game_params *params, float *x, float *y)
{
int pw, ph;
game_redraw,
game_anim_length,
game_flash_length,
+ game_is_solved,
TRUE, FALSE, game_print_size, game_print,
FALSE /* wants_statusbar */,
FALSE, game_timing_state,