struct game_params {
int w, h;
float expandfactor;
+ int unique;
};
#define INDEX(state, x, y) (((y) * (state)->w) + (x))
ret->w = ret->h = 7;
ret->expandfactor = 0.0F;
+ ret->unique = TRUE;
return ret;
}
ret->w = w;
ret->h = h;
ret->expandfactor = 0.0F;
+ ret->unique = TRUE;
return TRUE;
}
if (*string == 'e') {
string++;
ret->expandfactor = atof(string);
+ while (*string &&
+ (*string == '.' || isdigit((unsigned char)*string))) string++;
+ }
+ if (*string == 'a') {
+ string++;
+ ret->unique = FALSE;
}
}
sprintf(data, "%dx%d", params->w, params->h);
if (full && params->expandfactor)
sprintf(data + strlen(data), "e%g", params->expandfactor);
+ if (full && !params->unique)
+ strcat(data, "a");
return dupstr(data);
}
ret[2].sval = dupstr(buf);
ret[2].ival = 0;
- ret[3].name = NULL;
- ret[3].type = C_END;
+ ret[3].name = "Ensure unique solution";
+ ret[3].type = C_BOOLEAN;
ret[3].sval = NULL;
- ret[3].ival = 0;
+ ret[3].ival = params->unique;
+
+ ret[4].name = NULL;
+ ret[4].type = C_END;
+ ret[4].sval = NULL;
+ ret[4].ival = 0;
return ret;
}
ret->w = atoi(cfg[0].sval);
ret->h = atoi(cfg[1].sval);
ret->expandfactor = atof(cfg[2].sval);
+ ret->unique = cfg[3].ival;
return ret;
}
}
static int rect_solver(int w, int h, int nrects, struct numberdata *numbers,
- random_state *rs)
+ game_state *result, random_state *rs)
{
struct rectlist *rectpositions;
int *overlaps, *rectbyplace, *workspace;
* rectangle) which overlaps a candidate placement of the
* number for some other rectangle.
*/
- {
+ if (rs) {
struct rpn {
int rect;
int placement;
i, rectpositions[i].n);
#endif
assert(rectpositions[i].n > 0);
- if (rectpositions[i].n > 1)
+ if (rectpositions[i].n > 1) {
ret = FALSE;
+ } else if (result) {
+ /*
+ * Place the rectangle in its only possible position.
+ */
+ int x, y;
+ struct rect *r = &rectpositions[i].rects[0];
+
+ for (y = 0; y < r->h; y++) {
+ if (r->x > 0)
+ vedge(result, r->x, r->y+y) = 1;
+ if (r->x+r->w < result->w)
+ vedge(result, r->x+r->w, r->y+y) = 1;
+ }
+ for (x = 0; x < r->w; x++) {
+ if (r->y > 0)
+ hedge(result, r->x+x, r->y) = 1;
+ if (r->y+r->h < result->h)
+ hedge(result, r->x+x, r->y+r->h) = 1;
+ }
+ }
}
/*
}
}
- ret = rect_solver(params->w, params->h, nnumbers, nd, rs);
+ if (params->unique)
+ ret = rect_solver(params->w, params->h, nnumbers, nd,
+ NULL, rs);
+ else
+ ret = TRUE; /* allow any number placement at all */
if (ret) {
/*
return NULL;
}
-static game_state *new_game(game_params *params, char *desc)
+static game_state *new_game(midend_data *me, game_params *params, char *desc)
{
game_state *state = snew(game_state);
int x, y, i, area;
game_state *ret;
if (!ai) {
- *error = "Solution not known for this puzzle";
- return NULL;
+ int i, j, n;
+ struct numberdata *nd;
+
+ /*
+ * Attempt the in-built solver.
+ */
+
+ /* Set up each number's (very short) candidate position list. */
+ for (i = n = 0; i < state->h * state->w; i++)
+ if (state->grid[i])
+ n++;
+
+ nd = snewn(n, struct numberdata);
+
+ for (i = j = 0; i < state->h * state->w; i++)
+ if (state->grid[i]) {
+ nd[j].area = state->grid[i];
+ nd[j].npoints = 1;
+ nd[j].points = snewn(1, struct point);
+ nd[j].points[0].x = i % state->w;
+ nd[j].points[0].y = i / state->w;
+ j++;
+ }
+
+ assert(j == n);
+
+ ret = dup_game(state);
+ ret->cheated = TRUE;
+
+ rect_solver(state->w, state->h, n, nd, ret, NULL);
+
+ /*
+ * Clean up.
+ */
+ for (i = 0; i < n; i++)
+ sfree(nd[i].points);
+ sfree(nd);
+
+ return ret;
}
assert(state->w == ai->w);
int startdrag = FALSE, enddrag = FALSE, active = FALSE;
game_state *ret;
+ button &= ~MOD_MASK;
+
if (button == LEFT_BUTTON) {
startdrag = TRUE;
} else if (button == LEFT_RELEASE) {
}
static float game_anim_length(game_state *oldstate,
- game_state *newstate, int dir)
+ game_state *newstate, int dir, game_ui *ui)
{
return 0.0F;
}
static float game_flash_length(game_state *oldstate,
- game_state *newstate, int dir)
+ game_state *newstate, int dir, game_ui *ui)
{
if (!oldstate->completed && newstate->completed &&
!oldstate->cheated && !newstate->cheated)
return FALSE;
}
+static int game_timing_state(game_state *state)
+{
+ return TRUE;
+}
+
#ifdef COMBINED
#define thegame rect
#endif
game_anim_length,
game_flash_length,
game_wants_statusbar,
+ FALSE, game_timing_state,
};