X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/07dfb697bb30781c963b11eb00c4951bb5db6a7d..0a6892dbcbd8ecb9be7e88a0368926fe521ae479:/twiddle.c diff --git a/twiddle.c b/twiddle.c index b554879..66ce4d1 100644 --- a/twiddle.c +++ b/twiddle.c @@ -14,7 +14,8 @@ #include "puzzles.h" -#define TILE_SIZE 48 +#define PREFERRED_TILE_SIZE 48 +#define TILE_SIZE (ds->tilesize) #define BORDER (TILE_SIZE / 2) #define HIGHLIGHT_WIDTH (TILE_SIZE / 20) #define COORD(x) ( (x) * TILE_SIZE + BORDER ) @@ -362,7 +363,14 @@ static char *new_game_desc(game_params *params, random_state *rs, */ oldtotal = prevmoves[y*rw+x]; newtotal = oldtotal + r; - } while (abs(newtotal) < abs(oldtotal) || abs(newtotal) > 2); + + /* + * Special case here for w==h==n, in which case + * there is actually no way to _avoid_ all moves + * repeating or undoing previous ones. + */ + } while ((w != n || h != n) && + (abs(newtotal) < abs(oldtotal) || abs(newtotal) > 2)); do_rotate(grid, w, h, n, params->orientable, x, y, r); @@ -538,26 +546,10 @@ static int compare_int(const void *av, const void *bv) return 0; } -static game_state *solve_game(game_state *state, game_aux_info *aux, - char **error) +static char *solve_game(game_state *state, game_state *currstate, + game_aux_info *aux, char **error) { - game_state *ret = dup_game(state); - int i; - - /* - * Simply replace the grid with a solved one. For this game, - * this isn't a useful operation for actually telling the user - * what they should have done, but it is useful for - * conveniently being able to get hold of a clean state from - * which to practise manoeuvres. - */ - qsort(ret->grid, ret->w*ret->h, sizeof(int), compare_int); - for (i = 0; i < ret->w*ret->h; i++) - ret->grid[i] &= ~3; - ret->used_solve = ret->just_used_solve = TRUE; - ret->completed = ret->movecount = 1; - - return ret; + return dupstr("S"); } static char *game_text_format(game_state *state) @@ -621,11 +613,18 @@ static void game_changed_state(game_ui *ui, game_state *oldstate, { } -static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, - int x, int y, int button) +struct game_drawstate { + int started; + int w, h, bgcolour; + int *grid; + int tilesize; +}; + +static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds, + int x, int y, int button) { - int w = from->w, h = from->h, n = from->n, wh = w*h; - game_state *ret; + int w = state->w, h = state->h, n = state->n /* , wh = w*h */; + char buf[80]; int dir; button = button & (~MOD_MASK | MOD_NUM_KEYPAD); @@ -683,8 +682,43 @@ static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, } /* - * This is a valid move. Make it. + * If we reach here, we have a valid move. */ + sprintf(buf, "M%d,%d,%d", x, y, dir); + return dupstr(buf); +} + +static game_state *execute_move(game_state *from, char *move) +{ + game_state *ret; + int w = from->w, h = from->h, n = from->n, wh = w*h; + int x, y, dir; + + if (!strcmp(move, "S")) { + int i; + ret = dup_game(from); + + /* + * Simply replace the grid with a solved one. For this game, + * this isn't a useful operation for actually telling the user + * what they should have done, but it is useful for + * conveniently being able to get hold of a clean state from + * which to practise manoeuvres. + */ + qsort(ret->grid, ret->w*ret->h, sizeof(int), compare_int); + for (i = 0; i < ret->w*ret->h; i++) + ret->grid[i] &= ~3; + ret->used_solve = ret->just_used_solve = TRUE; + ret->completed = ret->movecount = 1; + + return ret; + } + + if (move[0] != 'M' || + sscanf(move+1, "%d,%d,%d", &x, &y, &dir) != 3 || + x < 0 || y < 0 || x > from->w - n || y > from->h - n) + return NULL; /* can't parse this move string */ + ret = dup_game(from); ret->just_used_solve = FALSE; /* zero this in a hurry */ ret->movecount++; @@ -706,14 +740,23 @@ static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, * Drawing routines. */ -struct game_drawstate { - int started; - int w, h, bgcolour; - int *grid; -}; - -static void game_size(game_params *params, int *x, int *y) +static void game_size(game_params *params, game_drawstate *ds, + int *x, int *y, int expand) { + int tsx, tsy, ts; + /* + * Each window dimension equals the tile size times one more + * than the grid dimension (the border is half the width of the + * tiles). + */ + tsx = *x / (params->w + 1); + tsy = *y / (params->h + 1); + ts = min(tsx, tsy); + if (expand) + ds->tilesize = ts; + else + ds->tilesize = min(ts, PREFERRED_TILE_SIZE); + *x = TILE_SIZE * params->w + 2 * BORDER; *y = TILE_SIZE * params->h + 2 * BORDER; } @@ -761,6 +804,7 @@ static game_drawstate *game_new_drawstate(game_state *state) ds->h = state->h; ds->bgcolour = COL_BACKGROUND; ds->grid = snewn(ds->w*ds->h, int); + ds->tilesize = 0; /* haven't decided yet */ for (i = 0; i < ds->w*ds->h; i++) ds->grid[i] = -1; @@ -794,8 +838,9 @@ static void rotate(int *xy, struct rotation *rot) } } -static void draw_tile(frontend *fe, game_state *state, int x, int y, - int tile, int flash_colour, struct rotation *rot) +static void draw_tile(frontend *fe, game_drawstate *ds, game_state *state, + int x, int y, int tile, int flash_colour, + struct rotation *rot) { int coords[8]; char str[40]; @@ -1110,7 +1155,7 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, ds->grid[i] != t || ds->grid[i] == -1 || t == -1) { int x = COORD(tx), y = COORD(ty); - draw_tile(fe, state, x, y, state->grid[i], bgcolour, rot); + draw_tile(fe, ds, state, x, y, state->grid[i], bgcolour, rot); ds->grid[i] = t; } } @@ -1180,7 +1225,8 @@ const struct game thegame = { new_ui, free_ui, game_changed_state, - make_move, + interpret_move, + execute_move, game_size, game_colours, game_new_drawstate,