From 09aa8de52cb962f1ceebfb1fd44f2c54a924fc5c Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Mon, 22 Jul 2024 21:43:25 -0400 Subject: puzzles: resync with upstream This brings the puzzles source in sync with Simon's branch, commit fd304c5 (from March 2024), with some added Rockbox-specific compatibility changes: https://www.franklinwei.com/git/puzzles/commit/?h=rockbox-devel&id=516830d9d76bdfe64fe5ccf2a9b59c33f5c7c078 There are quite a lot of backend changes, including a new "Mosaic" puzzle. In addition, some new frontend changes were necessary: - New "Preferences" menu to access the user preferences system. - Enabled spacebar input for several games. Change-Id: I94c7df674089c92f32d5f07025f6a1059068af1e --- apps/plugins/puzzles/src/keen.c | 250 ++++++++++++++++++++++++---------------- 1 file changed, 148 insertions(+), 102 deletions(-) (limited to 'apps/plugins/puzzles/src/keen.c') diff --git a/apps/plugins/puzzles/src/keen.c b/apps/plugins/puzzles/src/keen.c index 6b9610dbcd..7e2f71c8f9 100644 --- a/apps/plugins/puzzles/src/keen.c +++ b/apps/plugins/puzzles/src/keen.c @@ -8,7 +8,11 @@ #include #include #include -#include +#ifdef NO_TGMATH_H +# include +#else +# include +#endif #include "puzzles.h" #include "latin.h" @@ -69,7 +73,7 @@ struct game_params { struct clues { int refcount; int w; - int *dsf; + DSF *dsf; long *clues; }; @@ -677,7 +681,7 @@ static bool keen_valid(struct latin_solver *solver, void *vctx) return true; } -static int solver(int w, int *dsf, long *clues, digit *soln, int maxdiff) +static int solver(int w, DSF *dsf, long *clues, digit *soln, int maxdiff) { int a = w*w; struct solver_ctx ctx; @@ -704,11 +708,11 @@ static int solver(int w, int *dsf, long *clues, digit *soln, int maxdiff) ctx.clues = snewn(ctx.nboxes, long); ctx.whichbox = snewn(a, int); for (n = m = i = 0; i < a; i++) - if (dsf_canonify(dsf, i) == i) { + if (dsf_minimal(dsf, i) == i) { ctx.clues[n] = clues[i]; ctx.boxes[n] = m; for (j = 0; j < a; j++) - if (dsf_canonify(dsf, j) == i) { + if (dsf_minimal(dsf, j) == i) { ctx.boxlist[m++] = (j % w) * w + (j / w); /* transpose */ ctx.whichbox[ctx.boxlist[m-1]] = n; } @@ -740,7 +744,7 @@ static int solver(int w, int *dsf, long *clues, digit *soln, int maxdiff) * Grid generation. */ -static char *encode_block_structure(char *p, int w, int *dsf) +static char *encode_block_structure(char *p, int w, DSF *dsf) { int i, currrun = 0; char *orig, *q, *r, c; @@ -777,7 +781,7 @@ static char *encode_block_structure(char *p, int w, int *dsf) p0 = y*w+x; p1 = (y+1)*w+x; } - edge = (dsf_canonify(dsf, p0) != dsf_canonify(dsf, p1)); + edge = !dsf_equivalent(dsf, p0, p1); } if (edge) { @@ -815,13 +819,12 @@ static char *encode_block_structure(char *p, int w, int *dsf) return q; } -static const char *parse_block_structure(const char **p, int w, int *dsf) +static const char *parse_block_structure(const char **p, int w, DSF *dsf) { - int a = w*w; int pos = 0; int repc = 0, repn = 0; - dsf_init(dsf, a); + dsf_reinit(dsf); while (**p && (repn > 0 || **p != ',')) { int c; @@ -890,7 +893,8 @@ static char *new_game_desc(const game_params *params, random_state *rs, { int w = params->w, a = w*w; digit *grid, *soln; - int *order, *revorder, *singletons, *dsf; + int *order, *revorder, *singletons; + DSF *dsf; long *clues, *cluevals; int i, j, k, n, x, y, ret; int diff = params->diff; @@ -927,7 +931,7 @@ done order = snewn(a, int); revorder = snewn(a, int); singletons = snewn(a, int); - dsf = snew_dsf(a); + dsf = dsf_new_min(a); clues = snewn(a, long); cluevals = snewn(a, long); soln = snewn(a, digit); @@ -955,7 +959,7 @@ done for (i = 0; i < a; i++) singletons[i] = true; - dsf_init(dsf, a); + dsf_reinit(dsf); /* Place dominoes. */ for (i = 0; i < a; i++) { @@ -1037,11 +1041,10 @@ done * integer quotient, of course), but we rule out (or try to * avoid) some clues because they're of low quality. * - * Hence, we iterate once over the grid, stopping at the - * canonical element of every >2 block and the _non_- - * canonical element of every 2-block; the latter means that - * we can make our decision about a 2-block in the knowledge - * of both numbers in it. + * Hence, we iterate once over the grid, stopping at the first + * element in every >2 block and the _last_ element of every + * 2-block; the latter means that we can make our decision + * about a 2-block in the knowledge of both numbers in it. * * We reuse the 'singletons' array (finished with in the * above loop) to hold information about which blocks are @@ -1055,7 +1058,7 @@ done for (i = 0; i < a; i++) { singletons[i] = 0; - j = dsf_canonify(dsf, i); + j = dsf_minimal(dsf, i); k = dsf_size(dsf, j); if (params->multiplication_only) singletons[j] = F_MUL; @@ -1178,7 +1181,7 @@ done * Having chosen the clue types, calculate the clue values. */ for (i = 0; i < a; i++) { - j = dsf_canonify(dsf, i); + j = dsf_minimal(dsf, i); if (j == i) { cluevals[j] = grid[i]; } else { @@ -1206,7 +1209,7 @@ done } for (i = 0; i < a; i++) { - j = dsf_canonify(dsf, i); + j = dsf_minimal(dsf, i); if (j == i) { clues[j] |= cluevals[j]; } @@ -1252,7 +1255,7 @@ done p = encode_block_structure(p, w, dsf); *p++ = ','; for (i = 0; i < a; i++) { - j = dsf_canonify(dsf, i); + j = dsf_minimal(dsf, i); if (j == i) { switch (clues[j] & CMASK) { case C_ADD: *p++ = 'a'; break; @@ -1280,7 +1283,7 @@ done sfree(order); sfree(revorder); sfree(singletons); - sfree(dsf); + dsf_free(dsf); sfree(clues); sfree(cluevals); sfree(soln); @@ -1295,7 +1298,7 @@ done static const char *validate_desc(const game_params *params, const char *desc) { int w = params->w, a = w*w; - int *dsf; + DSF *dsf; const char *ret; const char *p = desc; int i; @@ -1303,15 +1306,17 @@ static const char *validate_desc(const game_params *params, const char *desc) /* * Verify that the block structure makes sense. */ - dsf = snew_dsf(a); + dsf = dsf_new_min(a); ret = parse_block_structure(&p, w, dsf); if (ret) { - sfree(dsf); + dsf_free(dsf); return ret; } - if (*p != ',') + if (*p != ',') { + dsf_free(dsf); return "Expected ',' after block structure description"; + } p++; /* @@ -1319,21 +1324,26 @@ static const char *validate_desc(const game_params *params, const char *desc) * and DIV clues don't apply to blocks of the wrong size. */ for (i = 0; i < a; i++) { - if (dsf_canonify(dsf, i) == i) { + if (dsf_minimal(dsf, i) == i) { if (*p == 'a' || *p == 'm') { /* these clues need no validation */ } else if (*p == 'd' || *p == 's') { - if (dsf_size(dsf, i) != 2) + if (dsf_size(dsf, i) != 2) { + dsf_free(dsf); return "Subtraction and division blocks must have area 2"; + } } else if (!*p) { + dsf_free(dsf); return "Too few clues for block structure"; } else { + dsf_free(dsf); return "Unrecognised clue type"; } p++; while (*p && isdigit((unsigned char)*p)) p++; } } + dsf_free(dsf); if (*p) return "Too many clues for block structure"; @@ -1373,7 +1383,7 @@ static game_state *new_game(midend *me, const game_params *params, state->clues = snew(struct clues); state->clues->refcount = 1; state->clues->w = w; - state->clues->dsf = snew_dsf(a); + state->clues->dsf = dsf_new_min(a); parse_block_structure(&p, w, state->clues->dsf); assert(*p == ','); @@ -1381,7 +1391,7 @@ static game_state *new_game(midend *me, const game_params *params, state->clues->clues = snewn(a, long); for (i = 0; i < a; i++) { - if (dsf_canonify(state->clues->dsf, i) == i) { + if (dsf_minimal(state->clues->dsf, i) == i) { long clue = 0; switch (*p) { case 'a': @@ -1448,7 +1458,7 @@ static void free_game(game_state *state) sfree(state->grid); sfree(state->pencil); if (--state->clues->refcount <= 0) { - sfree(state->clues->dsf); + dsf_free(state->clues->dsf); sfree(state->clues->clues); sfree(state->clues); } @@ -1490,16 +1500,6 @@ static char *solve_game(const game_state *state, const game_state *currstate, return out; } -static bool game_can_format_as_text_now(const game_params *params) -{ - return true; -} - -static char *game_text_format(const game_state *state) -{ - return NULL; -} - struct game_ui { /* * These are the coordinates of the currently highlighted @@ -1525,6 +1525,17 @@ struct game_ui { * allowed on immutable squares. */ bool hcursor; + + /* + * User preference option: if the user right-clicks in a square + * and presses a number key to add/remove a pencil mark, do we + * hide the mouse highlight again afterwards? + * + * Historically our answer was yes. The Android port prefers no. + * There are advantages both ways, depending how much you dislike + * the highlight cluttering your view. So it's a preference. + */ + bool pencil_keep_highlight; }; static game_ui *new_ui(const game_state *state) @@ -1533,8 +1544,9 @@ static game_ui *new_ui(const game_state *state) ui->hx = ui->hy = 0; ui->hpencil = false; - ui->hshow = false; - ui->hcursor = false; + ui->hshow = ui->hcursor = getenv_bool("PUZZLES_SHOW_CURSOR", false); + + ui->pencil_keep_highlight = false; return ui; } @@ -1544,13 +1556,26 @@ static void free_ui(game_ui *ui) sfree(ui); } -static char *encode_ui(const game_ui *ui) +static config_item *get_prefs(game_ui *ui) { - return NULL; + config_item *ret; + + ret = snewn(2, config_item); + + ret[0].name = "Keep mouse highlight after changing a pencil mark"; + ret[0].kw = "pencil-keep-highlight"; + ret[0].type = C_BOOLEAN; + ret[0].u.boolean.bval = ui->pencil_keep_highlight; + + ret[1].name = NULL; + ret[1].type = C_END; + + return ret; } -static void decode_ui(game_ui *ui, const char *encoding) +static void set_prefs(game_ui *ui, const config_item *cfg) { + ui->pencil_keep_highlight = cfg[0].u.boolean.bval; } static void game_changed_state(game_ui *ui, const game_state *oldstate, @@ -1569,6 +1594,14 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate, } } +static const char *current_key_label(const game_ui *ui, + const game_state *state, int button) +{ + if (ui->hshow && (button == CURSOR_SELECT)) + return ui->hpencil ? "Ink" : "Pencil"; + return ""; +} + #define PREFERRED_TILESIZE 48 #define TILESIZE (ds->tilesize) #define BORDER (TILESIZE / 2) @@ -1613,7 +1646,7 @@ static bool check_errors(const game_state *state, long *errors) for (i = 0; i < a; i++) { long clue; - j = dsf_canonify(state->clues->dsf, i); + j = dsf_minimal(state->clues->dsf, i); if (j == i) { cluevals[i] = state->grid[i]; } else { @@ -1647,7 +1680,7 @@ static bool check_errors(const game_state *state, long *errors) } for (i = 0; i < a; i++) { - j = dsf_canonify(state->clues->dsf, i); + j = dsf_minimal(state->clues->dsf, i); if (j == i) { if ((state->clues->clues[j] & ~CMASK) != cluevals[i]) { errs = true; @@ -1709,7 +1742,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, int tx, ty; char buf[80]; - button &= ~MOD_MASK; + button = STRIP_BUTTON_MODIFIERS(button); tx = FROMCOORD(x); ty = FROMCOORD(y); @@ -1726,7 +1759,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, ui->hpencil = false; } ui->hcursor = false; - return UI_UPDATE; + return MOVE_UI_UPDATE; } if (button == RIGHT_BUTTON) { /* @@ -1746,20 +1779,18 @@ static char *interpret_move(const game_state *state, game_ui *ui, ui->hshow = false; } ui->hcursor = false; - return UI_UPDATE; + return MOVE_UI_UPDATE; } } if (IS_CURSOR_MOVE(button)) { - move_cursor(button, &ui->hx, &ui->hy, w, w, false); - ui->hshow = true; ui->hcursor = true; - return UI_UPDATE; + return move_cursor(button, &ui->hx, &ui->hy, w, w, false, &ui->hshow); } if (ui->hshow && (button == CURSOR_SELECT)) { ui->hpencil ^= 1; ui->hcursor = true; - return UI_UPDATE; + return MOVE_UI_UPDATE; } if (ui->hshow && @@ -1776,10 +1807,31 @@ static char *interpret_move(const game_state *state, game_ui *ui, if (ui->hpencil && state->grid[ui->hy*w+ui->hx]) return NULL; + /* + * If you ask to fill a square with what it already contains, + * or blank it when it's already empty, that has no effect... + */ + if ((!ui->hpencil || n == 0) && state->grid[ui->hy*w+ui->hx] == n && + state->pencil[ui->hy*w+ui->hx] == 0) { + /* ... expect to remove the cursor in mouse mode. */ + if (!ui->hcursor) { + ui->hshow = false; + return MOVE_UI_UPDATE; + } + return NULL; + } + sprintf(buf, "%c%d,%d,%d", (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); - if (!ui->hcursor) ui->hshow = false; + /* + * Hide the highlight after a keypress, if it was mouse- + * generated. Also, don't hide it if this move has changed + * pencil marks and the user preference says not to hide the + * highlight in that situation. + */ + if (!ui->hcursor && !(ui->hpencil && ui->pencil_keep_highlight)) + ui->hshow = false; return dupstr(buf); } @@ -1854,7 +1906,7 @@ static game_state *execute_move(const game_state *from, const char *move) #define SIZE(w) ((w) * TILESIZE + 2*BORDER) static void game_compute_size(const game_params *params, int tilesize, - int *x, int *y) + const game_ui *ui, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; @@ -1939,6 +1991,7 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues, int tx, ty, tw, th; int cx, cy, cw, ch; char str[64]; + bool draw_clue = dsf_minimal(clues->dsf, y*w+x) == y*w+x; tx = BORDER + x * TILESIZE + 1 + GRIDEXTRA; ty = BORDER + y * TILESIZE + 1 + GRIDEXTRA; @@ -1948,13 +2001,13 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues, cw = tw = TILESIZE-1-2*GRIDEXTRA; ch = th = TILESIZE-1-2*GRIDEXTRA; - if (x > 0 && dsf_canonify(clues->dsf, y*w+x) == dsf_canonify(clues->dsf, y*w+x-1)) + if (x > 0 && dsf_equivalent(clues->dsf, y*w+x, y*w+x-1)) cx -= GRIDEXTRA, cw += GRIDEXTRA; - if (x+1 < w && dsf_canonify(clues->dsf, y*w+x) == dsf_canonify(clues->dsf, y*w+x+1)) + if (x+1 < w && dsf_equivalent(clues->dsf, y*w+x, y*w+x+1)) cw += GRIDEXTRA; - if (y > 0 && dsf_canonify(clues->dsf, y*w+x) == dsf_canonify(clues->dsf, (y-1)*w+x)) + if (y > 0 && dsf_equivalent(clues->dsf, y*w+x, (y-1)*w+x)) cy -= GRIDEXTRA, ch += GRIDEXTRA; - if (y+1 < w && dsf_canonify(clues->dsf, y*w+x) == dsf_canonify(clues->dsf, (y+1)*w+x)) + if (y+1 < w && dsf_equivalent(clues->dsf, y*w+x, (y+1)*w+x)) ch += GRIDEXTRA; clip(dr, cx, cy, cw, ch); @@ -1979,17 +2032,21 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues, * Draw the corners of thick lines in corner-adjacent squares, * which jut into this square by one pixel. */ - if (x > 0 && y > 0 && dsf_canonify(clues->dsf, y*w+x) != dsf_canonify(clues->dsf, (y-1)*w+x-1)) - draw_rect(dr, tx-GRIDEXTRA, ty-GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); - if (x+1 < w && y > 0 && dsf_canonify(clues->dsf, y*w+x) != dsf_canonify(clues->dsf, (y-1)*w+x+1)) - draw_rect(dr, tx+TILESIZE-1-2*GRIDEXTRA, ty-GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); - if (x > 0 && y+1 < w && dsf_canonify(clues->dsf, y*w+x) != dsf_canonify(clues->dsf, (y+1)*w+x-1)) - draw_rect(dr, tx-GRIDEXTRA, ty+TILESIZE-1-2*GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); - if (x+1 < w && y+1 < w && dsf_canonify(clues->dsf, y*w+x) != dsf_canonify(clues->dsf, (y+1)*w+x+1)) - draw_rect(dr, tx+TILESIZE-1-2*GRIDEXTRA, ty+TILESIZE-1-2*GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); + if (x > 0 && y > 0 && !dsf_equivalent(clues->dsf, y*w+x, (y-1)*w+x-1)) + draw_rect(dr, tx-GRIDEXTRA, ty-GRIDEXTRA, + GRIDEXTRA, GRIDEXTRA, COL_GRID); + if (x+1 < w && y > 0 && !dsf_equivalent(clues->dsf, y*w+x, (y-1)*w+x+1)) + draw_rect(dr, tx+TILESIZE-1-2*GRIDEXTRA, ty-GRIDEXTRA, + GRIDEXTRA, GRIDEXTRA, COL_GRID); + if (x > 0 && y+1 < w && !dsf_equivalent(clues->dsf, y*w+x, (y+1)*w+x-1)) + draw_rect(dr, tx-GRIDEXTRA, ty+TILESIZE-1-2*GRIDEXTRA, + GRIDEXTRA, GRIDEXTRA, COL_GRID); + if (x+1 < w && y+1 < w && !dsf_equivalent(clues->dsf, y*w+x, (y+1)*w+x+1)) + draw_rect(dr, tx+TILESIZE-1-2*GRIDEXTRA, ty+TILESIZE-1-2*GRIDEXTRA, + GRIDEXTRA, GRIDEXTRA, COL_GRID); /* Draw the box clue. */ - if (dsf_canonify(clues->dsf, y*w+x) == y*w+x) { + if (draw_clue) { long clue = clues->clues[y*w+x]; long cluetype = clue & CMASK, clueval = clue & ~CMASK; int size = dsf_size(clues->dsf, y*w+x); @@ -2043,7 +2100,7 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues, pr = pl + TILESIZE - GRIDEXTRA; pt = ty + GRIDEXTRA; pb = pt + TILESIZE - GRIDEXTRA; - if (dsf_canonify(clues->dsf, y*w+x) == y*w+x) { + if (draw_clue) { /* * Make space for the clue text. */ @@ -2097,7 +2154,7 @@ static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues, * And move it down a bit if it's collided with some * clue text. */ - if (dsf_canonify(clues->dsf, y*w+x) == y*w+x) { + if (draw_clue) { pt = max(pt, ty + GRIDEXTRA * 3 + TILESIZE/4); } @@ -2133,14 +2190,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds, int x, y; if (!ds->started) { - /* - * The initial contents of the window are not guaranteed and - * can vary with front ends. To be on the safe side, all - * games should start by drawing a big background-colour - * rectangle covering the whole window. - */ - draw_rect(dr, 0, 0, SIZE(w), SIZE(w), COL_BACKGROUND); - /* * Big containing rectangle. */ @@ -2217,21 +2266,15 @@ static int game_status(const game_state *state) return state->completed ? +1 : 0; } -static bool game_timing_state(const game_state *state, game_ui *ui) -{ - if (state->completed) - return false; - return true; -} - -static void game_print_size(const game_params *params, float *x, float *y) +static void game_print_size(const game_params *params, const game_ui *ui, + float *x, float *y) { int pw, ph; /* * We use 9mm squares by default, like Solo. */ - game_compute_size(params, 900, &pw, &ph); + game_compute_size(params, 900, ui, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } @@ -2245,7 +2288,7 @@ static void game_print_size(const game_params *params, float *x, float *y) * single polygon. */ static void outline_block_structure(drawing *dr, game_drawstate *ds, - int w, int *dsf, int ink) + int w, DSF *dsf, int ink) { int a = w*w; int *coords; @@ -2258,7 +2301,7 @@ static void outline_block_structure(drawing *dr, game_drawstate *ds, * Iterate over all the blocks. */ for (i = 0; i < a; i++) { - if (dsf_canonify(dsf, i) != i) + if (dsf_minimal(dsf, i) != i) continue; /* @@ -2297,11 +2340,11 @@ static void outline_block_structure(drawing *dr, game_drawstate *ds, tx = x - dy + dx; ty = y + dx + dy; nin += (tx >= 0 && tx < w && ty >= 0 && ty < w && - dsf_canonify(dsf, ty*w+tx) == i); + dsf_minimal(dsf, ty*w+tx) == i); tx = x - dy; ty = y + dx; nin += (tx >= 0 && tx < w && ty >= 0 && ty < w && - dsf_canonify(dsf, ty*w+tx) == i); + dsf_minimal(dsf, ty*w+tx) == i); if (nin == 0) { /* * Turn right. @@ -2338,9 +2381,9 @@ static void outline_block_structure(drawing *dr, game_drawstate *ds, * somewhere sensible. */ assert(x >= 0 && x < w && y >= 0 && y < w && - dsf_canonify(dsf, y*w+x) == i); + dsf_minimal(dsf, y*w+x) == i); assert(x+dx < 0 || x+dx >= w || y+dy < 0 || y+dy >= w || - dsf_canonify(dsf, (y+dy)*w+(x+dx)) != i); + dsf_minimal(dsf, (y+dy)*w+(x+dx)) != i); /* * Record the point we just went past at one end of the @@ -2367,7 +2410,8 @@ static void outline_block_structure(drawing *dr, game_drawstate *ds, sfree(coords); } -static void game_print(drawing *dr, const game_state *state, int tilesize) +static void game_print(drawing *dr, const game_state *state, const game_ui *ui, + int tilesize) { int w = state->par.w; int ink = print_mono_colour(dr, 0); @@ -2413,7 +2457,7 @@ static void game_print(drawing *dr, const game_state *state, int tilesize) */ for (y = 0; y < w; y++) for (x = 0; x < w; x++) - if (dsf_canonify(state->clues->dsf, y*w+x) == y*w+x) { + if (dsf_minimal(state->clues->dsf, y*w+x) == y*w+x) { long clue = state->clues->clues[y*w+x]; long cluetype = clue & CMASK, clueval = clue & ~CMASK; int size = dsf_size(state->clues->dsf, y*w+x); @@ -2478,13 +2522,15 @@ const struct game thegame = { dup_game, free_game, true, solve_game, - false, game_can_format_as_text_now, game_text_format, + false, NULL, NULL, /* can_format_as_text_now, text_format */ + get_prefs, set_prefs, new_ui, free_ui, - encode_ui, - decode_ui, + NULL, /* encode_ui */ + NULL, /* decode_ui */ game_request_keys, game_changed_state, + current_key_label, interpret_move, execute_move, PREFERRED_TILESIZE, game_compute_size, game_set_size, @@ -2498,7 +2544,7 @@ const struct game thegame = { game_status, true, false, game_print_size, game_print, false, /* wants_statusbar */ - false, game_timing_state, + false, NULL, /* timing_state */ REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */ }; -- cgit v1.2.3