sfree(params);
}
-static game_params *dup_params(game_params *params)
+static game_params *dup_params(const game_params *params)
{
game_params *ret = snew(game_params);
*ret = *params; /* structure copy */
}
}
-static char *encode_params(game_params *params, int full)
+static char *encode_params(const game_params *params, int full)
{
char str[80];
return dupstr(str);
}
-static config_item *game_configure(game_params *params)
+static config_item *game_configure(const game_params *params)
{
config_item *ret;
char buf[80];
return ret;
}
-static game_params *custom_params(config_item *cfg)
+static game_params *custom_params(const config_item *cfg)
{
game_params *ret = snew(game_params);
return ret;
}
-static char *validate_params(game_params *params, int full)
+static char *validate_params(const game_params *params, int full)
{
if (params->c < 2)
return "Both dimensions must be at least 2";
}
}
+#if defined STANDALONE_SOLVER && defined __GNUC__
+/*
+ * Forward-declare the functions taking printf-like format arguments
+ * with __attribute__((format)) so as to ensure the argument syntax
+ * gets debugged.
+ */
+struct solver_scratch;
+static int solver_elim(struct solver_usage *usage, int *indices,
+ char *fmt, ...) __attribute__((format(printf,3,4)));
+static int solver_intersect(struct solver_usage *usage,
+ int *indices1, int *indices2, char *fmt, ...)
+ __attribute__((format(printf,4,5)));
+static int solver_set(struct solver_usage *usage,
+ struct solver_scratch *scratch,
+ int *indices, char *fmt, ...)
+ __attribute__((format(printf,4,5)));
+#endif
+
static int solver_elim(struct solver_usage *usage, int *indices
#ifdef STANDALONE_SOLVER
, char *fmt, ...
}
assert(nsquares > 0);
- if (nsquares > 4)
+ if (nsquares < 2 || nsquares > 4)
return 0;
if (!cage_is_region) {
* Place all the clue numbers we are given.
*/
for (x = 0; x < cr; x++)
- for (y = 0; y < cr; y++)
- if (grid[y*cr+x])
+ for (y = 0; y < cr; y++) {
+ int n = grid[y*cr+x];
+ if (n) {
+ if (!cube(x,y,n)) {
+ diff = DIFF_IMPOSSIBLE;
+ goto got_result;
+ }
solver_place(usage, x, y, grid[y*cr+x]);
+ }
+ }
/*
* Now loop over the grid repeatedly trying all permitted modes
);
if (ret > 0) {
changed = TRUE;
- kdiff = max(kdiff, DIFF_KINTERSECT);
+ kdiff = max(kdiff, DIFF_KSUMS);
} else if (ret < 0) {
diff = DIFF_IMPOSSIBLE;
goto got_result;
#ifdef STANDALONE_SOLVER
, "intersectional analysis,"
" %d in \\-diagonal vs block %s",
- n, 1+x, usage->blocks->blocknames[b]
+ n, usage->blocks->blocknames[b]
#endif
) ||
solver_intersect(usage, scratch->indexlist2,
#ifdef STANDALONE_SOLVER
, "intersectional analysis,"
" %d in block %s vs \\-diagonal",
- n, usage->blocks->blocknames[b], 1+x
+ n, usage->blocks->blocknames[b]
#endif
)) {
diff = max(diff, DIFF_INTERSECT);
#ifdef STANDALONE_SOLVER
, "intersectional analysis,"
" %d in /-diagonal vs block %s",
- n, 1+x, usage->blocks->blocknames[b]
+ n, usage->blocks->blocknames[b]
#endif
) ||
solver_intersect(usage, scratch->indexlist2,
#ifdef STANDALONE_SOLVER
, "intersectional analysis,"
" %d in block %s vs /-diagonal",
- n, usage->blocks->blocknames[b], 1+x
+ n, usage->blocks->blocknames[b]
#endif
)) {
diff = max(diff, DIFF_INTERSECT);
scratch->indexlist[i*cr+n-1] = cubepos2(diag1(i), n);
ret = solver_set(usage, scratch, scratch->indexlist
#ifdef STANDALONE_SOLVER
- , "set elimination, \\-diagonal"
+ , "set elimination, /-diagonal"
#endif
);
if (ret < 0) {
return TRUE;
}
-static int symmetries(game_params *params, int x, int y, int *output, int s)
+static int symmetries(const game_params *params, int x, int y,
+ int *output, int s)
{
int c = params->c, r = params->r, cr = c*r;
int i = 0;
return grid_encode_space(area);
}
-static char *encode_puzzle_desc(game_params *params, digit *grid,
+static char *encode_puzzle_desc(const game_params *params, digit *grid,
struct block_structure *blocks,
digit *kgrid,
struct block_structure *kblocks)
return b;
}
-static char *new_game_desc(game_params *params, random_state *rs,
+static char *new_game_desc(const game_params *params, random_state *rs,
char **aux, int interactive)
{
int c = params->c, r = params->r, cr = c*r;
return desc;
}
-static char *spec_to_grid(char *desc, digit *grid, int area)
+static const char *spec_to_grid(const char *desc, digit *grid, int area)
{
int i = 0;
while (*desc && *desc != ',') {
* end of the block spec, and return an error string or NULL if everything
* is OK. The DSF is stored in *PDSF.
*/
-static char *spec_to_dsf(char **pdesc, int **pdsf, int cr, int area)
+static char *spec_to_dsf(const char **pdesc, int **pdsf, int cr, int area)
{
- char *desc = *pdesc;
+ const char *desc = *pdesc;
int pos = 0;
int *dsf;
}
desc++;
- adv = (c != 25); /* 'z' is a special case */
+ adv = (c != 26); /* 'z' is a special case */
while (c-- > 0) {
int p0, p1;
* Non-edge; merge the two dsf classes on either
* side of it.
*/
- assert(pos < 2*cr*(cr-1));
+ if (pos >= 2*cr*(cr-1)) {
+ sfree(dsf);
+ return "Too much data in block structure specification";
+ }
+
if (pos < cr*(cr-1)) {
int y = pos/(cr-1);
int x = pos%(cr-1);
return NULL;
}
-static char *validate_grid_desc(char **pdesc, int range, int area)
+static char *validate_grid_desc(const char **pdesc, int range, int area)
{
- char *desc = *pdesc;
+ const char *desc = *pdesc;
int squares = 0;
while (*desc && *desc != ',') {
int n = *desc++;
return NULL;
}
-static char *validate_block_desc(char **pdesc, int cr, int area,
+static char *validate_block_desc(const char **pdesc, int cr, int area,
int min_nr_blocks, int max_nr_blocks,
int min_nr_squares, int max_nr_squares)
{
return NULL;
}
-static char *validate_desc(game_params *params, char *desc)
+static char *validate_desc(const game_params *params, const char *desc)
{
int cr = params->c * params->r, area = cr*cr;
char *err;
return NULL;
}
-static game_state *new_game(midend *me, game_params *params, char *desc)
+static game_state *new_game(midend *me, const game_params *params,
+ const char *desc)
{
game_state *state = snew(game_state);
int c = params->c, r = params->r, cr = c*r, area = cr * cr;
return state;
}
-static game_state *dup_game(game_state *state)
+static game_state *dup_game(const game_state *state)
{
game_state *ret = snew(game_state);
int cr = state->cr, area = cr * cr;
sfree(state);
}
-static char *solve_game(game_state *state, game_state *currstate,
- char *ai, char **error)
+static char *solve_game(const game_state *state, const game_state *currstate,
+ const char *ai, char **error)
{
int cr = state->cr;
char *ret;
return ret;
}
-static int game_can_format_as_text_now(game_params *params)
+static int game_can_format_as_text_now(const game_params *params)
{
/*
* Formatting Killer puzzles as text is currently unsupported. I
return TRUE;
}
-static char *game_text_format(game_state *state)
+static char *game_text_format(const game_state *state)
{
assert(!state->kblocks);
return grid_text_format(state->cr, state->blocks, state->xtype,
int hcursor;
};
-static game_ui *new_ui(game_state *state)
+static game_ui *new_ui(const game_state *state)
{
game_ui *ui = snew(game_ui);
sfree(ui);
}
-static char *encode_ui(game_ui *ui)
+static char *encode_ui(const game_ui *ui)
{
return NULL;
}
-static void decode_ui(game_ui *ui, char *encoding)
+static void decode_ui(game_ui *ui, const char *encoding)
{
}
-static void game_changed_state(game_ui *ui, game_state *oldstate,
- game_state *newstate)
+static void game_changed_state(game_ui *ui, const game_state *oldstate,
+ const game_state *newstate)
{
int cr = newstate->cr;
/*
int nregions, *entered_items;
};
-static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
- int x, int y, int button)
+static char *interpret_move(const game_state *state, game_ui *ui,
+ const game_drawstate *ds,
+ int x, int y, int button)
{
int cr = state->cr;
int tx, ty;
return dupstr(buf);
}
+ if (button == 'M' || button == 'm')
+ return dupstr("M");
+
return NULL;
}
-static game_state *execute_move(game_state *from, char *move)
+static game_state *execute_move(const game_state *from, const char *move)
{
int cr = from->cr;
game_state *ret;
int x, y, n;
if (move[0] == 'S') {
- char *p;
+ const char *p;
ret = dup_game(from);
ret->completed = ret->cheated = TRUE;
}
}
return ret;
+ } else if (move[0] == 'M') {
+ /*
+ * Fill in absolutely all pencil marks in unfilled squares,
+ * for those who like to play by the rigorous approach of
+ * starting off in that state and eliminating things.
+ */
+ ret = dup_game(from);
+ for (y = 0; y < cr; y++) {
+ for (x = 0; x < cr; x++) {
+ if (!ret->grid[y*cr+x]) {
+ memset(ret->pencil + (y*cr+x)*cr, 1, cr);
+ }
+ }
+ }
+ return ret;
} else
return NULL; /* couldn't parse move string */
}
#define SIZE(cr) ((cr) * TILE_SIZE + 2*BORDER + 1)
#define GETTILESIZE(cr, w) ( (double)(w-1) / (double)(cr+1) )
-static void game_compute_size(game_params *params, int tilesize,
- int *x, int *y)
+static void game_compute_size(const game_params *params, int tilesize,
+ int *x, int *y)
{
/* Ick: fake up `ds->tilesize' for macro expansion purposes */
struct { int tilesize; } ads, *ds = &ads;
}
static void game_set_size(drawing *dr, game_drawstate *ds,
- game_params *params, int tilesize)
+ const game_params *params, int tilesize)
{
ds->tilesize = tilesize;
}
return ret;
}
-static game_drawstate *game_new_drawstate(drawing *dr, game_state *state)
+static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
{
struct game_drawstate *ds = snew(struct game_drawstate);
int cr = state->cr;
sfree(ds);
}
-static void draw_number(drawing *dr, game_drawstate *ds, game_state *state,
- int x, int y, int hl)
+static void draw_number(drawing *dr, game_drawstate *ds,
+ const game_state *state, int x, int y, int hl)
{
int cr = state->cr;
int tx, ty, tw, th;
ds->hl[y*cr+x] = hl;
}
-static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
- game_state *state, int dir, game_ui *ui,
- float animtime, float flashtime)
+static void game_redraw(drawing *dr, game_drawstate *ds,
+ const game_state *oldstate, const game_state *state,
+ int dir, const game_ui *ui,
+ float animtime, float flashtime)
{
int cr = state->cr;
int x, y;
}
}
-static float game_anim_length(game_state *oldstate, game_state *newstate,
- int dir, game_ui *ui)
+static float game_anim_length(const game_state *oldstate,
+ const 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_ui *ui)
+static float game_flash_length(const game_state *oldstate,
+ const game_state *newstate, int dir, game_ui *ui)
{
if (!oldstate->completed && newstate->completed &&
!oldstate->cheated && !newstate->cheated)
return 0.0F;
}
-static int game_timing_state(game_state *state, game_ui *ui)
+static int game_status(const game_state *state)
+{
+ return state->completed ? +1 : 0;
+}
+
+static int game_timing_state(const game_state *state, game_ui *ui)
{
if (state->completed)
return FALSE;
return TRUE;
}
-static void game_print_size(game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, float *x, float *y)
{
int pw, ph;
* the interior of the affected squares.
*/
static void outline_block_structure(drawing *dr, game_drawstate *ds,
- game_state *state,
+ const game_state *state,
struct block_structure *blocks,
int ink, int inset)
{
sfree(coords);
}
-static void game_print(drawing *dr, game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, int tilesize)
{
int cr = state->cr;
int ink = print_mono_colour(dr, 0);
game_redraw,
game_anim_length,
game_flash_length,
+ game_status,
TRUE, FALSE, game_print_size, game_print,
FALSE, /* wants_statusbar */
FALSE, game_timing_state,
dlev.diff==DIFF_IMPOSSIBLE ? "Impossible (no solution exists)":
"INTERNAL ERROR: unrecognised difficulty code");
if (p->killer)
- printf("Killer diffculty: %s\n",
+ printf("Killer difficulty: %s\n",
dlev.kdiff==DIFF_KSINGLE ? "Trivial (single square cages only)":
dlev.kdiff==DIFF_KMINMAX ? "Simple (maximum sum analysis required)":
dlev.kdiff==DIFF_KSUMS ? "Intermediate (sum possibilities)":