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/singles.c | 111 ++++++++++++++++++++++++------------- 1 file changed, 73 insertions(+), 38 deletions(-) (limited to 'apps/plugins/puzzles/src/singles.c') diff --git a/apps/plugins/puzzles/src/singles.c b/apps/plugins/puzzles/src/singles.c index 202ce08b20..07db8361ae 100644 --- a/apps/plugins/puzzles/src/singles.c +++ b/apps/plugins/puzzles/src/singles.c @@ -58,13 +58,17 @@ #include #include #include -#include +#ifdef NO_TGMATH_H +# include +#else +# include +#endif #include "puzzles.h" #include "latin.h" #ifdef STANDALONE_SOLVER -bool verbose = false; +static bool verbose = false; #endif #define PREFERRED_TILE_SIZE 32 @@ -82,7 +86,7 @@ bool verbose = false; #define FLASH_TIME 0.7F enum { - COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT, + COL_BACKGROUND, COL_UNUSED1, COL_LOWLIGHT, COL_BLACK, COL_WHITE, COL_BLACKNUM, COL_GRID, COL_CURSOR, COL_ERROR, NCOLOURS @@ -254,7 +258,7 @@ static game_params *custom_params(const config_item *cfg) static const char *validate_params(const game_params *params, bool full) { if (params->w < 2 || params->h < 2) - return "Width and neight must be at least two"; + return "Width and height must be at least two"; if (params->w > 10+26+26 || params->h > 10+26+26) return "Puzzle is too large"; if (full) { @@ -417,7 +421,7 @@ static void debug_state(const char *desc, game_state *state) { sfree(dbg); } -static void connect_if_same(game_state *state, int *dsf, int i1, int i2) +static void connect_if_same(game_state *state, DSF *dsf, int i1, int i2) { int c1, c2; @@ -429,13 +433,13 @@ static void connect_if_same(game_state *state, int *dsf, int i1, int i2) dsf_merge(dsf, c1, c2); } -static void connect_dsf(game_state *state, int *dsf) +static void connect_dsf(game_state *state, DSF *dsf) { int x, y, i; /* Construct a dsf array for connected blocks; connections * tracked to right and down. */ - dsf_init(dsf, state->n); + dsf_reinit(dsf); for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { i = y*state->w + x; @@ -494,7 +498,7 @@ static int check_rowcol(game_state *state, int starti, int di, int sz, unsigned static bool check_complete(game_state *state, unsigned flags) { - int *dsf = snewn(state->n, int); + DSF *dsf = dsf_new(state->n); int x, y, i, error = 0, nwhite, w = state->w, h = state->h; if (flags & CC_MARK_ERRORS) { @@ -543,7 +547,7 @@ static bool check_complete(game_state *state, unsigned flags) int size = dsf_size(dsf, i); if (largest < size) { largest = size; - canonical = i; + canonical = dsf_canonify(dsf, i); } } @@ -558,7 +562,7 @@ static bool check_complete(game_state *state, unsigned flags) } } - sfree(dsf); + dsf_free(dsf); return !(error > 0); } @@ -1304,9 +1308,10 @@ found: return j; } -static char *new_game_desc(const game_params *params, random_state *rs, +static char *new_game_desc(const game_params *params_orig, random_state *rs, char **aux, bool interactive) { + game_params *params = dup_params(params_orig); game_state *state = blank_game(params->w, params->h); game_state *tosolve = blank_game(params->w, params->h); int i, j, *scratch, *rownums, *colnums, x, y, ntries; @@ -1315,6 +1320,12 @@ static char *new_game_desc(const game_params *params, random_state *rs, digit *latin; struct solver_state *ss = solver_state_new(state); + /* Downgrade difficulty to Easy for puzzles so tiny that they aren't + * possible to generate at Tricky. These are 2x2, 2x3 and 3x3, i.e. + * any puzzle that doesn't have one dimension at least 4. */ + if ((w < 4 || h < 4) && params->diff > DIFF_EASY) + params->diff = DIFF_EASY; + scratch = snewn(state->n, int); rownums = snewn(h*o, int); colnums = snewn(w*o, int); @@ -1408,6 +1419,7 @@ randomise: free_game(tosolve); free_game(state); + free_params(params); solver_state_free(ss); sfree(scratch); sfree(rownums); @@ -1446,24 +1458,37 @@ static game_ui *new_ui(const game_state *state) game_ui *ui = snew(game_ui); ui->cx = ui->cy = 0; - ui->cshow = false; + ui->cshow = getenv_bool("PUZZLES_SHOW_CURSOR", false); ui->show_black_nums = false; return ui; } -static void free_ui(game_ui *ui) +static config_item *get_prefs(game_ui *ui) { - sfree(ui); + config_item *ret; + + ret = snewn(2, config_item); + + ret[0].name = "Show numbers on black squares"; + ret[0].kw = "show-black-nums"; + ret[0].type = C_BOOLEAN; + ret[0].u.boolean.bval = ui->show_black_nums; + + ret[1].name = NULL; + ret[1].type = C_END; + + return ret; } -static char *encode_ui(const game_ui *ui) +static void set_prefs(game_ui *ui, const config_item *cfg) { - return NULL; + ui->show_black_nums = cfg[0].u.boolean.bval; } -static void decode_ui(game_ui *ui, const char *encoding) +static void free_ui(game_ui *ui) { + sfree(ui); } static void game_changed_state(game_ui *ui, const game_state *oldstate, @@ -1473,6 +1498,18 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate, ui->cshow = false; } +static const char *current_key_label(const game_ui *ui, + const game_state *state, int button) +{ + if (IS_CURSOR_SELECT(button) && ui->cshow) { + unsigned int f = state->flags[ui->cy * state->w + ui->cx]; + if (f & F_BLACK) return "Restore"; + if (f & F_CIRCLE) return "Remove"; + return button == CURSOR_SELECT ? "Black" : "Circle"; + } + return ""; +} + #define DS_BLACK 0x1 #define DS_CIRCLE 0x2 #define DS_CURSOR 0x4 @@ -1497,11 +1534,10 @@ static char *interpret_move(const game_state *state, game_ui *ui, int i, x = FROMCOORD(mx), y = FROMCOORD(my); enum { NONE, TOGGLE_BLACK, TOGGLE_CIRCLE, UI } action = NONE; - if (IS_CURSOR_MOVE(button)) { - move_cursor(button, &ui->cx, &ui->cy, state->w, state->h, true); - ui->cshow = true; - action = UI; - } else if (IS_CURSOR_SELECT(button)) { + if (IS_CURSOR_MOVE(button)) + return move_cursor(button, &ui->cx, &ui->cy, state->w, state->h, true, + &ui->cshow); + else if (IS_CURSOR_SELECT(button)) { x = ui->cx; y = ui->cy; if (!ui->cshow) { action = UI; @@ -1519,14 +1555,14 @@ static char *interpret_move(const game_state *state, game_ui *ui, } if (!INGRID(state, x, y)) { ui->show_black_nums = !ui->show_black_nums; - action = UI; /* this wants to be a per-game option. */ + action = UI; } else if (button == LEFT_BUTTON) { action = TOGGLE_BLACK; } else if (button == RIGHT_BUTTON) { action = TOGGLE_CIRCLE; } } - if (action == UI) return UI_UPDATE; + if (action == UI) return MOVE_UI_UPDATE; if (action == TOGGLE_BLACK || action == TOGGLE_CIRCLE) { i = y * state->w + x; @@ -1587,7 +1623,7 @@ badmove: */ 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; @@ -1608,12 +1644,13 @@ static float *game_colours(frontend *fe, int *ncolours) float *ret = snewn(3 * NCOLOURS, float); int i; - game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); + game_mkhighlight(fe, ret, COL_BACKGROUND, -1, COL_LOWLIGHT); for (i = 0; i < 3; i++) { ret[COL_BLACK * 3 + i] = 0.0F; ret[COL_BLACKNUM * 3 + i] = 0.4F; ret[COL_WHITE * 3 + i] = 1.0F; ret[COL_GRID * 3 + i] = ret[COL_LOWLIGHT * 3 + i]; + ret[COL_UNUSED1 * 3 + i] = 0.0F; /* To placate an assertion. */ } ret[COL_CURSOR * 3 + 0] = 0.2F; ret[COL_CURSOR * 3 + 1] = 0.8F; @@ -1708,7 +1745,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds, if (!ds->started) { int wsz = TILE_SIZE * state->w + 2 * BORDER; int hsz = TILE_SIZE * state->h + 2 * BORDER; - draw_rect(dr, 0, 0, wsz, hsz, COL_BACKGROUND); draw_rect_outline(dr, COORD(0)-1, COORD(0)-1, TILE_SIZE * state->w + 2, TILE_SIZE * state->h + 2, COL_GRID); @@ -1776,22 +1812,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; /* 8mm squares by default. */ - game_compute_size(params, 800, &pw, &ph); + game_compute_size(params, 800, 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 paper = print_mono_colour(dr, 1); @@ -1848,12 +1881,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 */ NULL, /* game_request_keys */ game_changed_state, + current_key_label, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, @@ -1867,7 +1902,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, /* flags */ }; -- cgit v1.2.3