X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/b6b0369e58b13a0de27f1758af5e385a1d786e7a..6ae3730169b0c020d90fe20ace77262d19d26a2b:/pattern.c diff --git a/pattern.c b/pattern.c index d597127..4fc1562 100644 --- a/pattern.c +++ b/pattern.c @@ -18,10 +18,6 @@ #define max(x,y) ( (x)>(y) ? (x):(y) ) #define min(x,y) ( (x)<(y) ? (x):(y) ) -const char *const game_name = "Pattern"; -const char *const game_winhelp_topic = "games.pattern"; -const int game_can_configure = TRUE; - enum { COL_BACKGROUND, COL_EMPTY, @@ -61,7 +57,7 @@ struct game_state { #define FLASH_TIME 0.13F -game_params *default_params(void) +static game_params *default_params(void) { game_params *ret = snew(game_params); @@ -70,7 +66,7 @@ game_params *default_params(void) return ret; } -int game_fetch_preset(int i, char **name, game_params **params) +static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char str[80]; @@ -96,19 +92,19 @@ int game_fetch_preset(int i, char **name, game_params **params) return TRUE; } -void free_params(game_params *params) +static void free_params(game_params *params) { sfree(params); } -game_params *dup_params(game_params *params) +static game_params *dup_params(game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } -game_params *decode_params(char const *string) +static game_params *decode_params(char const *string) { game_params *ret = default_params(); char const *p = string; @@ -126,7 +122,7 @@ game_params *decode_params(char const *string) return ret; } -char *encode_params(game_params *params) +static char *encode_params(game_params *params) { char ret[400]; int len; @@ -138,7 +134,7 @@ char *encode_params(game_params *params) return dupstr(ret); } -config_item *game_configure(game_params *params) +static config_item *game_configure(game_params *params) { config_item *ret; char buf[80]; @@ -165,7 +161,7 @@ config_item *game_configure(game_params *params) return ret; } -game_params *custom_params(config_item *cfg) +static game_params *custom_params(config_item *cfg) { game_params *ret = snew(game_params); @@ -175,7 +171,7 @@ game_params *custom_params(config_item *cfg) return ret; } -char *validate_params(game_params *params) +static char *validate_params(game_params *params) { if (params->w <= 0 && params->h <= 0) return "Width and height must both be greater than zero"; @@ -285,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)]; } @@ -307,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); } } @@ -315,23 +320,23 @@ static void generate(random_state *rs, int w, int h, unsigned char *retgrid) sfree(fgrid); } -int compute_rowdata(int *ret, unsigned char *start, int len, int step) +static int compute_rowdata(int *ret, unsigned char *start, int len, int step) { int i, n; n = 0; for (i = 0; i < len; i++) { - if (start[i*step] == GRID_UNKNOWN) - return -1; - if (start[i*step] == GRID_FULL) { int runlen = 1; - while (i+runlen < len && start[(i+runlen)*step]) + while (i+runlen < len && start[(i+runlen)*step] == GRID_FULL) runlen++; ret[n++] = runlen; i += runlen; } + + if (i < len && start[i*step] == GRID_UNKNOWN) + return -1; } return n; @@ -412,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 { @@ -443,7 +476,7 @@ static unsigned char *generate_soluble(random_state *rs, int w, int h) return grid; } -char *new_game_seed(game_params *params, random_state *rs) +static char *new_game_seed(game_params *params, random_state *rs) { unsigned char *grid; int i, j, max, rowlen, *rowdata; @@ -507,7 +540,7 @@ char *new_game_seed(game_params *params, random_state *rs) return seed; } -char *validate_seed(game_params *params, char *seed) +static char *validate_seed(game_params *params, char *seed) { int i, n, rowspace; char *p; @@ -549,7 +582,7 @@ char *validate_seed(game_params *params, char *seed) return NULL; } -game_state *new_game(game_params *params, char *seed) +static game_state *new_game(game_params *params, char *seed) { int i; char *p; @@ -584,7 +617,7 @@ game_state *new_game(game_params *params, char *seed) return state; } -game_state *dup_game(game_state *state) +static game_state *dup_game(game_state *state) { game_state *ret = snew(game_state); @@ -607,7 +640,7 @@ game_state *dup_game(game_state *state) return ret; } -void free_game(game_state *state) +static void free_game(game_state *state) { sfree(state->rowdata); sfree(state->rowlen); @@ -624,7 +657,7 @@ struct game_ui { int drag, release, state; }; -game_ui *new_ui(game_state *state) +static game_ui *new_ui(game_state *state) { game_ui *ret; @@ -634,12 +667,13 @@ game_ui *new_ui(game_state *state) return ret; } -void free_ui(game_ui *ui) +static void free_ui(game_ui *ui) { sfree(ui); } -game_state *make_move(game_state *from, game_ui *ui, int x, int y, int button) +static game_state *make_move(game_state *from, game_ui *ui, + int x, int y, int button) { game_state *ret; @@ -775,13 +809,13 @@ struct game_drawstate { unsigned char *visible; }; -void game_size(game_params *params, int *x, int *y) +static void game_size(game_params *params, int *x, int *y) { *x = SIZE(params->w); *y = SIZE(params->h); } -float *game_colours(frontend *fe, game_state *state, int *ncolours) +static float *game_colours(frontend *fe, game_state *state, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); @@ -807,7 +841,7 @@ float *game_colours(frontend *fe, game_state *state, int *ncolours) return ret; } -game_drawstate *game_new_drawstate(game_state *state) +static game_drawstate *game_new_drawstate(game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); @@ -820,7 +854,7 @@ game_drawstate *game_new_drawstate(game_state *state) return ds; } -void game_free_drawstate(game_drawstate *ds) +static void game_free_drawstate(game_drawstate *ds) { sfree(ds->visible); sfree(ds); @@ -848,7 +882,7 @@ static void grid_square(frontend *fe, game_drawstate *ds, TILE_SIZE, TILE_SIZE); } -void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, +static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, game_state *state, int dir, game_ui *ui, float animtime, float flashtime) { @@ -906,7 +940,7 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, * Draw the grid outline. */ draw_rect(fe, TOCOORD(ds->w, 0) - 1, TOCOORD(ds->h, 0) - 1, - ds->w * TILE_SIZE + 2, ds->h * TILE_SIZE + 2, + ds->w * TILE_SIZE + 3, ds->h * TILE_SIZE + 3, COL_GRID); ds->started = TRUE; @@ -957,19 +991,54 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, } } -float game_anim_length(game_state *oldstate, game_state *newstate, int dir) +static float game_anim_length(game_state *oldstate, + game_state *newstate, int dir) { return 0.0F; } -float game_flash_length(game_state *oldstate, game_state *newstate, int dir) +static float game_flash_length(game_state *oldstate, + game_state *newstate, int dir) { if (!oldstate->completed && newstate->completed) return FLASH_TIME; return 0.0F; } -int game_wants_statusbar(void) +static int game_wants_statusbar(void) { return FALSE; } + +#ifdef COMBINED +#define thegame pattern +#endif + +const struct game thegame = { + "Pattern", "games.pattern", TRUE, + default_params, + game_fetch_preset, + decode_params, + encode_params, + free_params, + dup_params, + game_configure, + custom_params, + validate_params, + new_game_seed, + validate_seed, + new_game, + dup_game, + free_game, + new_ui, + free_ui, + make_move, + game_size, + game_colours, + game_new_drawstate, + game_free_drawstate, + game_redraw, + game_anim_length, + game_flash_length, + game_wants_statusbar, +};