diff options
author | Franklin Wei <franklin@rockbox.org> | 2024-07-22 21:43:25 -0400 |
---|---|---|
committer | Franklin Wei <franklin@rockbox.org> | 2024-07-22 21:44:08 -0400 |
commit | 09aa8de52cb962f1ceebfb1fd44f2c54a924fc5c (patch) | |
tree | 182bd4efb2dc8ca4fcb369d8cccab0c0f290d054 /apps/plugins/puzzles/src/pattern.c | |
parent | c72030f98c953a82ed6f5c7132ad000c3d5f4a16 (diff) | |
download | rockbox-09aa8de52cb962f1ceebfb1fd44f2c54a924fc5c.tar.gz rockbox-09aa8de52cb962f1ceebfb1fd44f2c54a924fc5c.zip |
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
Diffstat (limited to 'apps/plugins/puzzles/src/pattern.c')
-rw-r--r-- | apps/plugins/puzzles/src/pattern.c | 224 |
1 files changed, 145 insertions, 79 deletions
diff --git a/apps/plugins/puzzles/src/pattern.c b/apps/plugins/puzzles/src/pattern.c index df720b7d82..b370a3dc2f 100644 --- a/apps/plugins/puzzles/src/pattern.c +++ b/apps/plugins/puzzles/src/pattern.c | |||
@@ -7,7 +7,12 @@ | |||
7 | #include <string.h> | 7 | #include <string.h> |
8 | #include <assert.h> | 8 | #include <assert.h> |
9 | #include <ctype.h> | 9 | #include <ctype.h> |
10 | #include <math.h> | 10 | #include <limits.h> |
11 | #ifdef NO_TGMATH_H | ||
12 | # include <math.h> | ||
13 | #else | ||
14 | # include <tgmath.h> | ||
15 | #endif | ||
11 | 16 | ||
12 | #include "puzzles.h" | 17 | #include "puzzles.h" |
13 | 18 | ||
@@ -53,6 +58,7 @@ typedef struct game_state_common { | |||
53 | int *rowdata, *rowlen; | 58 | int *rowdata, *rowlen; |
54 | bool *immutable; | 59 | bool *immutable; |
55 | int refcount; | 60 | int refcount; |
61 | enum { FS_SMALL, FS_LARGE } fontsize; | ||
56 | } game_state_common; | 62 | } game_state_common; |
57 | 63 | ||
58 | struct game_state { | 64 | struct game_state { |
@@ -176,7 +182,10 @@ static const char *validate_params(const game_params *params, bool full) | |||
176 | { | 182 | { |
177 | if (params->w <= 0 || params->h <= 0) | 183 | if (params->w <= 0 || params->h <= 0) |
178 | return "Width and height must both be greater than zero"; | 184 | return "Width and height must both be greater than zero"; |
179 | if (params->w * params->w < 2) | 185 | if (params->w > INT_MAX - 1 || params->h > INT_MAX - 1 || |
186 | params->w > INT_MAX / params->h) | ||
187 | return "Puzzle must not be unreasonably large"; | ||
188 | if (params->w * params->h < 2) | ||
180 | return "Grid must contain at least two squares"; | 189 | return "Grid must contain at least two squares"; |
181 | return NULL; | 190 | return NULL; |
182 | } | 191 | } |
@@ -360,7 +369,7 @@ static int compute_rowdata(int *ret, unsigned char *start, int len, int step) | |||
360 | #define STILL_UNKNOWN 3 | 369 | #define STILL_UNKNOWN 3 |
361 | 370 | ||
362 | #ifdef STANDALONE_SOLVER | 371 | #ifdef STANDALONE_SOLVER |
363 | bool verbose = false; | 372 | static bool verbose = false; |
364 | #endif | 373 | #endif |
365 | 374 | ||
366 | static bool do_recurse(unsigned char *known, unsigned char *deduced, | 375 | static bool do_recurse(unsigned char *known, unsigned char *deduced, |
@@ -441,6 +450,8 @@ static bool do_row(unsigned char *known, unsigned char *deduced, | |||
441 | int rowlen, i, freespace; | 450 | int rowlen, i, freespace; |
442 | bool done_any; | 451 | bool done_any; |
443 | 452 | ||
453 | assert(len >= 0); /* avoid compile warnings about the memsets below */ | ||
454 | |||
444 | freespace = len+1; | 455 | freespace = len+1; |
445 | for (rowlen = 0; data[rowlen]; rowlen++) { | 456 | for (rowlen = 0; data[rowlen]; rowlen++) { |
446 | minpos_done[rowlen] = minpos_ok[rowlen] = len - 1; | 457 | minpos_done[rowlen] = minpos_ok[rowlen] = len - 1; |
@@ -654,7 +665,7 @@ static bool solve_puzzle(const game_state *state, unsigned char *grid, | |||
654 | #ifndef STANDALONE_PICTURE_GENERATOR | 665 | #ifndef STANDALONE_PICTURE_GENERATOR |
655 | static unsigned char *generate_soluble(random_state *rs, int w, int h) | 666 | static unsigned char *generate_soluble(random_state *rs, int w, int h) |
656 | { | 667 | { |
657 | int i, j, ntries, max; | 668 | int i, j, max; |
658 | bool ok; | 669 | bool ok; |
659 | unsigned char *grid, *matrix, *workspace; | 670 | unsigned char *grid, *matrix, *workspace; |
660 | unsigned int *changed_h, *changed_w; | 671 | unsigned int *changed_h, *changed_w; |
@@ -670,11 +681,7 @@ static unsigned char *generate_soluble(random_state *rs, int w, int h) | |||
670 | changed_w = snewn(max+1, unsigned int); | 681 | changed_w = snewn(max+1, unsigned int); |
671 | rowdata = snewn(max+1, int); | 682 | rowdata = snewn(max+1, int); |
672 | 683 | ||
673 | ntries = 0; | ||
674 | |||
675 | do { | 684 | do { |
676 | ntries++; | ||
677 | |||
678 | generate(rs, w, h, grid); | 685 | generate(rs, w, h, grid); |
679 | 686 | ||
680 | /* | 687 | /* |
@@ -719,7 +726,7 @@ static unsigned char *generate_soluble(random_state *rs, int w, int h) | |||
719 | #endif | 726 | #endif |
720 | 727 | ||
721 | #ifdef STANDALONE_PICTURE_GENERATOR | 728 | #ifdef STANDALONE_PICTURE_GENERATOR |
722 | unsigned char *picture; | 729 | static unsigned char *picture; |
723 | #endif | 730 | #endif |
724 | 731 | ||
725 | static char *new_game_desc(const game_params *params, random_state *rs, | 732 | static char *new_game_desc(const game_params *params, random_state *rs, |
@@ -908,6 +915,10 @@ static const char *validate_desc(const game_params *params, const char *desc) | |||
908 | p = desc; | 915 | p = desc; |
909 | while (*desc && isdigit((unsigned char)*desc)) desc++; | 916 | while (*desc && isdigit((unsigned char)*desc)) desc++; |
910 | n = atoi(p); | 917 | n = atoi(p); |
918 | if (n <= 0) | ||
919 | return "all clues must be positive"; | ||
920 | if (n > INT_MAX - 1) | ||
921 | return "at least one clue is grossly excessive"; | ||
911 | rowspace -= n+1; | 922 | rowspace -= n+1; |
912 | 923 | ||
913 | if (rowspace < 0) { | 924 | if (rowspace < 0) { |
@@ -965,7 +976,7 @@ static const char *validate_desc(const game_params *params, const char *desc) | |||
965 | static game_state *new_game(midend *me, const game_params *params, | 976 | static game_state *new_game(midend *me, const game_params *params, |
966 | const char *desc) | 977 | const char *desc) |
967 | { | 978 | { |
968 | int i; | 979 | int i, j; |
969 | const char *p; | 980 | const char *p; |
970 | game_state *state = snew(game_state); | 981 | game_state *state = snew(game_state); |
971 | 982 | ||
@@ -1003,6 +1014,26 @@ static game_state *new_game(midend *me, const game_params *params, | |||
1003 | } | 1014 | } |
1004 | } | 1015 | } |
1005 | 1016 | ||
1017 | /* | ||
1018 | * Choose a font size based on the clues. If any column clue is | ||
1019 | * more than one digit, switch to the smaller size. | ||
1020 | */ | ||
1021 | state->common->fontsize = FS_LARGE; | ||
1022 | for (i = 0; i < params->w; i++) | ||
1023 | for (j = 0; j < state->common->rowlen[i]; j++) | ||
1024 | if (state->common->rowdata[state->common->rowsize * i + j] >= 10) | ||
1025 | state->common->fontsize = FS_SMALL; | ||
1026 | /* | ||
1027 | * We might also need to use the small font if there are lots of | ||
1028 | * row clues. We assume that all clues are one digit and that a | ||
1029 | * single-digit clue takes up 1.5 tiles, of which the clue is 0.5 | ||
1030 | * tiles and the space is 1.0 tiles. | ||
1031 | */ | ||
1032 | for (i = params->w; i < params->w + params->h; i++) | ||
1033 | if ((state->common->rowlen[i] * 3 - 2) > | ||
1034 | TLBORDER(state->common->w) * 2) | ||
1035 | state->common->fontsize = FS_SMALL; | ||
1036 | |||
1006 | if (desc[-1] == ',') { | 1037 | if (desc[-1] == ',') { |
1007 | /* | 1038 | /* |
1008 | * Optional extra piece of game description which fills in | 1039 | * Optional extra piece of game description which fills in |
@@ -1217,7 +1248,7 @@ static game_ui *new_ui(const game_state *state) | |||
1217 | ret = snew(game_ui); | 1248 | ret = snew(game_ui); |
1218 | ret->dragging = false; | 1249 | ret->dragging = false; |
1219 | ret->cur_x = ret->cur_y = 0; | 1250 | ret->cur_x = ret->cur_y = 0; |
1220 | ret->cur_visible = false; | 1251 | ret->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false); |
1221 | 1252 | ||
1222 | return ret; | 1253 | return ret; |
1223 | } | 1254 | } |
@@ -1227,18 +1258,26 @@ static void free_ui(game_ui *ui) | |||
1227 | sfree(ui); | 1258 | sfree(ui); |
1228 | } | 1259 | } |
1229 | 1260 | ||
1230 | static char *encode_ui(const game_ui *ui) | 1261 | static void game_changed_state(game_ui *ui, const game_state *oldstate, |
1231 | { | 1262 | const game_state *newstate) |
1232 | return NULL; | ||
1233 | } | ||
1234 | |||
1235 | static void decode_ui(game_ui *ui, const char *encoding) | ||
1236 | { | 1263 | { |
1237 | } | 1264 | } |
1238 | 1265 | ||
1239 | static void game_changed_state(game_ui *ui, const game_state *oldstate, | 1266 | static const char *current_key_label(const game_ui *ui, |
1240 | const game_state *newstate) | 1267 | const game_state *state, int button) |
1241 | { | 1268 | { |
1269 | if (IS_CURSOR_SELECT(button)) { | ||
1270 | if (!ui->cur_visible) return ""; | ||
1271 | switch (state->grid[ui->cur_y * state->common->w + ui->cur_x]) { | ||
1272 | case GRID_UNKNOWN: | ||
1273 | return button == CURSOR_SELECT ? "Black" : "White"; | ||
1274 | case GRID_FULL: | ||
1275 | return button == CURSOR_SELECT ? "White" : "Grey"; | ||
1276 | case GRID_EMPTY: | ||
1277 | return button == CURSOR_SELECT ? "Grey" : "Black"; | ||
1278 | } | ||
1279 | } | ||
1280 | return ""; | ||
1242 | } | 1281 | } |
1243 | 1282 | ||
1244 | struct game_drawstate { | 1283 | struct game_drawstate { |
@@ -1247,6 +1286,7 @@ struct game_drawstate { | |||
1247 | int tilesize; | 1286 | int tilesize; |
1248 | unsigned char *visible, *numcolours; | 1287 | unsigned char *visible, *numcolours; |
1249 | int cur_x, cur_y; | 1288 | int cur_x, cur_y; |
1289 | char *strbuf; /* Used for formatting clues. */ | ||
1250 | }; | 1290 | }; |
1251 | 1291 | ||
1252 | static char *interpret_move(const game_state *state, game_ui *ui, | 1292 | static char *interpret_move(const game_state *state, game_ui *ui, |
@@ -1254,7 +1294,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
1254 | int x, int y, int button) | 1294 | int x, int y, int button) |
1255 | { | 1295 | { |
1256 | bool control = button & MOD_CTRL, shift = button & MOD_SHFT; | 1296 | bool control = button & MOD_CTRL, shift = button & MOD_SHFT; |
1257 | button &= ~MOD_MASK; | 1297 | button = STRIP_BUTTON_MODIFIERS(button); |
1258 | 1298 | ||
1259 | x = FROMCOORD(state->common->w, x); | 1299 | x = FROMCOORD(state->common->w, x); |
1260 | y = FROMCOORD(state->common->h, y); | 1300 | y = FROMCOORD(state->common->h, y); |
@@ -1294,7 +1334,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
1294 | ui->drag_start_y = ui->drag_end_y = y; | 1334 | ui->drag_start_y = ui->drag_end_y = y; |
1295 | ui->cur_visible = false; | 1335 | ui->cur_visible = false; |
1296 | 1336 | ||
1297 | return UI_UPDATE; | 1337 | return MOVE_UI_UPDATE; |
1298 | } | 1338 | } |
1299 | 1339 | ||
1300 | if (ui->dragging && button == ui->drag) { | 1340 | if (ui->dragging && button == ui->drag) { |
@@ -1323,7 +1363,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
1323 | ui->drag_end_x = x; | 1363 | ui->drag_end_x = x; |
1324 | ui->drag_end_y = y; | 1364 | ui->drag_end_y = y; |
1325 | 1365 | ||
1326 | return UI_UPDATE; | 1366 | return MOVE_UI_UPDATE; |
1327 | } | 1367 | } |
1328 | 1368 | ||
1329 | if (ui->dragging && button == ui->release) { | 1369 | if (ui->dragging && button == ui->release) { |
@@ -1351,20 +1391,21 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
1351 | x1, y1, x2-x1+1, y2-y1+1); | 1391 | x1, y1, x2-x1+1, y2-y1+1); |
1352 | return dupstr(buf); | 1392 | return dupstr(buf); |
1353 | } else | 1393 | } else |
1354 | return UI_UPDATE; | 1394 | return MOVE_UI_UPDATE; |
1355 | } | 1395 | } |
1356 | 1396 | ||
1357 | if (IS_CURSOR_MOVE(button)) { | 1397 | if (IS_CURSOR_MOVE(button)) { |
1358 | int x = ui->cur_x, y = ui->cur_y, newstate; | 1398 | int x = ui->cur_x, y = ui->cur_y, newstate; |
1359 | char buf[80]; | 1399 | char buf[80], *ret; |
1360 | move_cursor(button, &ui->cur_x, &ui->cur_y, state->common->w, state->common->h, false); | 1400 | ret = move_cursor(button, &ui->cur_x, &ui->cur_y, |
1361 | ui->cur_visible = true; | 1401 | state->common->w, state->common->h, false, |
1362 | if (!control && !shift) return UI_UPDATE; | 1402 | &ui->cur_visible); |
1403 | if (!control && !shift) return ret; | ||
1363 | 1404 | ||
1364 | newstate = control ? shift ? GRID_UNKNOWN : GRID_FULL : GRID_EMPTY; | 1405 | newstate = control ? shift ? GRID_UNKNOWN : GRID_FULL : GRID_EMPTY; |
1365 | if (state->grid[y * state->common->w + x] == newstate && | 1406 | if (state->grid[y * state->common->w + x] == newstate && |
1366 | state->grid[ui->cur_y * state->common->w + ui->cur_x] == newstate) | 1407 | state->grid[ui->cur_y * state->common->w + ui->cur_x] == newstate) |
1367 | return UI_UPDATE; | 1408 | return ret; |
1368 | 1409 | ||
1369 | sprintf(buf, "%c%d,%d,%d,%d", control ? shift ? 'U' : 'F' : 'E', | 1410 | sprintf(buf, "%c%d,%d,%d,%d", control ? shift ? 'U' : 'F' : 'E', |
1370 | min(x, ui->cur_x), min(y, ui->cur_y), | 1411 | min(x, ui->cur_x), min(y, ui->cur_y), |
@@ -1379,7 +1420,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
1379 | 1420 | ||
1380 | if (!ui->cur_visible) { | 1421 | if (!ui->cur_visible) { |
1381 | ui->cur_visible = true; | 1422 | ui->cur_visible = true; |
1382 | return UI_UPDATE; | 1423 | return MOVE_UI_UPDATE; |
1383 | } | 1424 | } |
1384 | 1425 | ||
1385 | if (button == CURSOR_SELECT2) | 1426 | if (button == CURSOR_SELECT2) |
@@ -1637,7 +1678,7 @@ static bool check_errors(const game_state *state, int i) | |||
1637 | */ | 1678 | */ |
1638 | 1679 | ||
1639 | static void game_compute_size(const game_params *params, int tilesize, | 1680 | static void game_compute_size(const game_params *params, int tilesize, |
1640 | int *x, int *y) | 1681 | const game_ui *ui, int *x, int *y) |
1641 | { | 1682 | { |
1642 | /* Ick: fake up `ds->tilesize' for macro expansion purposes */ | 1683 | /* Ick: fake up `ds->tilesize' for macro expansion purposes */ |
1643 | struct { int tilesize; } ads, *ds = &ads; | 1684 | struct { int tilesize; } ads, *ds = &ads; |
@@ -1692,6 +1733,8 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) | |||
1692 | ds->numcolours = snewn(ds->w + ds->h, unsigned char); | 1733 | ds->numcolours = snewn(ds->w + ds->h, unsigned char); |
1693 | memset(ds->numcolours, 255, ds->w + ds->h); | 1734 | memset(ds->numcolours, 255, ds->w + ds->h); |
1694 | ds->cur_x = ds->cur_y = 0; | 1735 | ds->cur_x = ds->cur_y = 0; |
1736 | ds->strbuf = snewn(state->common->rowsize * | ||
1737 | MAX_DIGITS(*state->common->rowdata) + 1, char); | ||
1695 | 1738 | ||
1696 | return ds; | 1739 | return ds; |
1697 | } | 1740 | } |
@@ -1699,6 +1742,8 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) | |||
1699 | static void game_free_drawstate(drawing *dr, game_drawstate *ds) | 1742 | static void game_free_drawstate(drawing *dr, game_drawstate *ds) |
1700 | { | 1743 | { |
1701 | sfree(ds->visible); | 1744 | sfree(ds->visible); |
1745 | sfree(ds->numcolours); | ||
1746 | sfree(ds->strbuf); | ||
1702 | sfree(ds); | 1747 | sfree(ds); |
1703 | } | 1748 | } |
1704 | 1749 | ||
@@ -1743,19 +1788,43 @@ static void draw_numbers( | |||
1743 | int *rowdata = state->common->rowdata + state->common->rowsize * i; | 1788 | int *rowdata = state->common->rowdata + state->common->rowsize * i; |
1744 | int nfit; | 1789 | int nfit; |
1745 | int j; | 1790 | int j; |
1791 | int rx, ry, rw, rh; | ||
1792 | int fontsize; | ||
1746 | 1793 | ||
1747 | if (erase) { | 1794 | if (i < state->common->w) { |
1748 | if (i < state->common->w) { | 1795 | rx = TOCOORD(state->common->w, i); |
1749 | draw_rect(dr, TOCOORD(state->common->w, i), 0, | 1796 | ry = 0; |
1750 | TILE_SIZE, BORDER + TLBORDER(state->common->h) * TILE_SIZE, | 1797 | rw = TILE_SIZE; |
1751 | COL_BACKGROUND); | 1798 | rh = BORDER + TLBORDER(state->common->h) * TILE_SIZE; |
1752 | } else { | 1799 | } else { |
1753 | draw_rect(dr, 0, TOCOORD(state->common->h, i - state->common->w), | 1800 | rx = 0; |
1754 | BORDER + TLBORDER(state->common->w) * TILE_SIZE, TILE_SIZE, | 1801 | ry = TOCOORD(state->common->h, i - state->common->w); |
1755 | COL_BACKGROUND); | 1802 | rw = BORDER + TLBORDER(state->common->w) * TILE_SIZE; |
1756 | } | 1803 | rh = TILE_SIZE; |
1757 | } | 1804 | } |
1758 | 1805 | ||
1806 | clip(dr, rx, ry, rw, rh); | ||
1807 | if (erase) | ||
1808 | draw_rect(dr, rx, ry, rw, rh, COL_BACKGROUND); | ||
1809 | |||
1810 | /* | ||
1811 | * Choose a font size that's suitable for the lengths of clue. | ||
1812 | * Only column clues are interesting because row clues can be | ||
1813 | * spaced out independent of the tile size. For column clues, we | ||
1814 | * want to go as large as practical while leaving decent space | ||
1815 | * between horizintally adjacent clues. We currently distinguish | ||
1816 | * two cases: FS_LARGE is when all column clues are single digits, | ||
1817 | * and FS_SMALL in all other cases. | ||
1818 | * | ||
1819 | * If we assume that a digit is about 0.6em wide, and we want | ||
1820 | * about that space between clues, then FS_LARGE should be | ||
1821 | * TILESIZE/1.2. If we also assume that clues are at most two | ||
1822 | * digits long then the case where adjacent clues are two digits | ||
1823 | * long requries FS_SMALL to be TILESIZE/1.8. | ||
1824 | */ | ||
1825 | fontsize = (TILE_SIZE + 0.5F) / | ||
1826 | (state->common->fontsize == FS_LARGE ? 1.2F : 1.8F); | ||
1827 | |||
1759 | /* | 1828 | /* |
1760 | * Normally I space the numbers out by the same distance as the | 1829 | * Normally I space the numbers out by the same distance as the |
1761 | * tile size. However, if there are more numbers than available | 1830 | * tile size. However, if there are more numbers than available |
@@ -1768,32 +1837,38 @@ static void draw_numbers( | |||
1768 | nfit = max(rowlen, nfit) - 1; | 1837 | nfit = max(rowlen, nfit) - 1; |
1769 | assert(nfit > 0); | 1838 | assert(nfit > 0); |
1770 | 1839 | ||
1771 | for (j = 0; j < rowlen; j++) { | 1840 | if (i < state->common->w) { |
1772 | int x, y; | 1841 | for (j = 0; j < rowlen; j++) { |
1773 | char str[80]; | 1842 | int x, y; |
1843 | char str[MAX_DIGITS(*rowdata) + 1]; | ||
1774 | 1844 | ||
1775 | if (i < state->common->w) { | 1845 | x = rx; |
1776 | x = TOCOORD(state->common->w, i); | ||
1777 | y = BORDER + TILE_SIZE * (TLBORDER(state->common->h)-1); | 1846 | y = BORDER + TILE_SIZE * (TLBORDER(state->common->h)-1); |
1778 | y -= ((rowlen-j-1)*TILE_SIZE) * (TLBORDER(state->common->h)-1) / nfit; | 1847 | y -= ((rowlen-j-1)*TILE_SIZE) * (TLBORDER(state->common->h)-1) / nfit; |
1779 | } else { | 1848 | sprintf(str, "%d", rowdata[j]); |
1780 | y = TOCOORD(state->common->h, i - state->common->w); | 1849 | draw_text(dr, x+TILE_SIZE/2, y+TILE_SIZE/2, FONT_VARIABLE, |
1781 | x = BORDER + TILE_SIZE * (TLBORDER(state->common->w)-1); | 1850 | fontsize, ALIGN_HCENTRE | ALIGN_VCENTRE, colour, str); |
1782 | x -= ((rowlen-j-1)*TILE_SIZE) * (TLBORDER(state->common->w)-1) / nfit; | ||
1783 | } | 1851 | } |
1784 | |||
1785 | sprintf(str, "%d", rowdata[j]); | ||
1786 | draw_text(dr, x+TILE_SIZE/2, y+TILE_SIZE/2, FONT_VARIABLE, | ||
1787 | TILE_SIZE/2, ALIGN_HCENTRE | ALIGN_VCENTRE, colour, str); | ||
1788 | } | ||
1789 | |||
1790 | if (i < state->common->w) { | ||
1791 | draw_update(dr, TOCOORD(state->common->w, i), 0, | ||
1792 | TILE_SIZE, BORDER + TLBORDER(state->common->h) * TILE_SIZE); | ||
1793 | } else { | 1852 | } else { |
1794 | draw_update(dr, 0, TOCOORD(state->common->h, i - state->common->w), | 1853 | int x, y; |
1795 | BORDER + TLBORDER(state->common->w) * TILE_SIZE, TILE_SIZE); | 1854 | size_t off = 0; |
1855 | const char *spaces = " "; | ||
1856 | |||
1857 | assert(rowlen <= state->common->rowsize); | ||
1858 | *ds->strbuf = '\0'; | ||
1859 | /* Squish up a bit if there are lots of clues. */ | ||
1860 | if (rowlen > TLBORDER(state->common->w)) spaces++; | ||
1861 | for (j = 0; j < rowlen; j++) | ||
1862 | off += sprintf(ds->strbuf + off, "%s%d", | ||
1863 | j ? spaces : "", rowdata[j]); | ||
1864 | y = ry; | ||
1865 | x = BORDER + TILE_SIZE * (TLBORDER(state->common->w)-1); | ||
1866 | draw_text(dr, x+TILE_SIZE, y+TILE_SIZE/2, FONT_VARIABLE, | ||
1867 | fontsize, ALIGN_HRIGHT | ALIGN_VCENTRE, colour, ds->strbuf); | ||
1796 | } | 1868 | } |
1869 | |||
1870 | unclip(dr); | ||
1871 | draw_update(dr, rx, ry, rw, rh); | ||
1797 | } | 1872 | } |
1798 | 1873 | ||
1799 | static void game_redraw(drawing *dr, game_drawstate *ds, | 1874 | static void game_redraw(drawing *dr, game_drawstate *ds, |
@@ -1808,14 +1883,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds, | |||
1808 | 1883 | ||
1809 | if (!ds->started) { | 1884 | if (!ds->started) { |
1810 | /* | 1885 | /* |
1811 | * The initial contents of the window are not guaranteed | ||
1812 | * and can vary with front ends. To be on the safe side, | ||
1813 | * all games should start by drawing a big background- | ||
1814 | * colour rectangle covering the whole window. | ||
1815 | */ | ||
1816 | draw_rect(dr, 0, 0, SIZE(ds->w), SIZE(ds->h), COL_BACKGROUND); | ||
1817 | |||
1818 | /* | ||
1819 | * Draw the grid outline. | 1886 | * Draw the grid outline. |
1820 | */ | 1887 | */ |
1821 | draw_rect(dr, TOCOORD(ds->w, 0) - 1, TOCOORD(ds->h, 0) - 1, | 1888 | draw_rect(dr, TOCOORD(ds->w, 0) - 1, TOCOORD(ds->h, 0) - 1, |
@@ -1936,24 +2003,21 @@ static int game_status(const game_state *state) | |||
1936 | return state->completed ? +1 : 0; | 2003 | return state->completed ? +1 : 0; |
1937 | } | 2004 | } |
1938 | 2005 | ||
1939 | static bool game_timing_state(const game_state *state, game_ui *ui) | 2006 | static void game_print_size(const game_params *params, const game_ui *ui, |
1940 | { | 2007 | float *x, float *y) |
1941 | return true; | ||
1942 | } | ||
1943 | |||
1944 | static void game_print_size(const game_params *params, float *x, float *y) | ||
1945 | { | 2008 | { |
1946 | int pw, ph; | 2009 | int pw, ph; |
1947 | 2010 | ||
1948 | /* | 2011 | /* |
1949 | * I'll use 5mm squares by default. | 2012 | * I'll use 5mm squares by default. |
1950 | */ | 2013 | */ |
1951 | game_compute_size(params, 500, &pw, &ph); | 2014 | game_compute_size(params, 500, ui, &pw, &ph); |
1952 | *x = pw / 100.0F; | 2015 | *x = pw / 100.0F; |
1953 | *y = ph / 100.0F; | 2016 | *y = ph / 100.0F; |
1954 | } | 2017 | } |
1955 | 2018 | ||
1956 | static void game_print(drawing *dr, const game_state *state, int tilesize) | 2019 | static void game_print(drawing *dr, const game_state *state, const game_ui *ui, |
2020 | int tilesize) | ||
1957 | { | 2021 | { |
1958 | int w = state->common->w, h = state->common->h; | 2022 | int w = state->common->w, h = state->common->h; |
1959 | int ink = print_mono_colour(dr, 0); | 2023 | int ink = print_mono_colour(dr, 0); |
@@ -2027,12 +2091,14 @@ const struct game thegame = { | |||
2027 | free_game, | 2091 | free_game, |
2028 | true, solve_game, | 2092 | true, solve_game, |
2029 | true, game_can_format_as_text_now, game_text_format, | 2093 | true, game_can_format_as_text_now, game_text_format, |
2094 | NULL, NULL, /* get_prefs, set_prefs */ | ||
2030 | new_ui, | 2095 | new_ui, |
2031 | free_ui, | 2096 | free_ui, |
2032 | encode_ui, | 2097 | NULL, /* encode_ui */ |
2033 | decode_ui, | 2098 | NULL, /* decode_ui */ |
2034 | NULL, /* game_request_keys */ | 2099 | NULL, /* game_request_keys */ |
2035 | game_changed_state, | 2100 | game_changed_state, |
2101 | current_key_label, | ||
2036 | interpret_move, | 2102 | interpret_move, |
2037 | execute_move, | 2103 | execute_move, |
2038 | PREFERRED_TILE_SIZE, game_compute_size, game_set_size, | 2104 | PREFERRED_TILE_SIZE, game_compute_size, game_set_size, |
@@ -2046,7 +2112,7 @@ const struct game thegame = { | |||
2046 | game_status, | 2112 | game_status, |
2047 | true, false, game_print_size, game_print, | 2113 | true, false, game_print_size, game_print, |
2048 | false, /* wants_statusbar */ | 2114 | false, /* wants_statusbar */ |
2049 | false, game_timing_state, | 2115 | false, NULL, /* timing_state */ |
2050 | REQUIRE_RBUTTON, /* flags */ | 2116 | REQUIRE_RBUTTON, /* flags */ |
2051 | }; | 2117 | }; |
2052 | 2118 | ||