diff options
Diffstat (limited to 'apps/plugins/puzzles/src/twiddle.c')
-rw-r--r-- | apps/plugins/puzzles/src/twiddle.c | 108 |
1 files changed, 40 insertions, 68 deletions
diff --git a/apps/plugins/puzzles/src/twiddle.c b/apps/plugins/puzzles/src/twiddle.c index a107925aee..49d8db7825 100644 --- a/apps/plugins/puzzles/src/twiddle.c +++ b/apps/plugins/puzzles/src/twiddle.c | |||
@@ -10,7 +10,12 @@ | |||
10 | #include <string.h> | 10 | #include <string.h> |
11 | #include <assert.h> | 11 | #include <assert.h> |
12 | #include <ctype.h> | 12 | #include <ctype.h> |
13 | #include <math.h> | 13 | #include <limits.h> |
14 | #ifdef NO_TGMATH_H | ||
15 | # include <math.h> | ||
16 | #else | ||
17 | # include <tgmath.h> | ||
18 | #endif | ||
14 | 19 | ||
15 | #include "puzzles.h" | 20 | #include "puzzles.h" |
16 | 21 | ||
@@ -123,14 +128,16 @@ static void decode_params(game_params *ret, char const *string) | |||
123 | while (*string) { | 128 | while (*string) { |
124 | if (*string == 'r') { | 129 | if (*string == 'r') { |
125 | ret->rowsonly = true; | 130 | ret->rowsonly = true; |
131 | string++; | ||
126 | } else if (*string == 'o') { | 132 | } else if (*string == 'o') { |
127 | ret->orientable = true; | 133 | ret->orientable = true; |
134 | string++; | ||
128 | } else if (*string == 'm') { | 135 | } else if (*string == 'm') { |
129 | string++; | 136 | string++; |
130 | ret->movetarget = atoi(string); | 137 | ret->movetarget = atoi(string); |
131 | while (string[1] && isdigit((unsigned char)string[1])) string++; | 138 | while (*string && isdigit((unsigned char)*string)) string++; |
132 | } | 139 | } else |
133 | string++; | 140 | string++; |
134 | } | 141 | } |
135 | } | 142 | } |
136 | 143 | ||
@@ -210,6 +217,8 @@ static const char *validate_params(const game_params *params, bool full) | |||
210 | return "Width must be at least the rotating block size"; | 217 | return "Width must be at least the rotating block size"; |
211 | if (params->h < params->n) | 218 | if (params->h < params->n) |
212 | return "Height must be at least the rotating block size"; | 219 | return "Height must be at least the rotating block size"; |
220 | if (params->w > INT_MAX / params->h) | ||
221 | return "Width times height must not be unreasonably large"; | ||
213 | if (params->movetarget < 0) | 222 | if (params->movetarget < 0) |
214 | return "Number of shuffling moves may not be negative"; | 223 | return "Number of shuffling moves may not be negative"; |
215 | return NULL; | 224 | return NULL; |
@@ -523,18 +532,6 @@ static void free_game(game_state *state) | |||
523 | sfree(state); | 532 | sfree(state); |
524 | } | 533 | } |
525 | 534 | ||
526 | static int compare_int(const void *av, const void *bv) | ||
527 | { | ||
528 | const int *a = (const int *)av; | ||
529 | const int *b = (const int *)bv; | ||
530 | if (*a < *b) | ||
531 | return -1; | ||
532 | else if (*a > *b) | ||
533 | return +1; | ||
534 | else | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | static char *solve_game(const game_state *state, const game_state *currstate, | 535 | static char *solve_game(const game_state *state, const game_state *currstate, |
539 | const char *aux, const char **error) | 536 | const char *aux, const char **error) |
540 | { | 537 | { |
@@ -615,7 +612,7 @@ static game_ui *new_ui(const game_state *state) | |||
615 | 612 | ||
616 | ui->cur_x = 0; | 613 | ui->cur_x = 0; |
617 | ui->cur_y = 0; | 614 | ui->cur_y = 0; |
618 | ui->cur_visible = false; | 615 | ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false); |
619 | 616 | ||
620 | return ui; | 617 | return ui; |
621 | } | 618 | } |
@@ -625,18 +622,20 @@ static void free_ui(game_ui *ui) | |||
625 | sfree(ui); | 622 | sfree(ui); |
626 | } | 623 | } |
627 | 624 | ||
628 | static char *encode_ui(const game_ui *ui) | 625 | static void game_changed_state(game_ui *ui, const game_state *oldstate, |
629 | { | 626 | const game_state *newstate) |
630 | return NULL; | ||
631 | } | ||
632 | |||
633 | static void decode_ui(game_ui *ui, const char *encoding) | ||
634 | { | 627 | { |
635 | } | 628 | } |
636 | 629 | ||
637 | static void game_changed_state(game_ui *ui, const game_state *oldstate, | 630 | static const char *current_key_label(const game_ui *ui, |
638 | const game_state *newstate) | 631 | const game_state *state, int button) |
639 | { | 632 | { |
633 | if (!ui->cur_visible) return ""; | ||
634 | switch (button) { | ||
635 | case CURSOR_SELECT: return "Turn left"; | ||
636 | case CURSOR_SELECT2: return "Turn right"; | ||
637 | } | ||
638 | return ""; | ||
640 | } | 639 | } |
641 | 640 | ||
642 | struct game_drawstate { | 641 | struct game_drawstate { |
@@ -657,18 +656,9 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
657 | 656 | ||
658 | button = button & (~MOD_MASK | MOD_NUM_KEYPAD); | 657 | button = button & (~MOD_MASK | MOD_NUM_KEYPAD); |
659 | 658 | ||
660 | if (IS_CURSOR_MOVE(button)) { | 659 | if (IS_CURSOR_MOVE(button)) |
661 | if (button == CURSOR_LEFT && ui->cur_x > 0) | 660 | return move_cursor(button, &ui->cur_x, &ui->cur_y, w-n+1, h-n+1, |
662 | ui->cur_x--; | 661 | false, &ui->cur_visible); |
663 | if (button == CURSOR_RIGHT && (ui->cur_x+n) < (w)) | ||
664 | ui->cur_x++; | ||
665 | if (button == CURSOR_UP && ui->cur_y > 0) | ||
666 | ui->cur_y--; | ||
667 | if (button == CURSOR_DOWN && (ui->cur_y+n) < (h)) | ||
668 | ui->cur_y++; | ||
669 | ui->cur_visible = true; | ||
670 | return UI_UPDATE; | ||
671 | } | ||
672 | 662 | ||
673 | if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { | 663 | if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { |
674 | /* | 664 | /* |
@@ -691,7 +681,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
691 | dir = (button == CURSOR_SELECT2) ? -1 : +1; | 681 | dir = (button == CURSOR_SELECT2) ? -1 : +1; |
692 | } else { | 682 | } else { |
693 | ui->cur_visible = true; | 683 | ui->cur_visible = true; |
694 | return UI_UPDATE; | 684 | return MOVE_UI_UPDATE; |
695 | } | 685 | } |
696 | } else if (button == 'a' || button == 'A' || button==MOD_NUM_KEYPAD+'7') { | 686 | } else if (button == 'a' || button == 'A' || button==MOD_NUM_KEYPAD+'7') { |
697 | x = y = 0; | 687 | x = y = 0; |
@@ -756,7 +746,7 @@ static game_state *execute_move(const game_state *from, const char *move) | |||
756 | * conveniently being able to get hold of a clean state from | 746 | * conveniently being able to get hold of a clean state from |
757 | * which to practise manoeuvres. | 747 | * which to practise manoeuvres. |
758 | */ | 748 | */ |
759 | qsort(ret->grid, ret->w*ret->h, sizeof(int), compare_int); | 749 | qsort(ret->grid, ret->w*ret->h, sizeof(int), compare_integers); |
760 | for (i = 0; i < ret->w*ret->h; i++) | 750 | for (i = 0; i < ret->w*ret->h; i++) |
761 | ret->grid[i] &= ~3; | 751 | ret->grid[i] &= ~3; |
762 | ret->used_solve = true; | 752 | ret->used_solve = true; |
@@ -791,7 +781,7 @@ static game_state *execute_move(const game_state *from, const char *move) | |||
791 | */ | 781 | */ |
792 | 782 | ||
793 | static void game_compute_size(const game_params *params, int tilesize, | 783 | static void game_compute_size(const game_params *params, int tilesize, |
794 | int *x, int *y) | 784 | const game_ui *ui, int *x, int *y) |
795 | { | 785 | { |
796 | /* Ick: fake up `ds->tilesize' for macro expansion purposes */ | 786 | /* Ick: fake up `ds->tilesize' for macro expansion purposes */ |
797 | struct { int tilesize; } ads, *ds = &ads; | 787 | struct { int tilesize; } ads, *ds = &ads; |
@@ -870,8 +860,8 @@ static void rotate(int *xy, struct rotation *rot) | |||
870 | xf2 = rot->c * xf + rot->s * yf; | 860 | xf2 = rot->c * xf + rot->s * yf; |
871 | yf2 = - rot->s * xf + rot->c * yf; | 861 | yf2 = - rot->s * xf + rot->c * yf; |
872 | 862 | ||
873 | xy[0] = (int)(xf2 + rot->ox + 0.5); /* round to nearest */ | 863 | xy[0] = (int)(xf2 + rot->ox + 0.5F); /* round to nearest */ |
874 | xy[1] = (int)(yf2 + rot->oy + 0.5); /* round to nearest */ | 864 | xy[1] = (int)(yf2 + rot->oy + 0.5F); /* round to nearest */ |
875 | } | 865 | } |
876 | } | 866 | } |
877 | 867 | ||
@@ -1058,7 +1048,7 @@ static int highlight_colour(float angle) | |||
1058 | COL_LOWLIGHT, | 1048 | COL_LOWLIGHT, |
1059 | }; | 1049 | }; |
1060 | 1050 | ||
1061 | return colours[(int)((angle + 2*PI) / (PI/16)) & 31]; | 1051 | return colours[(int)((angle + 2*(float)PI) / ((float)PI/16)) & 31]; |
1062 | } | 1052 | } |
1063 | 1053 | ||
1064 | static float game_anim_length_real(const game_state *oldstate, | 1054 | static float game_anim_length_real(const game_state *oldstate, |
@@ -1135,13 +1125,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds, | |||
1135 | if (!ds->started) { | 1125 | if (!ds->started) { |
1136 | int coords[10]; | 1126 | int coords[10]; |
1137 | 1127 | ||
1138 | draw_rect(dr, 0, 0, | ||
1139 | TILE_SIZE * state->w + 2 * BORDER, | ||
1140 | TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND); | ||
1141 | draw_update(dr, 0, 0, | ||
1142 | TILE_SIZE * state->w + 2 * BORDER, | ||
1143 | TILE_SIZE * state->h + 2 * BORDER); | ||
1144 | |||
1145 | /* | 1128 | /* |
1146 | * Recessed area containing the whole puzzle. | 1129 | * Recessed area containing the whole puzzle. |
1147 | */ | 1130 | */ |
@@ -1189,7 +1172,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds, | |||
1189 | rot->cw = rot->ch = TILE_SIZE * state->n; | 1172 | rot->cw = rot->ch = TILE_SIZE * state->n; |
1190 | rot->ox = rot->cx + rot->cw/2; | 1173 | rot->ox = rot->cx + rot->cw/2; |
1191 | rot->oy = rot->cy + rot->ch/2; | 1174 | rot->oy = rot->cy + rot->ch/2; |
1192 | angle = (float)((-PI/2 * lastr) * (1.0 - animtime / anim_max)); | 1175 | angle = ((-(float)PI/2 * lastr) * (1.0F - animtime / anim_max)); |
1193 | rot->c = (float)cos(angle); | 1176 | rot->c = (float)cos(angle); |
1194 | rot->s = (float)sin(angle); | 1177 | rot->s = (float)sin(angle); |
1195 | 1178 | ||
@@ -1282,19 +1265,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds, | |||
1282 | } | 1265 | } |
1283 | } | 1266 | } |
1284 | 1267 | ||
1285 | static bool game_timing_state(const game_state *state, game_ui *ui) | ||
1286 | { | ||
1287 | return true; | ||
1288 | } | ||
1289 | |||
1290 | static void game_print_size(const game_params *params, float *x, float *y) | ||
1291 | { | ||
1292 | } | ||
1293 | |||
1294 | static void game_print(drawing *dr, const game_state *state, int tilesize) | ||
1295 | { | ||
1296 | } | ||
1297 | |||
1298 | #ifdef COMBINED | 1268 | #ifdef COMBINED |
1299 | #define thegame twiddle | 1269 | #define thegame twiddle |
1300 | #endif | 1270 | #endif |
@@ -1316,12 +1286,14 @@ const struct game thegame = { | |||
1316 | free_game, | 1286 | free_game, |
1317 | true, solve_game, | 1287 | true, solve_game, |
1318 | true, game_can_format_as_text_now, game_text_format, | 1288 | true, game_can_format_as_text_now, game_text_format, |
1289 | NULL, NULL, /* get_prefs, set_prefs */ | ||
1319 | new_ui, | 1290 | new_ui, |
1320 | free_ui, | 1291 | free_ui, |
1321 | encode_ui, | 1292 | NULL, /* encode_ui */ |
1322 | decode_ui, | 1293 | NULL, /* decode_ui */ |
1323 | NULL, /* game_request_keys */ | 1294 | NULL, /* game_request_keys */ |
1324 | game_changed_state, | 1295 | game_changed_state, |
1296 | current_key_label, | ||
1325 | interpret_move, | 1297 | interpret_move, |
1326 | execute_move, | 1298 | execute_move, |
1327 | PREFERRED_TILE_SIZE, game_compute_size, game_set_size, | 1299 | PREFERRED_TILE_SIZE, game_compute_size, game_set_size, |
@@ -1333,9 +1305,9 @@ const struct game thegame = { | |||
1333 | game_flash_length, | 1305 | game_flash_length, |
1334 | game_get_cursor_location, | 1306 | game_get_cursor_location, |
1335 | game_status, | 1307 | game_status, |
1336 | false, false, game_print_size, game_print, | 1308 | false, false, NULL, NULL, /* print_size, print */ |
1337 | true, /* wants_statusbar */ | 1309 | true, /* wants_statusbar */ |
1338 | false, game_timing_state, | 1310 | false, NULL, /* timing_state */ |
1339 | 0, /* flags */ | 1311 | 0, /* flags */ |
1340 | }; | 1312 | }; |
1341 | 1313 | ||