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/unequal.c | 193 +++++++++++++++++++++++++------------ 1 file changed, 129 insertions(+), 64 deletions(-) (limited to 'apps/plugins/puzzles/src/unequal.c') diff --git a/apps/plugins/puzzles/src/unequal.c b/apps/plugins/puzzles/src/unequal.c index 153954e510..ab32e4ab79 100644 --- a/apps/plugins/puzzles/src/unequal.c +++ b/apps/plugins/puzzles/src/unequal.c @@ -21,7 +21,11 @@ #include #include #include -#include +#ifdef NO_TGMATH_H +# include +#else +# include +#endif #include "puzzles.h" #include "latin.h" /* contains typedef for digit */ @@ -84,6 +88,7 @@ struct game_params { #define ADJ_TO_SPENT(x) ((x) << 9) #define F_ERROR_MASK (F_ERROR|F_ERROR_UP|F_ERROR_RIGHT|F_ERROR_DOWN|F_ERROR_LEFT) +#define F_SPENT_MASK (F_SPENT_UP|F_SPENT_RIGHT|F_SPENT_DOWN|F_SPENT_LEFT) struct game_state { int order; @@ -890,13 +895,14 @@ static int solver_state(game_state *state, int maxdiff) struct latin_solver solver; int diff; - latin_solver_alloc(&solver, state->nums, state->order); - - diff = latin_solver_main(&solver, maxdiff, - DIFF_LATIN, DIFF_SET, DIFF_EXTREME, - DIFF_EXTREME, DIFF_RECURSIVE, - unequal_solvers, unequal_valid, ctx, - clone_ctx, free_ctx); + if (latin_solver_alloc(&solver, state->nums, state->order)) + diff = latin_solver_main(&solver, maxdiff, + DIFF_LATIN, DIFF_SET, DIFF_EXTREME, + DIFF_EXTREME, DIFF_RECURSIVE, + unequal_solvers, unequal_valid, ctx, + clone_ctx, free_ctx); + else + diff = DIFF_IMPOSSIBLE; memcpy(state->hints, solver.cube, state->order*state->order*state->order); @@ -1073,7 +1079,7 @@ static int gg_best_clue(game_state *state, int *scratch, digit *latin) } #ifdef STANDALONE_SOLVER -int maxtries; +static int maxtries; #define MAXTRIES maxtries #else #define MAXTRIES 50 @@ -1430,6 +1436,17 @@ static char *solve_game(const game_state *state, const game_state *currstate, struct game_ui { int hx, hy; /* as for solo.c, highlight pos */ bool hshow, hpencil, hcursor; /* show state, type, and ?cursor. */ + + /* + * 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) @@ -1438,8 +1455,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; } @@ -1449,13 +1467,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, @@ -1470,6 +1501,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 && IS_CURSOR_SELECT(button)) + return ui->hpencil ? "Ink" : "Pencil"; + return ""; +} + struct game_drawstate { int tilesize, order; bool started; @@ -1491,7 +1530,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, char buf[80]; bool shift_or_control = button & (MOD_SHFT | MOD_CTRL); - button &= ~MOD_MASK; + button = STRIP_BUTTON_MODIFIERS(button); if (x >= 0 && x < ds->order && y >= 0 && y < ds->order && IS_MOUSE_DOWN(button)) { if (oy - COORD(y) > TILE_SIZE && ox - COORD(x) > TILE_SIZE) @@ -1527,7 +1566,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, ui->hshow = true; } ui->hcursor = false; - return UI_UPDATE; + return MOVE_UI_UPDATE; } if (button == RIGHT_BUTTON) { /* pencil highlighting for non-filled squares */ @@ -1541,7 +1580,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, ui->hshow = true; } ui->hcursor = false; - return UI_UPDATE; + return MOVE_UI_UPDATE; } } @@ -1549,7 +1588,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, if (shift_or_control) { int nx = ui->hx, ny = ui->hy, i; bool self; - move_cursor(button, &nx, &ny, ds->order, ds->order, false); + move_cursor(button, &nx, &ny, ds->order, ds->order, false, NULL); ui->hshow = true; ui->hcursor = true; @@ -1557,12 +1596,12 @@ static char *interpret_move(const game_state *state, game_ui *ui, ny != ui->hy + adjthan[i].dy); ++i); if (i == 4) - return UI_UPDATE; /* invalid direction, i.e. out of + return MOVE_UI_UPDATE; /* invalid direction, i.e. out of * the board */ if (!(GRID(state, flags, ui->hx, ui->hy) & adjthan[i].f || GRID(state, flags, nx, ny ) & adjthan[i].fo)) - return UI_UPDATE; /* no clue to toggle */ + return MOVE_UI_UPDATE; /* no clue to toggle */ if (state->mode == MODE_ADJACENT) self = (adjthan[i].dx >= 0 && adjthan[i].dy >= 0); @@ -1570,24 +1609,23 @@ static char *interpret_move(const game_state *state, game_ui *ui, self = (GRID(state, flags, ui->hx, ui->hy) & adjthan[i].f); if (self) - sprintf(buf, "F%d,%d,%d", ui->hx, ui->hy, + sprintf(buf, "F%d,%d,%u", ui->hx, ui->hy, ADJ_TO_SPENT(adjthan[i].f)); else - sprintf(buf, "F%d,%d,%d", nx, ny, + sprintf(buf, "F%d,%d,%u", nx, ny, ADJ_TO_SPENT(adjthan[i].fo)); return dupstr(buf); } else { - move_cursor(button, &ui->hx, &ui->hy, ds->order, ds->order, false); - ui->hshow = true; ui->hcursor = true; - return UI_UPDATE; + return move_cursor(button, &ui->hx, &ui->hy, ds->order, ds->order, + false, &ui->hshow); } } if (ui->hshow && IS_CURSOR_SELECT(button)) { ui->hpencil = !ui->hpencil; ui->hcursor = true; - return UI_UPDATE; + return MOVE_UI_UPDATE; } n = c2n(button, state->order); @@ -1604,11 +1642,37 @@ static char *interpret_move(const game_state *state, game_ui *ui, if (ui->hpencil && GRID(state, nums, ui->hx, ui->hy) > 0) return NULL; /* can't change hints on filled square (!) */ + /* + * 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) && + GRID(state, nums, ui->hx, ui->hy) == n) { + bool anypencil = false; + int i; + for (i = 0; i < state->order; i++) + anypencil = anypencil || HINT(state, ui->hx, ui->hy, i); + if (!anypencil) { + /* ... 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); } @@ -1624,7 +1688,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, static game_state *execute_move(const game_state *state, const char *move) { game_state *ret = NULL; - int x, y, n, i, rc; + int x, y, n, i; debug(("execute_move: %s", move)); @@ -1649,7 +1713,7 @@ static game_state *execute_move(const game_state *state, const char *move) const char *p; ret = dup_game(state); - ret->completed = ret->cheated = true; + ret->cheated = true; p = move+1; for (i = 0; i < state->order*state->order; i++) { @@ -1660,8 +1724,8 @@ static game_state *execute_move(const game_state *state, const char *move) p++; } if (*p) goto badmove; - rc = check_complete(ret->nums, ret, true); - assert(rc > 0); + if (!ret->completed && check_complete(ret->nums, ret, true) > 0) + ret->completed = true; return ret; } else if (move[0] == 'M') { ret = dup_game(state); @@ -1678,7 +1742,8 @@ static game_state *execute_move(const game_state *state, const char *move) check_complete(ret->nums, ret, true); return ret; } else if (move[0] == 'F' && sscanf(move+1, "%d,%d,%d", &x, &y, &n) == 3 && - x >= 0 && x < state->order && y >= 0 && y < state->order) { + x >= 0 && x < state->order && y >= 0 && y < state->order && + (n & ~F_SPENT_MASK) == 0) { ret = dup_game(state); GRID(ret, flags, x, y) ^= n; return ret; @@ -1696,7 +1761,7 @@ badmove: #define DRAW_SIZE (TILE_SIZE*ds->order + GAP_SIZE*(ds->order-1) + BORDER*2) 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, order; } ads, *ds = &ads; @@ -1779,18 +1844,18 @@ static void draw_gt(drawing *dr, int ox, int oy, { int coords[12]; int xdx = (dx1+dx2 ? 0 : 1), xdy = (dx1+dx2 ? 1 : 0); - coords[0] = ox + xdx + dx1; - coords[1] = oy + xdy + dy1; - coords[2] = ox + xdx + dx1 + dx2; - coords[3] = oy + xdy + dy1 + dy2; - coords[4] = ox - xdx + dx1 + dx2; - coords[5] = oy - xdy + dy1 + dy2; - coords[6] = ox - xdx + dx1; - coords[7] = oy - xdy + dy1; - coords[8] = ox - xdx; - coords[9] = oy - xdy; - coords[10] = ox + xdx; - coords[11] = oy + xdy; + coords[0] = ox + xdx; + coords[1] = oy + xdy; + coords[2] = ox + xdx + dx1; + coords[3] = oy + xdy + dy1; + coords[4] = ox + xdx + dx1 + dx2; + coords[5] = oy + xdy + dy1 + dy2; + coords[6] = ox - xdx + dx1 + dx2; + coords[7] = oy - xdy + dy1 + dy2; + coords[8] = ox - xdx + dx1; + coords[9] = oy - xdy + dy1; + coords[10] = ox - xdx; + coords[11] = oy - xdy; draw_polygon(dr, coords, 6, col, col); } @@ -2059,22 +2124,19 @@ 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) -{ - 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; /* 10mm squares by default, roughly the same as Grauniad. */ - game_compute_size(params, 1000, &pw, &ph); + game_compute_size(params, 1000, ui, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } -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 ink = print_mono_colour(dr, 0); int x, y, o = state->order, ox, oy, n; @@ -2133,12 +2195,14 @@ const struct game thegame = { free_game, true, solve_game, true, game_can_format_as_text_now, game_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_TILE_SIZE, game_compute_size, game_set_size, @@ -2152,7 +2216,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 */ }; @@ -2165,7 +2229,7 @@ const struct game thegame = { #include #include -const char *quis = NULL; +static const char *quis = NULL; #if 0 /* currently unused */ @@ -2233,13 +2297,14 @@ static int solve(game_params *p, char *desc, int debug) solver_show_working = debug; game_debug(state); - latin_solver_alloc(&solver, state->nums, state->order); - - diff = latin_solver_main(&solver, DIFF_RECURSIVE, - DIFF_LATIN, DIFF_SET, DIFF_EXTREME, - DIFF_EXTREME, DIFF_RECURSIVE, - unequal_solvers, unequal_valid, ctx, - clone_ctx, free_ctx); + if (latin_solver_alloc(&solver, state->nums, state->order)) + diff = latin_solver_main(&solver, DIFF_RECURSIVE, + DIFF_LATIN, DIFF_SET, DIFF_EXTREME, + DIFF_EXTREME, DIFF_RECURSIVE, + unequal_solvers, unequal_valid, ctx, + clone_ctx, free_ctx); + else + diff = DIFF_IMPOSSIBLE; free_ctx(ctx); -- cgit v1.2.3