ret->c = ret->r = 3;
ret->symm = SYMM_ROT2; /* a plausible default */
- ret->diff = DIFF_SIMPLE; /* so is this */
+ ret->diff = DIFF_BLOCK; /* so is this */
return ret;
}
} presets[] = {
{ "2x2 Trivial", { 2, 2, SYMM_ROT2, DIFF_BLOCK } },
{ "2x3 Basic", { 2, 3, SYMM_ROT2, DIFF_SIMPLE } },
+ { "3x3 Trivial", { 3, 3, SYMM_ROT2, DIFF_BLOCK } },
{ "3x3 Basic", { 3, 3, SYMM_ROT2, DIFF_SIMPLE } },
{ "3x3 Intermediate", { 3, 3, SYMM_ROT2, DIFF_INTERSECT } },
{ "3x3 Advanced", { 3, 3, SYMM_ROT2, DIFF_SET } },
+ { "3x3 Unreasonable", { 3, 3, SYMM_ROT2, DIFF_RECURSIVE } },
{ "3x4 Basic", { 3, 4, SYMM_ROT2, DIFF_SIMPLE } },
{ "4x4 Basic", { 4, 4, SYMM_ROT2, DIFF_SIMPLE } },
};
ret->c = ret->r = atoi(string);
ret->symm = SYMM_ROT2;
+ ret->diff = DIFF_BLOCK;
while (*string && isdigit((unsigned char)*string)) string++;
if (*string == 'x') {
string++;
string++, ret->diff = DIFF_INTERSECT;
else if (*string == 'a') /* advanced */
string++, ret->diff = DIFF_SET;
+ else if (*string == 'u') /* unreasonable */
+ string++, ret->diff = DIFF_RECURSIVE;
} else
string++; /* eat unknown character */
}
ret[3].name = "Difficulty";
ret[3].type = C_CHOICES;
- ret[3].sval = ":Trivial:Basic:Intermediate:Advanced";
+ ret[3].sval = ":Trivial:Basic:Intermediate:Advanced:Unreasonable";
ret[3].ival = params->diff;
ret[4].name = NULL;
return i;
}
+struct game_aux_info {
+ int c, r;
+ digit *grid;
+};
+
static char *new_game_seed(game_params *params, random_state *rs,
game_aux_info **aux)
{
char *seed;
int coords[16], ncoords;
int xlim, ylim;
- int maxdiff;
+ int maxdiff, recursing;
/*
* Adjust the maximum difficulty level to be consistent with
assert(ret == 1);
assert(check_valid(c, r, grid));
+ /*
+ * Save the solved grid in the aux_info.
+ */
+ {
+ game_aux_info *ai = snew(game_aux_info);
+ ai->c = c;
+ ai->r = r;
+ ai->grid = snewn(cr * cr, digit);
+ memcpy(ai->grid, grid, cr * cr * sizeof(digit));
+ *aux = ai;
+ }
+
/*
* Now we have a solved grid, start removing things from it
* while preserving solubility.
*/
symmetry_limit(params, &xlim, &ylim, params->symm);
+ recursing = FALSE;
while (1) {
int x, y, i, j;
* nsolve.
*/
for (i = 0; i < nlocs; i++) {
+ int ret;
+
x = locs[i].x;
y = locs[i].y;
for (j = 0; j < ncoords; j++)
grid2[coords[2*j+1]*cr+coords[2*j]] = 0;
- if (nsolve(c, r, grid2) <= maxdiff) {
+ if (recursing)
+ ret = (rsolve(c, r, grid2, NULL, 2) == 1);
+ else
+ ret = (nsolve(c, r, grid2) <= maxdiff);
+
+ if (ret) {
for (j = 0; j < ncoords; j++)
grid[coords[2*j+1]*cr+coords[2*j]] = 0;
break;
if (i == nlocs) {
/*
- * There was nothing we could remove without destroying
- * solvability.
+ * There was nothing we could remove without
+ * destroying solvability. If we're trying to
+ * generate a recursion-only grid and haven't
+ * switched over to rsolve yet, we now do;
+ * otherwise we give up.
*/
- break;
+ if (maxdiff == DIFF_RECURSIVE && !recursing) {
+ recursing = TRUE;
+ } else {
+ break;
+ }
}
}
memcpy(grid2, grid, area);
- } while (nsolve(c, r, grid2) != maxdiff);
+ } while (nsolve(c, r, grid2) < maxdiff);
sfree(grid2);
sfree(locs);
static void game_free_aux_info(game_aux_info *aux)
{
- assert(!"Shouldn't happen");
+ sfree(aux->grid);
+ sfree(aux);
}
static char *validate_seed(game_params *params, char *seed)
sfree(state);
}
-static game_state *solve_game(game_state *state, game_aux_info *aux,
+static game_state *solve_game(game_state *state, game_aux_info *ai,
char **error)
{
game_state *ret;
- int c = state->c, r = state->r;
+ int c = state->c, r = state->r, cr = c*r;
int rsolve_ret;
- /*
- * I could have stored the grid I invented in the game_aux_info
- * and extracted it here where available, but it seems easier
- * just to run my internal solver in all cases.
- */
-
ret = dup_game(state);
ret->completed = ret->cheated = TRUE;
- rsolve_ret = rsolve(c, r, ret->grid, NULL, 2);
+ /*
+ * If we already have the solution in the aux_info, save
+ * ourselves some time.
+ */
+ if (ai) {
+
+ assert(c == ai->c);
+ assert(r == ai->r);
+ memcpy(ret->grid, ai->grid, cr * cr * sizeof(digit));
- if (rsolve_ret != 1) {
- free_game(ret);
- if (rsolve_ret == 0)
- *error = "No solution exists for this puzzle";
- else
- *error = "Multiple solutions exist for this puzzle";
- return NULL;
+ } else {
+ rsolve_ret = rsolve(c, r, ret->grid, NULL, 2);
+
+ if (rsolve_ret != 1) {
+ free_game(ret);
+ if (rsolve_ret == 0)
+ *error = "No solution exists for this puzzle";
+ else
+ *error = "Multiple solutions exist for this puzzle";
+ return NULL;
+ }
}
return ret;
int tx, ty;
game_state *ret;
+ button &= ~MOD_NUM_KEYPAD; /* we treat this the same as normal */
+
tx = (x + TILE_SIZE - BORDER) / TILE_SIZE - 1;
ty = (y + TILE_SIZE - BORDER) / TILE_SIZE - 1;