summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/src/sixteen.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/puzzles/src/sixteen.c')
-rw-r--r--apps/plugins/puzzles/src/sixteen.c87
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
581static char *encode_ui(const game_ui *ui) 588static void game_changed_state(game_ui *ui, const game_state *oldstate,
582{ 589 const game_state *newstate)
583 return NULL;
584}
585
586static void decode_ui(game_ui *ui, const char *encoding)
587{ 590{
588} 591}
589 592
590static void game_changed_state(game_ui *ui, const game_state *oldstate, 593static 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
595struct game_drawstate { 608struct 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
792static void game_compute_size(const game_params *params, int tilesize, 805static 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
1168static bool game_timing_state(const game_state *state, game_ui *ui)
1169{
1170 return true;
1171}
1172
1173static void game_print_size(const game_params *params, float *x, float *y)
1174{
1175}
1176
1177static 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