summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/src/cube.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/puzzles/src/cube.c')
-rw-r--r--apps/plugins/puzzles/src/cube.c110
1 files changed, 52 insertions, 58 deletions
diff --git a/apps/plugins/puzzles/src/cube.c b/apps/plugins/puzzles/src/cube.c
index 8c8c46faed..08788cbd65 100644
--- a/apps/plugins/puzzles/src/cube.c
+++ b/apps/plugins/puzzles/src/cube.c
@@ -7,7 +7,11 @@
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#ifdef NO_TGMATH_H
11# include <math.h>
12#else
13# include <tgmath.h>
14#endif
11 15
12#include "puzzles.h" 16#include "puzzles.h"
13 17
@@ -171,7 +175,7 @@ enum { LEFT, RIGHT, UP, DOWN, UP_LEFT, UP_RIGHT, DOWN_LEFT, DOWN_RIGHT };
171 (ra)[0] = rx; (ra)[1] = ry; (ra)[2] = rz; \ 175 (ra)[0] = rx; (ra)[1] = ry; (ra)[2] = rz; \
172} while (0) 176} while (0)
173 177
174#define APPROXEQ(x,y) ( SQ(x-y) < 0.1 ) 178#define APPROXEQ(x,y) ( SQ(x-y) < 0.1F )
175 179
176struct grid_square { 180struct grid_square {
177 float x, y; 181 float x, y;
@@ -202,8 +206,8 @@ struct game_grid {
202}; 206};
203 207
204#define SET_SQUARE(state, i, val) \ 208#define SET_SQUARE(state, i, val) \
205 ((state)->bluemask[(i)/32] &= ~(1 << ((i)%32)), \ 209 ((state)->bluemask[(i)/32] &= ~(1UL << ((i)%32)), \
206 (state)->bluemask[(i)/32] |= ((!!val) << ((i)%32))) 210 (state)->bluemask[(i)/32] |= ((unsigned long)(!!val) << ((i)%32)))
207#define GET_SQUARE(state, i) \ 211#define GET_SQUARE(state, i) \
208 (((state)->bluemask[(i)/32] >> ((i)%32)) & 1) 212 (((state)->bluemask[(i)/32] >> ((i)%32)) & 1)
209 213
@@ -542,12 +546,38 @@ static const char *validate_params(const game_params *params, bool full)
542 if (params->solid < 0 || params->solid >= lenof(solids)) 546 if (params->solid < 0 || params->solid >= lenof(solids))
543 return "Unrecognised solid type"; 547 return "Unrecognised solid type";
544 548
549 if (params->d1 < 0 || params->d2 < 0)
550 return "Grid dimensions may not be negative";
551
545 if (solids[params->solid]->order == 4) { 552 if (solids[params->solid]->order == 4) {
546 if (params->d1 <= 1 || params->d2 <= 1) 553 if (params->d1 <= 1 || params->d2 <= 1)
547 return "Both grid dimensions must be greater than one"; 554 return "Both grid dimensions must be greater than one";
555 if (params->d2 > INT_MAX / params->d1)
556 return "Grid area must not be unreasonably large";
548 } else { 557 } else {
549 if (params->d1 <= 0 && params->d2 <= 0) 558 if (params->d1 <= 0 && params->d2 <= 0)
550 return "At least one grid dimension must be greater than zero"; 559 return "At least one grid dimension must be greater than zero";
560
561 /*
562 * Check whether d1^2 + d2^2 + 4 d1 d2 > INT_MAX, without overflow:
563 *
564 * First check d1^2 doesn't overflow by itself.
565 *
566 * Then check d2^2 doesn't exceed the remaining space between
567 * d1^2 and INT_MAX.
568 *
569 * If that's all OK then we know both d1 and d2 are
570 * individually less than the square root of INT_MAX, so we
571 * can safely multiply them and compare against the
572 * _remaining_ space.
573 */
574 if ((params->d1 > 0 && params->d1 > INT_MAX / params->d1) ||
575 (params->d2 > 0 &&
576 params->d2 > (INT_MAX - params->d1*params->d1) / params->d2) ||
577 (params->d2 > 0 &&
578 params->d1*params->d2 > (INT_MAX - params->d1*params->d1 -
579 params->d2*params->d2) / params->d2))
580 return "Grid area must not be unreasonably large";
551 } 581 }
552 582
553 for (i = 0; i < 4; i++) 583 for (i = 0; i < 4; i++)
@@ -761,7 +791,7 @@ static bool align_poly(const struct solid *solid, struct grid_square *sq,
761 dist += SQ(solid->vertices[i*3+1] * flip - sq->points[j*2+1] + sq->y); 791 dist += SQ(solid->vertices[i*3+1] * flip - sq->points[j*2+1] + sq->y);
762 dist += SQ(solid->vertices[i*3+2] - zmin); 792 dist += SQ(solid->vertices[i*3+2] - zmin);
763 793
764 if (dist < 0.1) { 794 if (dist < 0.1F) {
765 matches++; 795 matches++;
766 index = i; 796 index = i;
767 } 797 }
@@ -811,7 +841,7 @@ static struct solid *transform_poly(const struct solid *solid, bool flip,
811 */ 841 */
812 vx = ret->vertices[key1*3+0] - ret->vertices[key0*3+0]; 842 vx = ret->vertices[key1*3+0] - ret->vertices[key0*3+0];
813 vy = ret->vertices[key1*3+1] - ret->vertices[key0*3+1]; 843 vy = ret->vertices[key1*3+1] - ret->vertices[key0*3+1];
814 assert(APPROXEQ(vx*vx + vy*vy, 1.0)); 844 assert(APPROXEQ(vx*vx + vy*vy, 1.0F));
815 845
816 vmatrix[0] = vx; vmatrix[3] = vy; vmatrix[6] = 0; 846 vmatrix[0] = vx; vmatrix[3] = vy; vmatrix[6] = 0;
817 vmatrix[1] = -vy; vmatrix[4] = vx; vmatrix[7] = 0; 847 vmatrix[1] = -vy; vmatrix[4] = vx; vmatrix[7] = 0;
@@ -999,22 +1029,6 @@ static void free_game(game_state *state)
999 sfree(state); 1029 sfree(state);
1000} 1030}
1001 1031
1002static char *solve_game(const game_state *state, const game_state *currstate,
1003 const char *aux, const char **error)
1004{
1005 return NULL;
1006}
1007
1008static bool game_can_format_as_text_now(const game_params *params)
1009{
1010 return true;
1011}
1012
1013static char *game_text_format(const game_state *state)
1014{
1015 return NULL;
1016}
1017
1018static game_ui *new_ui(const game_state *state) 1032static game_ui *new_ui(const game_state *state)
1019{ 1033{
1020 return NULL; 1034 return NULL;
@@ -1024,15 +1038,6 @@ static void free_ui(game_ui *ui)
1024{ 1038{
1025} 1039}
1026 1040
1027static char *encode_ui(const game_ui *ui)
1028{
1029 return NULL;
1030}
1031
1032static void decode_ui(game_ui *ui, const char *encoding)
1033{
1034}
1035
1036static void game_changed_state(game_ui *ui, const game_state *oldstate, 1041static void game_changed_state(game_ui *ui, const game_state *oldstate,
1037 const game_state *newstate) 1042 const game_state *newstate)
1038{ 1043{
@@ -1081,11 +1086,11 @@ static int find_move_dest(const game_state *from, int direction,
1081 for (j = 0; j < from->grid->squares[i].npoints; j++) { 1086 for (j = 0; j < from->grid->squares[i].npoints; j++) {
1082 dist = (SQ(from->grid->squares[i].points[j*2] - points[0]) + 1087 dist = (SQ(from->grid->squares[i].points[j*2] - points[0]) +
1083 SQ(from->grid->squares[i].points[j*2+1] - points[1])); 1088 SQ(from->grid->squares[i].points[j*2+1] - points[1]));
1084 if (dist < 0.1) 1089 if (dist < 0.1F)
1085 dkey[match++] = j; 1090 dkey[match++] = j;
1086 dist = (SQ(from->grid->squares[i].points[j*2] - points[2]) + 1091 dist = (SQ(from->grid->squares[i].points[j*2] - points[2]) +
1087 SQ(from->grid->squares[i].points[j*2+1] - points[3])); 1092 SQ(from->grid->squares[i].points[j*2+1] - points[3]));
1088 if (dist < 0.1) 1093 if (dist < 0.1F)
1089 dkey[match++] = j; 1094 dkey[match++] = j;
1090 } 1095 }
1091 1096
@@ -1140,7 +1145,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1140 cy = (int)(state->grid->squares[state->current].y * GRID_SCALE) + ds->oy; 1145 cy = (int)(state->grid->squares[state->current].y * GRID_SCALE) + ds->oy;
1141 1146
1142 if (x == cx && y == cy) 1147 if (x == cx && y == cy)
1143 return NULL; /* clicked in exact centre! */ 1148 return MOVE_NO_EFFECT; /* clicked in exact centre! */
1144 angle = atan2(y - cy, x - cx); 1149 angle = atan2(y - cy, x - cx);
1145 1150
1146 /* 1151 /*
@@ -1191,11 +1196,11 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1191 direction = RIGHT; 1196 direction = RIGHT;
1192 } 1197 }
1193 } else 1198 } else
1194 return NULL; 1199 return MOVE_UNUSED;
1195 1200
1196 mask = state->grid->squares[state->current].directions[direction]; 1201 mask = state->grid->squares[state->current].directions[direction];
1197 if (mask == 0) 1202 if (mask == 0)
1198 return NULL; 1203 return MOVE_NO_EFFECT;
1199 1204
1200 /* 1205 /*
1201 * Translate diagonal directions into orthogonal ones. 1206 * Translate diagonal directions into orthogonal ones.
@@ -1210,14 +1215,14 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1210 } 1215 }
1211 1216
1212 if (find_move_dest(state, direction, skey, dkey) < 0) 1217 if (find_move_dest(state, direction, skey, dkey) < 0)
1213 return NULL; 1218 return MOVE_NO_EFFECT;
1214 1219
1215 if (direction == LEFT) return dupstr("L"); 1220 if (direction == LEFT) return dupstr("L");
1216 if (direction == RIGHT) return dupstr("R"); 1221 if (direction == RIGHT) return dupstr("R");
1217 if (direction == UP) return dupstr("U"); 1222 if (direction == UP) return dupstr("U");
1218 if (direction == DOWN) return dupstr("D"); 1223 if (direction == DOWN) return dupstr("D");
1219 1224
1220 return NULL; /* should never happen */ 1225 return MOVE_NO_EFFECT; /* should never happen */
1221} 1226}
1222 1227
1223static game_state *execute_move(const game_state *from, const char *move) 1228static game_state *execute_move(const game_state *from, const char *move)
@@ -1484,7 +1489,7 @@ static struct bbox find_bbox(const game_params *params)
1484 ((int)(((bb).d - (bb).u + 2*(solid)->border) * gs)) 1489 ((int)(((bb).d - (bb).u + 2*(solid)->border) * gs))
1485 1490
1486static void game_compute_size(const game_params *params, int tilesize, 1491static void game_compute_size(const game_params *params, int tilesize,
1487 int *x, int *y) 1492 const game_ui *ui, int *x, int *y)
1488{ 1493{
1489 struct bbox bb = find_bbox(params); 1494 struct bbox bb = find_bbox(params);
1490 1495
@@ -1734,19 +1739,6 @@ static int game_status(const game_state *state)
1734 return state->completed ? +1 : 0; 1739 return state->completed ? +1 : 0;
1735} 1740}
1736 1741
1737static bool game_timing_state(const game_state *state, game_ui *ui)
1738{
1739 return true;
1740}
1741
1742static void game_print_size(const game_params *params, float *x, float *y)
1743{
1744}
1745
1746static void game_print(drawing *dr, const game_state *state, int tilesize)
1747{
1748}
1749
1750#ifdef COMBINED 1742#ifdef COMBINED
1751#define thegame cube 1743#define thegame cube
1752#endif 1744#endif
@@ -1766,14 +1758,16 @@ const struct game thegame = {
1766 new_game, 1758 new_game,
1767 dup_game, 1759 dup_game,
1768 free_game, 1760 free_game,
1769 false, solve_game, 1761 false, NULL, /* solve */
1770 false, game_can_format_as_text_now, game_text_format, 1762 false, NULL, NULL, /* can_format_as_text_now, text_format */
1763 NULL, NULL, /* get_prefs, set_prefs */
1771 new_ui, 1764 new_ui,
1772 free_ui, 1765 free_ui,
1773 encode_ui, 1766 NULL, /* encode_ui */
1774 decode_ui, 1767 NULL, /* decode_ui */
1775 NULL, /* game_request_keys */ 1768 NULL, /* game_request_keys */
1776 game_changed_state, 1769 game_changed_state,
1770 NULL, /* current_key_label */
1777 interpret_move, 1771 interpret_move,
1778 execute_move, 1772 execute_move,
1779 PREFERRED_GRID_SCALE, game_compute_size, game_set_size, 1773 PREFERRED_GRID_SCALE, game_compute_size, game_set_size,
@@ -1785,8 +1779,8 @@ const struct game thegame = {
1785 game_flash_length, 1779 game_flash_length,
1786 game_get_cursor_location, 1780 game_get_cursor_location,
1787 game_status, 1781 game_status,
1788 false, false, game_print_size, game_print, 1782 false, false, NULL, NULL, /* print_size, print */
1789 true, /* wants_statusbar */ 1783 true, /* wants_statusbar */
1790 false, game_timing_state, 1784 false, NULL, /* timing_state */
1791 0, /* flags */ 1785 0, /* flags */
1792}; 1786};