X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/95eedaa61373a2d476dbf8bd350903122409871a..8b738d6161f551dcb4778eecada784e9c1d2d3b1:/pattern.c diff --git a/pattern.c b/pattern.c index 91b1a2f..6dda1f4 100644 --- a/pattern.c +++ b/pattern.c @@ -281,6 +281,15 @@ static void generate(random_state *rs, int w, int h, unsigned char *retgrid) for (q = -1; q <= +1; q++) { if (i+p < 0 || i+p >= h || j+q < 0 || j+q >= w) continue; + /* + * An additional special case not mentioned + * above: if a grid dimension is 2xn then + * we do not average across that dimension + * at all. Otherwise a 2x2 grid would + * contain four identical squares. + */ + if ((h==2 && p!=0) || (w==2 && q!=0)) + continue; n++; sx += fgrid[(i+p)*w+(j+q)]; } @@ -303,7 +312,7 @@ static void generate(random_state *rs, int w, int h, unsigned char *retgrid) for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { - retgrid[i*w+j] = (fgrid[i*w+j] > threshold ? GRID_FULL : + retgrid[i*w+j] = (fgrid[i*w+j] >= threshold ? GRID_FULL : GRID_EMPTY); } } @@ -408,6 +417,34 @@ static unsigned char *generate_soluble(random_state *rs, int w, int h) generate(rs, w, h, grid); + /* + * The game is a bit too easy if any row or column is + * completely black or completely white. An exception is + * made for rows/columns that are under 3 squares, + * otherwise nothing will ever be successfully generated. + */ + ok = TRUE; + if (w > 2) { + for (i = 0; i < h; i++) { + int colours = 0; + for (j = 0; j < w; j++) + colours |= (grid[i*w+j] == GRID_FULL ? 2 : 1); + if (colours != 3) + ok = FALSE; + } + } + if (h > 2) { + for (j = 0; j < w; j++) { + int colours = 0; + for (i = 0; i < h; i++) + colours |= (grid[i*w+j] == GRID_FULL ? 2 : 1); + if (colours != 3) + ok = FALSE; + } + } + if (!ok) + continue; + memset(matrix, 0, w*h); do { @@ -611,6 +648,11 @@ static void free_game(game_state *state) sfree(state); } +static char *game_text_format(game_state *state) +{ + return NULL; +} + struct game_ui { int dragging; int drag_start_x; @@ -978,21 +1020,21 @@ static int game_wants_statusbar(void) #endif const struct game thegame = { - "Pattern", "games.pattern", TRUE, + "Pattern", "games.pattern", default_params, game_fetch_preset, decode_params, encode_params, free_params, dup_params, - game_configure, - custom_params, + TRUE, game_configure, custom_params, validate_params, new_game_seed, validate_seed, new_game, dup_game, free_game, + FALSE, game_text_format, new_ui, free_ui, make_move, @@ -1005,3 +1047,125 @@ const struct game thegame = { game_flash_length, game_wants_statusbar, }; + +#ifdef STANDALONE_SOLVER + +/* + * gcc -DSTANDALONE_SOLVER -o patternsolver pattern.c malloc.c + */ + +#include + +void frontend_default_colour(frontend *fe, float *output) {} +void draw_text(frontend *fe, int x, int y, int fonttype, int fontsize, + int align, int colour, char *text) {} +void draw_rect(frontend *fe, int x, int y, int w, int h, int colour) {} +void draw_line(frontend *fe, int x1, int y1, int x2, int y2, int colour) {} +void draw_polygon(frontend *fe, int *coords, int npoints, + int fill, int colour) {} +void clip(frontend *fe, int x, int y, int w, int h) {} +void unclip(frontend *fe) {} +void start_draw(frontend *fe) {} +void draw_update(frontend *fe, int x, int y, int w, int h) {} +void end_draw(frontend *fe) {} +unsigned long random_upto(random_state *state, unsigned long limit) +{ assert(!"Shouldn't get randomness"); return 0; } + +void fatal(char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "fatal error: "); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fprintf(stderr, "\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + game_params *p; + game_state *s; + int recurse = TRUE; + char *id = NULL, *seed, *err; + int y, x; + int grade = FALSE; + + while (--argc > 0) { + char *p = *++argv; + if (*p == '-') { + fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0]); + return 1; + } else { + id = p; + } + } + + if (!id) { + fprintf(stderr, "usage: %s \n", argv[0]); + return 1; + } + + seed = strchr(id, ':'); + if (!seed) { + fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]); + return 1; + } + *seed++ = '\0'; + + p = decode_params(id); + err = validate_seed(p, seed); + if (err) { + fprintf(stderr, "%s: %s\n", argv[0], err); + return 1; + } + s = new_game(p, seed); + + { + int w = p->w, h = p->h, i, j, done_any, max; + unsigned char *matrix, *workspace; + int *rowdata; + + matrix = snewn(w*h, unsigned char); + max = max(w, h); + workspace = snewn(max*3, unsigned char); + rowdata = snewn(max+1, int); + + memset(matrix, 0, w*h); + + do { + done_any = 0; + for (i=0; irowdata + s->rowsize*(w+i), + max*sizeof(int)); + rowdata[s->rowlen[w+i]] = 0; + done_any |= do_row(workspace, workspace+max, workspace+2*max, + matrix+i*w, w, 1, rowdata); + } + for (i=0; irowdata + s->rowsize*i, max*sizeof(int)); + rowdata[s->rowlen[i]] = 0; + done_any |= do_row(workspace, workspace+max, workspace+2*max, + matrix+i, h, w, rowdata); + } + } while (done_any); + + for (i = 0; i < h; i++) { + for (j = 0; j < w; j++) { + int c = (matrix[i*w+j] == UNKNOWN ? '?' : + matrix[i*w+j] == BLOCK ? '#' : + matrix[i*w+j] == DOT ? '.' : + '!'); + putchar(c); + } + printf("\n"); + } + } + + return 0; +} + +#endif