diff options
Diffstat (limited to 'apps/plugins/puzzles/src/flood.c')
-rw-r--r-- | apps/plugins/puzzles/src/flood.c | 184 |
1 files changed, 92 insertions, 92 deletions
diff --git a/apps/plugins/puzzles/src/flood.c b/apps/plugins/puzzles/src/flood.c index 74214a50b6..fe809745db 100644 --- a/apps/plugins/puzzles/src/flood.c +++ b/apps/plugins/puzzles/src/flood.c | |||
@@ -31,7 +31,12 @@ | |||
31 | #include <string.h> | 31 | #include <string.h> |
32 | #include <assert.h> | 32 | #include <assert.h> |
33 | #include <ctype.h> | 33 | #include <ctype.h> |
34 | #include <math.h> | 34 | #include <limits.h> |
35 | #ifdef NO_TGMATH_H | ||
36 | # include <math.h> | ||
37 | #else | ||
38 | # include <tgmath.h> | ||
39 | #endif | ||
35 | 40 | ||
36 | #include "puzzles.h" | 41 | #include "puzzles.h" |
37 | 42 | ||
@@ -140,13 +145,13 @@ static void decode_params(game_params *ret, char const *string) | |||
140 | if (*string == 'c') { | 145 | if (*string == 'c') { |
141 | string++; | 146 | string++; |
142 | ret->colours = atoi(string); | 147 | ret->colours = atoi(string); |
143 | while (string[1] && isdigit((unsigned char)string[1])) string++; | 148 | while (*string && isdigit((unsigned char)*string)) string++; |
144 | } else if (*string == 'm') { | 149 | } else if (*string == 'm') { |
145 | string++; | 150 | string++; |
146 | ret->leniency = atoi(string); | 151 | ret->leniency = atoi(string); |
147 | while (string[1] && isdigit((unsigned char)string[1])) string++; | 152 | while (*string && isdigit((unsigned char)*string)) string++; |
148 | } | 153 | } else |
149 | string++; | 154 | string++; |
150 | } | 155 | } |
151 | } | 156 | } |
152 | 157 | ||
@@ -210,7 +215,9 @@ static const char *validate_params(const game_params *params, bool full) | |||
210 | if (params->w * params->h < 2) | 215 | if (params->w * params->h < 2) |
211 | return "Grid must contain at least two squares"; | 216 | return "Grid must contain at least two squares"; |
212 | if (params->w < 1 || params->h < 1) | 217 | if (params->w < 1 || params->h < 1) |
213 | return "Width and height must both be at least one"; | 218 | return "Width and height must be at least one"; |
219 | if (params->w > INT_MAX / params->h) | ||
220 | return "Width times height must not be unreasonably large"; | ||
214 | if (params->colours < 3 || params->colours > 10) | 221 | if (params->colours < 3 || params->colours > 10) |
215 | return "Must have between 3 and 10 colours"; | 222 | return "Must have between 3 and 10 colours"; |
216 | if (params->leniency < 0) | 223 | if (params->leniency < 0) |
@@ -554,8 +561,10 @@ static char *new_game_desc(const game_params *params, random_state *rs, | |||
554 | /* | 561 | /* |
555 | * Invent a random grid. | 562 | * Invent a random grid. |
556 | */ | 563 | */ |
557 | for (i = 0; i < wh; i++) | 564 | do { |
558 | scratch->grid[i] = random_upto(rs, params->colours); | 565 | for (i = 0; i < wh; i++) |
566 | scratch->grid[i] = random_upto(rs, params->colours); | ||
567 | } while (completed(w, h, scratch->grid)); | ||
559 | 568 | ||
560 | /* | 569 | /* |
561 | * Run the solver, and count how many moves it uses. | 570 | * Run the solver, and count how many moves it uses. |
@@ -770,7 +779,7 @@ struct game_ui { | |||
770 | static game_ui *new_ui(const game_state *state) | 779 | static game_ui *new_ui(const game_state *state) |
771 | { | 780 | { |
772 | struct game_ui *ui = snew(struct game_ui); | 781 | struct game_ui *ui = snew(struct game_ui); |
773 | ui->cursor_visible = false; | 782 | ui->cursor_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false); |
774 | ui->cx = FILLX; | 783 | ui->cx = FILLX; |
775 | ui->cy = FILLY; | 784 | ui->cy = FILLY; |
776 | return ui; | 785 | return ui; |
@@ -781,18 +790,21 @@ static void free_ui(game_ui *ui) | |||
781 | sfree(ui); | 790 | sfree(ui); |
782 | } | 791 | } |
783 | 792 | ||
784 | static char *encode_ui(const game_ui *ui) | 793 | static void game_changed_state(game_ui *ui, const game_state *oldstate, |
785 | { | 794 | const game_state *newstate) |
786 | return NULL; | ||
787 | } | ||
788 | |||
789 | static void decode_ui(game_ui *ui, const char *encoding) | ||
790 | { | 795 | { |
791 | } | 796 | } |
792 | 797 | ||
793 | static void game_changed_state(game_ui *ui, const game_state *oldstate, | 798 | static const char *current_key_label(const game_ui *ui, |
794 | const game_state *newstate) | 799 | const game_state *state, int button) |
795 | { | 800 | { |
801 | if (button == CURSOR_SELECT && | ||
802 | state->grid[0] != state->grid[ui->cy*state->w+ui->cx]) | ||
803 | return "Fill"; | ||
804 | if (button == CURSOR_SELECT2 && | ||
805 | state->soln && state->solnpos < state->soln->nmoves) | ||
806 | return "Advance"; | ||
807 | return ""; | ||
796 | } | 808 | } |
797 | 809 | ||
798 | struct game_drawstate { | 810 | struct game_drawstate { |
@@ -818,35 +830,26 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
818 | { | 830 | { |
819 | int w = state->w, h = state->h; | 831 | int w = state->w, h = state->h; |
820 | int tx = -1, ty = -1, move = -1; | 832 | int tx = -1, ty = -1, move = -1; |
833 | char *nullret = MOVE_NO_EFFECT; | ||
821 | 834 | ||
822 | if (button == LEFT_BUTTON) { | 835 | if (button == LEFT_BUTTON) { |
823 | tx = FROMCOORD(x); | 836 | tx = FROMCOORD(x); |
824 | ty = FROMCOORD(y); | 837 | ty = FROMCOORD(y); |
825 | ui->cursor_visible = false; | 838 | if (ui->cursor_visible) { |
826 | } else if (button == CURSOR_LEFT && ui->cx > 0) { | 839 | ui->cursor_visible = false; |
827 | ui->cx--; | 840 | nullret = MOVE_UI_UPDATE; |
828 | ui->cursor_visible = true; | 841 | } |
829 | return UI_UPDATE; | 842 | } else if (IS_CURSOR_MOVE(button)) { |
830 | } else if (button == CURSOR_RIGHT && ui->cx+1 < w) { | 843 | return move_cursor(button, &ui->cx, &ui->cy, w, h, false, |
831 | ui->cx++; | 844 | &ui->cursor_visible); |
832 | ui->cursor_visible = true; | ||
833 | return UI_UPDATE; | ||
834 | } else if (button == CURSOR_UP && ui->cy > 0) { | ||
835 | ui->cy--; | ||
836 | ui->cursor_visible = true; | ||
837 | return UI_UPDATE; | ||
838 | } else if (button == CURSOR_DOWN && ui->cy+1 < h) { | ||
839 | ui->cy++; | ||
840 | ui->cursor_visible = true; | ||
841 | return UI_UPDATE; | ||
842 | } else if (button == CURSOR_SELECT) { | 845 | } else if (button == CURSOR_SELECT) { |
843 | tx = ui->cx; | 846 | tx = ui->cx; |
844 | ty = ui->cy; | 847 | ty = ui->cy; |
845 | } else if (button == CURSOR_SELECT2 && | 848 | } else if (button == CURSOR_SELECT2) { |
846 | state->soln && state->solnpos < state->soln->nmoves) { | 849 | if (state->soln && state->solnpos < state->soln->nmoves) |
847 | move = state->soln->moves[state->solnpos]; | 850 | move = state->soln->moves[state->solnpos]; |
848 | } else { | 851 | } else { |
849 | return NULL; | 852 | return MOVE_UNUSED; |
850 | } | 853 | } |
851 | 854 | ||
852 | if (tx >= 0 && tx < w && ty >= 0 && ty < h && | 855 | if (tx >= 0 && tx < w && ty >= 0 && ty < h && |
@@ -859,7 +862,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
859 | return dupstr(buf); | 862 | return dupstr(buf); |
860 | } | 863 | } |
861 | 864 | ||
862 | return NULL; | 865 | return nullret; |
863 | } | 866 | } |
864 | 867 | ||
865 | static game_state *execute_move(const game_state *state, const char *move) | 868 | static game_state *execute_move(const game_state *state, const char *move) |
@@ -869,7 +872,8 @@ static game_state *execute_move(const game_state *state, const char *move) | |||
869 | 872 | ||
870 | if (move[0] == 'M' && | 873 | if (move[0] == 'M' && |
871 | sscanf(move+1, "%d", &c) == 1 && | 874 | sscanf(move+1, "%d", &c) == 1 && |
872 | c >= 0 && | 875 | c >= 0 && c < state->colours && |
876 | c != state->grid[FILLY * state->w + FILLX] && | ||
873 | !state->complete) { | 877 | !state->complete) { |
874 | int *queue = snewn(state->w * state->h, int); | 878 | int *queue = snewn(state->w * state->h, int); |
875 | ret = dup_game(state); | 879 | ret = dup_game(state); |
@@ -920,11 +924,23 @@ static game_state *execute_move(const game_state *state, const char *move) | |||
920 | 924 | ||
921 | sol->moves = snewn(sol->nmoves, char); | 925 | sol->moves = snewn(sol->nmoves, char); |
922 | for (i = 0, p = move; i < sol->nmoves; i++) { | 926 | for (i = 0, p = move; i < sol->nmoves; i++) { |
923 | assert(*p); | 927 | if (!*p) { |
928 | badsolve: | ||
929 | sfree(sol->moves); | ||
930 | sfree(sol); | ||
931 | return NULL; | ||
932 | }; | ||
924 | sol->moves[i] = atoi(p); | 933 | sol->moves[i] = atoi(p); |
934 | if (sol->moves[i] < 0 || sol->moves[i] >= state->colours || | ||
935 | (i == 0 ? | ||
936 | sol->moves[i] == state->grid[FILLY * state->w + FILLX] : | ||
937 | sol->moves[i] == sol->moves[i-1])) | ||
938 | /* Solution contains a fill with an invalid colour or | ||
939 | * the current colour. */ | ||
940 | goto badsolve; | ||
925 | p += strspn(p, "0123456789"); | 941 | p += strspn(p, "0123456789"); |
926 | if (*p) { | 942 | if (*p) { |
927 | assert(*p == ','); | 943 | if (*p != ',') goto badsolve; |
928 | p++; | 944 | p++; |
929 | } | 945 | } |
930 | } | 946 | } |
@@ -949,7 +965,7 @@ static game_state *execute_move(const game_state *state, const char *move) | |||
949 | */ | 965 | */ |
950 | 966 | ||
951 | static void game_compute_size(const game_params *params, int tilesize, | 967 | static void game_compute_size(const game_params *params, int tilesize, |
952 | int *x, int *y) | 968 | const game_ui *ui, int *x, int *y) |
953 | { | 969 | { |
954 | /* Ick: fake up `ds->tilesize' for macro expansion purposes */ | 970 | /* Ick: fake up `ds->tilesize' for macro expansion purposes */ |
955 | struct { int tilesize; } ads, *ds = &ads; | 971 | struct { int tilesize; } ads, *ds = &ads; |
@@ -1076,31 +1092,33 @@ static void draw_tile(drawing *dr, game_drawstate *ds, | |||
1076 | colour += COL_1; | 1092 | colour += COL_1; |
1077 | draw_rect(dr, tx, ty, TILESIZE, TILESIZE, colour); | 1093 | draw_rect(dr, tx, ty, TILESIZE, TILESIZE, colour); |
1078 | 1094 | ||
1079 | if (tile & BORDER_L) | 1095 | if (SEP_WIDTH > 0) { |
1080 | draw_rect(dr, tx, ty, | 1096 | if (tile & BORDER_L) |
1081 | SEP_WIDTH, TILESIZE, COL_SEPARATOR); | 1097 | draw_rect(dr, tx, ty, |
1082 | if (tile & BORDER_R) | 1098 | SEP_WIDTH, TILESIZE, COL_SEPARATOR); |
1083 | draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty, | 1099 | if (tile & BORDER_R) |
1084 | SEP_WIDTH, TILESIZE, COL_SEPARATOR); | 1100 | draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty, |
1085 | if (tile & BORDER_U) | 1101 | SEP_WIDTH, TILESIZE, COL_SEPARATOR); |
1086 | draw_rect(dr, tx, ty, | 1102 | if (tile & BORDER_U) |
1087 | TILESIZE, SEP_WIDTH, COL_SEPARATOR); | 1103 | draw_rect(dr, tx, ty, |
1088 | if (tile & BORDER_D) | 1104 | TILESIZE, SEP_WIDTH, COL_SEPARATOR); |
1089 | draw_rect(dr, tx, ty + TILESIZE - SEP_WIDTH, | 1105 | if (tile & BORDER_D) |
1090 | TILESIZE, SEP_WIDTH, COL_SEPARATOR); | 1106 | draw_rect(dr, tx, ty + TILESIZE - SEP_WIDTH, |
1091 | 1107 | TILESIZE, SEP_WIDTH, COL_SEPARATOR); | |
1092 | if (tile & CORNER_UL) | 1108 | |
1093 | draw_rect(dr, tx, ty, | 1109 | if (tile & CORNER_UL) |
1094 | SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); | 1110 | draw_rect(dr, tx, ty, |
1095 | if (tile & CORNER_UR) | 1111 | SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); |
1096 | draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty, | 1112 | if (tile & CORNER_UR) |
1097 | SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); | 1113 | draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty, |
1098 | if (tile & CORNER_DL) | 1114 | SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); |
1099 | draw_rect(dr, tx, ty + TILESIZE - SEP_WIDTH, | 1115 | if (tile & CORNER_DL) |
1100 | SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); | 1116 | draw_rect(dr, tx, ty + TILESIZE - SEP_WIDTH, |
1101 | if (tile & CORNER_DR) | 1117 | SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); |
1102 | draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty + TILESIZE - SEP_WIDTH, | 1118 | if (tile & CORNER_DR) |
1103 | SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); | 1119 | draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty + TILESIZE - SEP_WIDTH, |
1120 | SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); | ||
1121 | } | ||
1104 | 1122 | ||
1105 | if (tile & CURSOR) | 1123 | if (tile & CURSOR) |
1106 | draw_rect_outline(dr, tx + CURSOR_INSET, ty + CURSOR_INSET, | 1124 | draw_rect_outline(dr, tx + CURSOR_INSET, ty + CURSOR_INSET, |
@@ -1130,13 +1148,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds, | |||
1130 | if (!ds->started) { | 1148 | if (!ds->started) { |
1131 | int coords[10]; | 1149 | int coords[10]; |
1132 | 1150 | ||
1133 | draw_rect(dr, 0, 0, | ||
1134 | TILESIZE * w + 2 * BORDER, | ||
1135 | TILESIZE * h + 2 * BORDER, COL_BACKGROUND); | ||
1136 | draw_update(dr, 0, 0, | ||
1137 | TILESIZE * w + 2 * BORDER, | ||
1138 | TILESIZE * h + 2 * BORDER); | ||
1139 | |||
1140 | /* | 1151 | /* |
1141 | * Recessed area containing the whole puzzle. | 1152 | * Recessed area containing the whole puzzle. |
1142 | */ | 1153 | */ |
@@ -1326,19 +1337,6 @@ static float game_flash_length(const game_state *oldstate, | |||
1326 | return 0.0F; | 1337 | return 0.0F; |
1327 | } | 1338 | } |
1328 | 1339 | ||
1329 | static bool game_timing_state(const game_state *state, game_ui *ui) | ||
1330 | { | ||
1331 | return true; | ||
1332 | } | ||
1333 | |||
1334 | static void game_print_size(const game_params *params, float *x, float *y) | ||
1335 | { | ||
1336 | } | ||
1337 | |||
1338 | static void game_print(drawing *dr, const game_state *state, int tilesize) | ||
1339 | { | ||
1340 | } | ||
1341 | |||
1342 | #ifdef COMBINED | 1340 | #ifdef COMBINED |
1343 | #define thegame flood | 1341 | #define thegame flood |
1344 | #endif | 1342 | #endif |
@@ -1360,12 +1358,14 @@ const struct game thegame = { | |||
1360 | free_game, | 1358 | free_game, |
1361 | true, solve_game, | 1359 | true, solve_game, |
1362 | true, game_can_format_as_text_now, game_text_format, | 1360 | true, game_can_format_as_text_now, game_text_format, |
1361 | NULL, NULL, /* get_prefs, set_prefs */ | ||
1363 | new_ui, | 1362 | new_ui, |
1364 | free_ui, | 1363 | free_ui, |
1365 | encode_ui, | 1364 | NULL, /* encode_ui */ |
1366 | decode_ui, | 1365 | NULL, /* decode_ui */ |
1367 | NULL, /* game_request_keys */ | 1366 | NULL, /* game_request_keys */ |
1368 | game_changed_state, | 1367 | game_changed_state, |
1368 | current_key_label, | ||
1369 | interpret_move, | 1369 | interpret_move, |
1370 | execute_move, | 1370 | execute_move, |
1371 | PREFERRED_TILESIZE, game_compute_size, game_set_size, | 1371 | PREFERRED_TILESIZE, game_compute_size, game_set_size, |
@@ -1377,8 +1377,8 @@ const struct game thegame = { | |||
1377 | game_flash_length, | 1377 | game_flash_length, |
1378 | game_get_cursor_location, | 1378 | game_get_cursor_location, |
1379 | game_status, | 1379 | game_status, |
1380 | false, false, game_print_size, game_print, | 1380 | false, false, NULL, NULL, /* print_size, print */ |
1381 | true, /* wants_statusbar */ | 1381 | true, /* wants_statusbar */ |
1382 | false, game_timing_state, | 1382 | false, NULL, /* timing_state */ |
1383 | 0, /* flags */ | 1383 | 0, /* flags */ |
1384 | }; | 1384 | }; |