summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/src/magnets.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/puzzles/src/magnets.c')
-rw-r--r--apps/plugins/puzzles/src/magnets.c125
1 files changed, 78 insertions, 47 deletions
diff --git a/apps/plugins/puzzles/src/magnets.c b/apps/plugins/puzzles/src/magnets.c
index edbb8490ad..7cb5fbc919 100644
--- a/apps/plugins/puzzles/src/magnets.c
+++ b/apps/plugins/puzzles/src/magnets.c
@@ -36,12 +36,17 @@
36#include <string.h> 36#include <string.h>
37#include <assert.h> 37#include <assert.h>
38#include <ctype.h> 38#include <ctype.h>
39#include <math.h> 39#include <limits.h>
40#ifdef NO_TGMATH_H
41# include <math.h>
42#else
43# include <tgmath.h>
44#endif
40 45
41#include "puzzles.h" 46#include "puzzles.h"
42 47
43#ifdef STANDALONE_SOLVER 48#ifdef STANDALONE_SOLVER
44bool verbose = 0; 49static bool verbose = false;
45#endif 50#endif
46 51
47enum { 52enum {
@@ -230,8 +235,17 @@ static game_params *custom_params(const config_item *cfg)
230 235
231static const char *validate_params(const game_params *params, bool full) 236static const char *validate_params(const game_params *params, bool full)
232{ 237{
233 if (params->w < 2) return "Width must be at least one"; 238 if (params->w < 2) return "Width must be at least two";
234 if (params->h < 2) return "Height must be at least one"; 239 if (params->h < 2) return "Height must be at least two";
240 if (params->w > INT_MAX / params->h)
241 return "Width times height must not be unreasonably large";
242 if (params->diff >= DIFF_TRICKY) {
243 if (params->w < 5 && params->h < 5)
244 return "Either width or height must be at least five for Tricky";
245 } else {
246 if (params->w < 3 && params->h < 3)
247 return "Either width or height must be at least three";
248 }
235 if (params->diff < 0 || params->diff >= DIFFCOUNT) 249 if (params->diff < 0 || params->diff >= DIFFCOUNT)
236 return "Unknown difficulty level"; 250 return "Unknown difficulty level";
237 251
@@ -510,7 +524,9 @@ nextchar:
510 * (i.e. each end points to the other) */ 524 * (i.e. each end points to the other) */
511 for (idx = 0; idx < state->wh; idx++) { 525 for (idx = 0; idx < state->wh; idx++) {
512 if (state->common->dominoes[idx] < 0 || 526 if (state->common->dominoes[idx] < 0 ||
513 state->common->dominoes[idx] > state->wh || 527 state->common->dominoes[idx] >= state->wh ||
528 (state->common->dominoes[idx] % state->w != idx % state->w &&
529 state->common->dominoes[idx] / state->w != idx / state->w) ||
514 state->common->dominoes[state->common->dominoes[idx]] != idx) { 530 state->common->dominoes[state->common->dominoes[idx]] != idx) {
515 *prob = "Domino descriptions inconsistent"; 531 *prob = "Domino descriptions inconsistent";
516 goto done; 532 goto done;
@@ -541,7 +557,7 @@ static const char *validate_desc(const game_params *params, const char *desc)
541{ 557{
542 const char *prob; 558 const char *prob;
543 game_state *st = new_game_int(params, desc, &prob); 559 game_state *st = new_game_int(params, desc, &prob);
544 if (!st) return (char*)prob; 560 if (!st) return prob;
545 free_game(st); 561 free_game(st);
546 return NULL; 562 return NULL;
547} 563}
@@ -1574,6 +1590,7 @@ static int lay_dominoes(game_state *state, random_state *rs, int *scratch)
1574 } 1590 }
1575 1591
1576 debug(("Laid %d dominoes, total %d dominoes.\n", nlaid, state->wh/2)); 1592 debug(("Laid %d dominoes, total %d dominoes.\n", nlaid, state->wh/2));
1593 (void)nlaid;
1577 game_debug(state, "Final layout"); 1594 game_debug(state, "Final layout");
1578 return ret; 1595 return ret;
1579} 1596}
@@ -1720,7 +1737,7 @@ static game_ui *new_ui(const game_state *state)
1720{ 1737{
1721 game_ui *ui = snew(game_ui); 1738 game_ui *ui = snew(game_ui);
1722 ui->cur_x = ui->cur_y = 0; 1739 ui->cur_x = ui->cur_y = 0;
1723 ui->cur_visible = false; 1740 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1724 return ui; 1741 return ui;
1725} 1742}
1726 1743
@@ -1729,15 +1746,6 @@ static void free_ui(game_ui *ui)
1729 sfree(ui); 1746 sfree(ui);
1730} 1747}
1731 1748
1732static char *encode_ui(const game_ui *ui)
1733{
1734 return NULL;
1735}
1736
1737static void decode_ui(game_ui *ui, const char *encoding)
1738{
1739}
1740
1741static void game_changed_state(game_ui *ui, const game_state *oldstate, 1749static void game_changed_state(game_ui *ui, const game_state *oldstate,
1742 const game_state *newstate) 1750 const game_state *newstate)
1743{ 1751{
@@ -1745,6 +1753,36 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1745 ui->cur_visible = false; 1753 ui->cur_visible = false;
1746} 1754}
1747 1755
1756static const char *current_key_label(const game_ui *ui,
1757 const game_state *state, int button)
1758{
1759 int idx;
1760
1761 if (IS_CURSOR_SELECT(button)) {
1762 if (!ui->cur_visible) return "";
1763 idx = ui->cur_y * state->w + ui->cur_x;
1764 if (button == CURSOR_SELECT) {
1765 if (state->grid[idx] == NEUTRAL && state->flags[idx] & GS_SET)
1766 return "";
1767 switch (state->grid[idx]) {
1768 case EMPTY: return "+";
1769 case POSITIVE: return "-";
1770 case NEGATIVE: return "Clear";
1771 }
1772 }
1773 if (button == CURSOR_SELECT2) {
1774 if (state->grid[idx] != NEUTRAL) return "";
1775 if (state->flags[idx] & GS_SET) /* neutral */
1776 return "?";
1777 if (state->flags[idx] & GS_NOTNEUTRAL) /* !neutral */
1778 return "Clear";
1779 else
1780 return "X";
1781 }
1782 }
1783 return "";
1784}
1785
1748struct game_drawstate { 1786struct game_drawstate {
1749 int tilesize; 1787 int tilesize;
1750 bool started, solved; 1788 bool started, solved;
@@ -1805,14 +1843,13 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1805 char *nullret = NULL, buf[80], movech; 1843 char *nullret = NULL, buf[80], movech;
1806 enum { CYCLE_MAGNET, CYCLE_NEUTRAL } action; 1844 enum { CYCLE_MAGNET, CYCLE_NEUTRAL } action;
1807 1845
1808 if (IS_CURSOR_MOVE(button)) { 1846 if (IS_CURSOR_MOVE(button))
1809 move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h, false); 1847 return move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h,
1810 ui->cur_visible = true; 1848 false, &ui->cur_visible);
1811 return UI_UPDATE; 1849 else if (IS_CURSOR_SELECT(button)) {
1812 } else if (IS_CURSOR_SELECT(button)) {
1813 if (!ui->cur_visible) { 1850 if (!ui->cur_visible) {
1814 ui->cur_visible = true; 1851 ui->cur_visible = true;
1815 return UI_UPDATE; 1852 return MOVE_UI_UPDATE;
1816 } 1853 }
1817 action = (button == CURSOR_SELECT) ? CYCLE_MAGNET : CYCLE_NEUTRAL; 1854 action = (button == CURSOR_SELECT) ? CYCLE_MAGNET : CYCLE_NEUTRAL;
1818 gx = ui->cur_x; 1855 gx = ui->cur_x;
@@ -1821,7 +1858,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1821 (button == LEFT_BUTTON || button == RIGHT_BUTTON)) { 1858 (button == LEFT_BUTTON || button == RIGHT_BUTTON)) {
1822 if (ui->cur_visible) { 1859 if (ui->cur_visible) {
1823 ui->cur_visible = false; 1860 ui->cur_visible = false;
1824 nullret = UI_UPDATE; 1861 nullret = MOVE_UI_UPDATE;
1825 } 1862 }
1826 action = (button == LEFT_BUTTON) ? CYCLE_MAGNET : CYCLE_NEUTRAL; 1863 action = (button == LEFT_BUTTON) ? CYCLE_MAGNET : CYCLE_NEUTRAL;
1827 } else if (button == LEFT_BUTTON && is_clue(state, gx, gy)) { 1864 } else if (button == LEFT_BUTTON && is_clue(state, gx, gy)) {
@@ -1928,7 +1965,7 @@ badmove:
1928 */ 1965 */
1929 1966
1930static void game_compute_size(const game_params *params, int tilesize, 1967static void game_compute_size(const game_params *params, int tilesize,
1931 int *x, int *y) 1968 const game_ui *ui, int *x, int *y)
1932{ 1969{
1933 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 1970 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1934 struct { int tilesize; } ads, *ds = &ads; 1971 struct { int tilesize; } ads, *ds = &ads;
@@ -2205,12 +2242,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2205 flash = (int)(flashtime * 5 / FLASH_TIME) % 2; 2242 flash = (int)(flashtime * 5 / FLASH_TIME) % 2;
2206 2243
2207 if (!ds->started) { 2244 if (!ds->started) {
2208 /* draw background, corner +-. */ 2245 /* draw corner +-. */
2209 draw_rect(dr, 0, 0,
2210 TILE_SIZE * (w+2) + 2 * BORDER,
2211 TILE_SIZE * (h+2) + 2 * BORDER,
2212 COL_BACKGROUND);
2213
2214 draw_sym(dr, ds, -1, -1, POSITIVE, COL_TEXT); 2246 draw_sym(dr, ds, -1, -1, POSITIVE, COL_TEXT);
2215 draw_sym(dr, ds, state->w, state->h, NEGATIVE, COL_TEXT); 2247 draw_sym(dr, ds, state->w, state->h, NEGATIVE, COL_TEXT);
2216 2248
@@ -2309,24 +2341,21 @@ static int game_status(const game_state *state)
2309 return state->completed ? +1 : 0; 2341 return state->completed ? +1 : 0;
2310} 2342}
2311 2343
2312static bool game_timing_state(const game_state *state, game_ui *ui) 2344static void game_print_size(const game_params *params, const game_ui *ui,
2313{ 2345 float *x, float *y)
2314 return true;
2315}
2316
2317static void game_print_size(const game_params *params, float *x, float *y)
2318{ 2346{
2319 int pw, ph; 2347 int pw, ph;
2320 2348
2321 /* 2349 /*
2322 * I'll use 6mm squares by default. 2350 * I'll use 6mm squares by default.
2323 */ 2351 */
2324 game_compute_size(params, 600, &pw, &ph); 2352 game_compute_size(params, 600, ui, &pw, &ph);
2325 *x = pw / 100.0F; 2353 *x = pw / 100.0F;
2326 *y = ph / 100.0F; 2354 *y = ph / 100.0F;
2327} 2355}
2328 2356
2329static void game_print(drawing *dr, const game_state *state, int tilesize) 2357static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2358 int tilesize)
2330{ 2359{
2331 int w = state->w, h = state->h; 2360 int w = state->w, h = state->h;
2332 int ink = print_mono_colour(dr, 0); 2361 int ink = print_mono_colour(dr, 0);
@@ -2430,12 +2459,14 @@ const struct game thegame = {
2430 free_game, 2459 free_game,
2431 true, solve_game, 2460 true, solve_game,
2432 true, game_can_format_as_text_now, game_text_format, 2461 true, game_can_format_as_text_now, game_text_format,
2462 NULL, NULL, /* get_prefs, set_prefs */
2433 new_ui, 2463 new_ui,
2434 free_ui, 2464 free_ui,
2435 encode_ui, 2465 NULL, /* encode_ui */
2436 decode_ui, 2466 NULL, /* decode_ui */
2437 NULL, /* game_request_keys */ 2467 NULL, /* game_request_keys */
2438 game_changed_state, 2468 game_changed_state,
2469 current_key_label,
2439 interpret_move, 2470 interpret_move,
2440 execute_move, 2471 execute_move,
2441 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 2472 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -2449,7 +2480,7 @@ const struct game thegame = {
2449 game_status, 2480 game_status,
2450 true, false, game_print_size, game_print, 2481 true, false, game_print_size, game_print,
2451 false, /* wants_statusbar */ 2482 false, /* wants_statusbar */
2452 false, game_timing_state, 2483 false, NULL, /* timing_state */
2453 REQUIRE_RBUTTON, /* flags */ 2484 REQUIRE_RBUTTON, /* flags */
2454}; 2485};
2455 2486
@@ -2458,14 +2489,14 @@ const struct game thegame = {
2458#include <time.h> 2489#include <time.h>
2459#include <stdarg.h> 2490#include <stdarg.h>
2460 2491
2461const char *quis = NULL; 2492static const char *quis = NULL;
2462bool csv = false; 2493static bool csv = false;
2463 2494
2464void usage(FILE *out) { 2495static void usage(FILE *out) {
2465 fprintf(out, "usage: %s [-v] [--print] <params>|<game id>\n", quis); 2496 fprintf(out, "usage: %s [-v] [--print] <params>|<game id>\n", quis);
2466} 2497}
2467 2498
2468void doprint(game_state *state) 2499static void doprint(game_state *state)
2469{ 2500{
2470 char *fmt = game_text_format(state); 2501 char *fmt = game_text_format(state);
2471 printf("%s", fmt); 2502 printf("%s", fmt);
@@ -2559,7 +2590,7 @@ static void start_soak(game_params *p, random_state *rs)
2559 sfree(aux); 2590 sfree(aux);
2560} 2591}
2561 2592
2562int main(int argc, const char *argv[]) 2593int main(int argc, char *argv[])
2563{ 2594{
2564 bool print = false, soak = false, solved = false; 2595 bool print = false, soak = false, solved = false;
2565 int ret; 2596 int ret;
@@ -2608,7 +2639,7 @@ int main(int argc, const char *argv[])
2608 decode_params(p, id); 2639 decode_params(p, id);
2609 err = validate_params(p, true); 2640 err = validate_params(p, true);
2610 if (err) { 2641 if (err) {
2611 fprintf(stderr, "%s: %s", argv[0], err); 2642 fprintf(stderr, "%s: %s\n", argv[0], err);
2612 goto done; 2643 goto done;
2613 } 2644 }
2614 2645