diff options
Diffstat (limited to 'apps/plugins/puzzles/src/sixteen.c')
-rw-r--r-- | apps/plugins/puzzles/src/sixteen.c | 87 |
1 files changed, 41 insertions, 46 deletions
diff --git a/apps/plugins/puzzles/src/sixteen.c b/apps/plugins/puzzles/src/sixteen.c index 0b02038c43..38f6711a49 100644 --- a/apps/plugins/puzzles/src/sixteen.c +++ b/apps/plugins/puzzles/src/sixteen.c | |||
@@ -9,7 +9,12 @@ | |||
9 | #include <string.h> | 9 | #include <string.h> |
10 | #include <assert.h> | 10 | #include <assert.h> |
11 | #include <ctype.h> | 11 | #include <ctype.h> |
12 | #include <math.h> | 12 | #include <limits.h> |
13 | #ifdef NO_TGMATH_H | ||
14 | # include <math.h> | ||
15 | #else | ||
16 | # include <tgmath.h> | ||
17 | #endif | ||
13 | 18 | ||
14 | #include "puzzles.h" | 19 | #include "puzzles.h" |
15 | 20 | ||
@@ -173,6 +178,8 @@ static const char *validate_params(const game_params *params, bool full) | |||
173 | { | 178 | { |
174 | if (params->w < 2 || params->h < 2) | 179 | if (params->w < 2 || params->h < 2) |
175 | return "Width and height must both be at least two"; | 180 | return "Width and height must both be at least two"; |
181 | if (params->w > INT_MAX / params->h) | ||
182 | return "Width times height must not be unreasonably large"; | ||
176 | if (params->movetarget < 0) | 183 | if (params->movetarget < 0) |
177 | return "Number of shuffling moves may not be negative"; | 184 | return "Number of shuffling moves may not be negative"; |
178 | return NULL; | 185 | return NULL; |
@@ -567,7 +574,7 @@ static game_ui *new_ui(const game_state *state) | |||
567 | game_ui *ui = snew(game_ui); | 574 | game_ui *ui = snew(game_ui); |
568 | ui->cur_x = 0; | 575 | ui->cur_x = 0; |
569 | ui->cur_y = 0; | 576 | ui->cur_y = 0; |
570 | ui->cur_visible = false; | 577 | ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false); |
571 | ui->cur_mode = unlocked; | 578 | ui->cur_mode = unlocked; |
572 | 579 | ||
573 | return ui; | 580 | return ui; |
@@ -578,18 +585,24 @@ static void free_ui(game_ui *ui) | |||
578 | sfree(ui); | 585 | sfree(ui); |
579 | } | 586 | } |
580 | 587 | ||
581 | static char *encode_ui(const game_ui *ui) | 588 | static void game_changed_state(game_ui *ui, const game_state *oldstate, |
582 | { | 589 | const game_state *newstate) |
583 | return NULL; | ||
584 | } | ||
585 | |||
586 | static void decode_ui(game_ui *ui, const char *encoding) | ||
587 | { | 590 | { |
588 | } | 591 | } |
589 | 592 | ||
590 | static void game_changed_state(game_ui *ui, const game_state *oldstate, | 593 | static const char *current_key_label(const game_ui *ui, |
591 | const game_state *newstate) | 594 | const game_state *state, int button) |
592 | { | 595 | { |
596 | if (IS_CURSOR_SELECT(button) && ui->cur_visible) { | ||
597 | if (ui->cur_x == -1 || ui->cur_x == state->w || | ||
598 | ui->cur_y == -1 || ui->cur_y == state->h) | ||
599 | return button == CURSOR_SELECT2 ? "Back" : "Slide"; | ||
600 | if (button == CURSOR_SELECT) | ||
601 | return ui->cur_mode == lock_tile ? "Unlock" : "Lock tile"; | ||
602 | if (button == CURSOR_SELECT2) | ||
603 | return ui->cur_mode == lock_position ? "Unlock" : "Lock pos"; | ||
604 | } | ||
605 | return ""; | ||
593 | } | 606 | } |
594 | 607 | ||
595 | struct game_drawstate { | 608 | struct game_drawstate { |
@@ -609,12 +622,12 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
609 | bool shift = button & MOD_SHFT, control = button & MOD_CTRL; | 622 | bool shift = button & MOD_SHFT, control = button & MOD_CTRL; |
610 | int pad = button & MOD_NUM_KEYPAD; | 623 | int pad = button & MOD_NUM_KEYPAD; |
611 | 624 | ||
612 | button &= ~MOD_MASK; | 625 | button = STRIP_BUTTON_MODIFIERS(button); |
613 | 626 | ||
614 | if (IS_CURSOR_MOVE(button) || pad) { | 627 | if (IS_CURSOR_MOVE(button) || pad) { |
615 | if (!ui->cur_visible) { | 628 | if (!ui->cur_visible) { |
616 | ui->cur_visible = true; | 629 | ui->cur_visible = true; |
617 | return UI_UPDATE; | 630 | return MOVE_UI_UPDATE; |
618 | } | 631 | } |
619 | 632 | ||
620 | if (control || shift || ui->cur_mode) { | 633 | if (control || shift || ui->cur_mode) { |
@@ -622,9 +635,9 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
622 | if (x < 0 || x >= state->w || y < 0 || y >= state->h) | 635 | if (x < 0 || x >= state->w || y < 0 || y >= state->h) |
623 | return NULL; | 636 | return NULL; |
624 | move_cursor(button | pad, &x, &y, | 637 | move_cursor(button | pad, &x, &y, |
625 | state->w, state->h, false); | 638 | state->w, state->h, false, NULL); |
626 | move_cursor(button | pad, &xwrap, &ywrap, | 639 | move_cursor(button | pad, &xwrap, &ywrap, |
627 | state->w, state->h, true); | 640 | state->w, state->h, true, NULL); |
628 | 641 | ||
629 | if (x != xwrap) { | 642 | if (x != xwrap) { |
630 | sprintf(buf, "R%d,%c1", y, x ? '+' : '-'); | 643 | sprintf(buf, "R%d,%c1", y, x ? '+' : '-'); |
@@ -645,7 +658,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
645 | int x = ui->cur_x + 1, y = ui->cur_y + 1; | 658 | int x = ui->cur_x + 1, y = ui->cur_y + 1; |
646 | 659 | ||
647 | move_cursor(button | pad, &x, &y, | 660 | move_cursor(button | pad, &x, &y, |
648 | state->w + 2, state->h + 2, false); | 661 | state->w + 2, state->h + 2, false, NULL); |
649 | 662 | ||
650 | if (x == 0 && y == 0) { | 663 | if (x == 0 && y == 0) { |
651 | int t = ui->cur_x; | 664 | int t = ui->cur_x; |
@@ -669,7 +682,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
669 | } | 682 | } |
670 | 683 | ||
671 | ui->cur_visible = true; | 684 | ui->cur_visible = true; |
672 | return UI_UPDATE; | 685 | return MOVE_UI_UPDATE; |
673 | } | 686 | } |
674 | } | 687 | } |
675 | 688 | ||
@@ -687,11 +700,11 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
687 | const enum cursor_mode m = (button == CURSOR_SELECT2 ? | 700 | const enum cursor_mode m = (button == CURSOR_SELECT2 ? |
688 | lock_position : lock_tile); | 701 | lock_position : lock_tile); |
689 | ui->cur_mode = (ui->cur_mode == m ? unlocked : m); | 702 | ui->cur_mode = (ui->cur_mode == m ? unlocked : m); |
690 | return UI_UPDATE; | 703 | return MOVE_UI_UPDATE; |
691 | } | 704 | } |
692 | } else { | 705 | } else { |
693 | ui->cur_visible = true; | 706 | ui->cur_visible = true; |
694 | return UI_UPDATE; | 707 | return MOVE_UI_UPDATE; |
695 | } | 708 | } |
696 | } else { | 709 | } else { |
697 | return NULL; | 710 | return NULL; |
@@ -706,7 +719,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, | |||
706 | else if (cy == state->h && cx >= 0 && cx < state->w) | 719 | else if (cy == state->h && cx >= 0 && cx < state->w) |
707 | dy = +1, dx = 0; | 720 | dy = +1, dx = 0; |
708 | else | 721 | else |
709 | return UI_UPDATE; /* invalid click location */ | 722 | return MOVE_UI_UPDATE; /* invalid click location */ |
710 | 723 | ||
711 | /* reverse direction if right hand button is pressed */ | 724 | /* reverse direction if right hand button is pressed */ |
712 | if (button == RIGHT_BUTTON || button == CURSOR_SELECT2) { | 725 | if (button == RIGHT_BUTTON || button == CURSOR_SELECT2) { |
@@ -748,11 +761,11 @@ static game_state *execute_move(const game_state *from, const char *move) | |||
748 | } | 761 | } |
749 | 762 | ||
750 | if (move[0] == 'R' && sscanf(move+1, "%d,%d", &cy, &dx) == 2 && | 763 | if (move[0] == 'R' && sscanf(move+1, "%d,%d", &cy, &dx) == 2 && |
751 | cy >= 0 && cy < from->h) { | 764 | cy >= 0 && cy < from->h && -from->h <= dx && dx <= from->w ) { |
752 | cx = dy = 0; | 765 | cx = dy = 0; |
753 | n = from->w; | 766 | n = from->w; |
754 | } else if (move[0] == 'C' && sscanf(move+1, "%d,%d", &cx, &dy) == 2 && | 767 | } else if (move[0] == 'C' && sscanf(move+1, "%d,%d", &cx, &dy) == 2 && |
755 | cx >= 0 && cx < from->w) { | 768 | cx >= 0 && cx < from->w && -from->h <= dy && dy <= from->h) { |
756 | cy = dx = 0; | 769 | cy = dx = 0; |
757 | n = from->h; | 770 | n = from->h; |
758 | } else | 771 | } else |
@@ -790,7 +803,7 @@ static game_state *execute_move(const game_state *from, const char *move) | |||
790 | */ | 803 | */ |
791 | 804 | ||
792 | static void game_compute_size(const game_params *params, int tilesize, | 805 | static void game_compute_size(const game_params *params, int tilesize, |
793 | int *x, int *y) | 806 | const game_ui *ui, int *x, int *y) |
794 | { | 807 | { |
795 | /* Ick: fake up `ds->tilesize' for macro expansion purposes */ | 808 | /* Ick: fake up `ds->tilesize' for macro expansion purposes */ |
796 | struct { int tilesize; } ads, *ds = &ads; | 809 | struct { int tilesize; } ads, *ds = &ads; |
@@ -937,13 +950,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds, | |||
937 | if (!ds->started) { | 950 | if (!ds->started) { |
938 | int coords[10]; | 951 | int coords[10]; |
939 | 952 | ||
940 | draw_rect(dr, 0, 0, | ||
941 | TILE_SIZE * state->w + 2 * BORDER, | ||
942 | TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND); | ||
943 | draw_update(dr, 0, 0, | ||
944 | TILE_SIZE * state->w + 2 * BORDER, | ||
945 | TILE_SIZE * state->h + 2 * BORDER); | ||
946 | |||
947 | /* | 953 | /* |
948 | * Recessed area containing the whole puzzle. | 954 | * Recessed area containing the whole puzzle. |
949 | */ | 955 | */ |
@@ -1165,19 +1171,6 @@ static int game_status(const game_state *state) | |||
1165 | return state->completed ? +1 : 0; | 1171 | return state->completed ? +1 : 0; |
1166 | } | 1172 | } |
1167 | 1173 | ||
1168 | static bool game_timing_state(const game_state *state, game_ui *ui) | ||
1169 | { | ||
1170 | return true; | ||
1171 | } | ||
1172 | |||
1173 | static void game_print_size(const game_params *params, float *x, float *y) | ||
1174 | { | ||
1175 | } | ||
1176 | |||
1177 | static void game_print(drawing *dr, const game_state *state, int tilesize) | ||
1178 | { | ||
1179 | } | ||
1180 | |||
1181 | #ifdef COMBINED | 1174 | #ifdef COMBINED |
1182 | #define thegame sixteen | 1175 | #define thegame sixteen |
1183 | #endif | 1176 | #endif |
@@ -1199,12 +1192,14 @@ const struct game thegame = { | |||
1199 | free_game, | 1192 | free_game, |
1200 | true, solve_game, | 1193 | true, solve_game, |
1201 | true, game_can_format_as_text_now, game_text_format, | 1194 | true, game_can_format_as_text_now, game_text_format, |
1195 | NULL, NULL, /* get_prefs, set_prefs */ | ||
1202 | new_ui, | 1196 | new_ui, |
1203 | free_ui, | 1197 | free_ui, |
1204 | encode_ui, | 1198 | NULL, /* encode_ui */ |
1205 | decode_ui, | 1199 | NULL, /* decode_ui */ |
1206 | NULL, /* game_request_keys */ | 1200 | NULL, /* game_request_keys */ |
1207 | game_changed_state, | 1201 | game_changed_state, |
1202 | current_key_label, | ||
1208 | interpret_move, | 1203 | interpret_move, |
1209 | execute_move, | 1204 | execute_move, |
1210 | PREFERRED_TILE_SIZE, game_compute_size, game_set_size, | 1205 | PREFERRED_TILE_SIZE, game_compute_size, game_set_size, |
@@ -1216,9 +1211,9 @@ const struct game thegame = { | |||
1216 | game_flash_length, | 1211 | game_flash_length, |
1217 | game_get_cursor_location, | 1212 | game_get_cursor_location, |
1218 | game_status, | 1213 | game_status, |
1219 | false, false, game_print_size, game_print, | 1214 | false, false, NULL, NULL, /* print_size, print */ |
1220 | true, /* wants_statusbar */ | 1215 | true, /* wants_statusbar */ |
1221 | false, game_timing_state, | 1216 | false, NULL, /* timing_state */ |
1222 | 0, /* flags */ | 1217 | 0, /* flags */ |
1223 | }; | 1218 | }; |
1224 | 1219 | ||