X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/6f2d8d7c70f6bbf8bce982ced1fa879e967afbbf..41184c244487c6f50cd174a0a913b02c5255aab9:/cube.c diff --git a/cube.c b/cube.c index 33ef6d3..0ff952f 100644 --- a/cube.c +++ b/cube.c @@ -274,10 +274,8 @@ static game_params *dup_params(game_params *params) return ret; } -static game_params *decode_params(char const *string) +static void decode_params(game_params *ret, char const *string) { - game_params *ret = default_params(); - switch (*string) { case 't': ret->solid = TETRAHEDRON; string++; break; case 'c': ret->solid = CUBE; string++; break; @@ -291,11 +289,9 @@ static game_params *decode_params(char const *string) string++; ret->d2 = atoi(string); } - - return ret; } -static char *encode_params(game_params *params) +static char *encode_params(game_params *params, int full) { char data[256]; @@ -304,10 +300,9 @@ static char *encode_params(game_params *params) return dupstr(data); } +typedef void (*egc_callback)(void *, struct grid_square *); -static void enum_grid_squares(game_params *params, - void (*callback)(void *, struct grid_square *), - void *ctx) +static void enum_grid_squares(game_params *params, egc_callback callback, void *ctx) { const struct solid *solid = solids[params->solid]; @@ -589,13 +584,13 @@ static void classify_grid_square_callback(void *ctx, struct grid_square *sq) data->squareindex++; } -static char *new_game_seed(game_params *params, random_state *rs, - game_aux_info **aux) +static char *new_game_desc(game_params *params, random_state *rs, + game_aux_info **aux, int interactive) { struct grid_data data; int i, j, k, m, area, facesperclass; int *flags; - char *seed, *p; + char *desc, *p; /* * Enumerate the grid squares, dividing them into equivalence @@ -659,8 +654,8 @@ static char *new_game_seed(game_params *params, random_state *rs, * the non-blue squares into a list in the now-unused gridptrs * array. */ - seed = snewn(area / 4 + 40, char); - p = seed; + desc = snewn(area / 4 + 40, char); + p = desc; j = 0; k = 8; m = 0; @@ -688,7 +683,7 @@ static char *new_game_seed(game_params *params, random_state *rs, sfree(data.gridptrs[0]); sfree(flags); - return seed; + return desc; } static void game_free_aux_info(game_aux_info *aux) @@ -844,35 +839,35 @@ static struct solid *transform_poly(const struct solid *solid, int flip, return ret; } -static char *validate_seed(game_params *params, char *seed) +static char *validate_desc(game_params *params, char *desc) { int area = grid_area(params->d1, params->d2, solids[params->solid]->order); int i, j; i = (area + 3) / 4; for (j = 0; j < i; j++) { - int c = seed[j]; + int c = desc[j]; if (c >= '0' && c <= '9') continue; if (c >= 'A' && c <= 'F') continue; if (c >= 'a' && c <= 'f') continue; return "Not enough hex digits at start of string"; - /* NB if seed[j]=='\0' that will also be caught here, so we're safe */ + /* NB if desc[j]=='\0' that will also be caught here, so we're safe */ } - if (seed[i] != ',') + if (desc[i] != ',') return "Expected ',' after hex digits"; i++; do { - if (seed[i] < '0' || seed[i] > '9') + if (desc[i] < '0' || desc[i] > '9') return "Expected decimal integer after ','"; i++; - } while (seed[i]); + } while (desc[i]); return NULL; } -static game_state *new_game(game_params *params, char *seed) +static game_state *new_game(midend_data *me, game_params *params, char *desc) { game_state *state = snew(game_state); int area; @@ -891,10 +886,10 @@ static game_state *new_game(game_params *params, char *seed) /* * Set up the blue squares and polyhedron position according to - * the game seed. + * the game description. */ { - char *p = seed; + char *p = desc; int i, j, v; j = 8; @@ -961,6 +956,7 @@ static game_state *dup_game(game_state *state) memcpy(ret->facecolours, state->facecolours, ret->solid->nfaces * sizeof(int)); ret->nsquares = state->nsquares; + ret->current = state->current; ret->squares = snewn(ret->nsquares, struct grid_square); memcpy(ret->squares, state->squares, ret->nsquares * sizeof(struct grid_square)); @@ -982,9 +978,17 @@ static game_state *dup_game(game_state *state) static void free_game(game_state *state) { + sfree(state->squares); + sfree(state->facecolours); sfree(state); } +static game_state *solve_game(game_state *state, game_aux_info *aux, + char **error) +{ + return NULL; +} + static char *game_text_format(game_state *state) { return NULL; @@ -999,7 +1003,11 @@ static void free_ui(game_ui *ui) { } -static game_state *make_move(game_state *from, game_ui *ui, +struct game_drawstate { + int ox, oy; /* pixel position of float origin */ +}; + +static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, int x, int y, int button) { int direction; @@ -1010,26 +1018,92 @@ static game_state *make_move(game_state *from, game_ui *ui, int i, j, dest, mask; struct solid *poly; + button = button & (~MOD_MASK | MOD_NUM_KEYPAD); + /* - * All moves are made with the cursor keys. + * Moves can be made with the cursor keys or numeric keypad, or + * alternatively you can left-click and the polyhedron will + * move in the general direction of the mouse pointer. */ - if (button == CURSOR_UP) + if (button == CURSOR_UP || button == (MOD_NUM_KEYPAD | '8')) direction = UP; - else if (button == CURSOR_DOWN) + else if (button == CURSOR_DOWN || button == (MOD_NUM_KEYPAD | '2')) direction = DOWN; - else if (button == CURSOR_LEFT) + else if (button == CURSOR_LEFT || button == (MOD_NUM_KEYPAD | '4')) direction = LEFT; - else if (button == CURSOR_RIGHT) + else if (button == CURSOR_RIGHT || button == (MOD_NUM_KEYPAD | '6')) direction = RIGHT; - else if (button == CURSOR_UP_LEFT) + else if (button == (MOD_NUM_KEYPAD | '7')) direction = UP_LEFT; - else if (button == CURSOR_DOWN_LEFT) + else if (button == (MOD_NUM_KEYPAD | '1')) direction = DOWN_LEFT; - else if (button == CURSOR_UP_RIGHT) + else if (button == (MOD_NUM_KEYPAD | '9')) direction = UP_RIGHT; - else if (button == CURSOR_DOWN_RIGHT) + else if (button == (MOD_NUM_KEYPAD | '3')) direction = DOWN_RIGHT; - else + else if (button == LEFT_BUTTON) { + /* + * Find the bearing of the click point from the current + * square's centre. + */ + int cx, cy; + double angle; + + cx = from->squares[from->current].x * GRID_SCALE + ds->ox; + cy = from->squares[from->current].y * GRID_SCALE + ds->oy; + + if (x == cx && y == cy) + return NULL; /* clicked in exact centre! */ + angle = atan2(y - cy, x - cx); + + /* + * There are three possibilities. + * + * - This square is a square, so we choose between UP, + * DOWN, LEFT and RIGHT by dividing the available angle + * at the 45-degree points. + * + * - This square is an up-pointing triangle, so we choose + * between DOWN, LEFT and RIGHT by dividing into + * 120-degree arcs. + * + * - This square is a down-pointing triangle, so we choose + * between UP, LEFT and RIGHT in the inverse manner. + * + * Don't forget that since our y-coordinates increase + * downwards, `angle' is measured _clockwise_ from the + * x-axis, not anticlockwise as most mathematicians would + * instinctively assume. + */ + if (from->squares[from->current].npoints == 4) { + /* Square. */ + if (fabs(angle) > 3*PI/4) + direction = LEFT; + else if (fabs(angle) < PI/4) + direction = RIGHT; + else if (angle > 0) + direction = DOWN; + else + direction = UP; + } else if (from->squares[from->current].directions[UP] == 0) { + /* Up-pointing triangle. */ + if (angle < -PI/2 || angle > 5*PI/6) + direction = LEFT; + else if (angle > PI/6) + direction = DOWN; + else + direction = RIGHT; + } else { + /* Down-pointing triangle. */ + assert(from->squares[from->current].directions[DOWN] == 0); + if (angle > PI/2 || angle < -5*PI/6) + direction = LEFT; + else if (angle < -PI/6) + direction = UP; + else + direction = RIGHT; + } + } else return NULL; /* @@ -1160,6 +1234,7 @@ static game_state *make_move(game_state *from, game_ui *ui, success = align_poly(poly, &from->squares[ret->current], all_pkey); if (!success) { + sfree(poly); angle = -angle; poly = transform_poly(from->solid, from->squares[from->current].flip, @@ -1283,10 +1358,6 @@ struct bbox { float l, r, u, d; }; -struct game_drawstate { - int ox, oy; /* pixel position of float origin */ -}; - static void find_bbox_callback(void *ctx, struct grid_square *sq) { struct bbox *bb = (struct bbox *)ctx; @@ -1503,8 +1574,8 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, } sfree(poly); - draw_update(fe, 0, 0, (int)((bb.r-bb.l+2.0F) * GRID_SCALE), - (int)((bb.d-bb.u+2.0F) * GRID_SCALE)); + game_size(&state->params, &i, &j); + draw_update(fe, 0, 0, i, j); /* * Update the status bar. @@ -1521,13 +1592,13 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, } static float game_anim_length(game_state *oldstate, - game_state *newstate, int dir) + game_state *newstate, int dir, game_ui *ui) { return ROLLTIME; } static float game_flash_length(game_state *oldstate, - game_state *newstate, int dir) + game_state *newstate, int dir, game_ui *ui) { return 0.0F; } @@ -1537,6 +1608,11 @@ static int game_wants_statusbar(void) return TRUE; } +static int game_timing_state(game_state *state) +{ + return TRUE; +} + #ifdef COMBINED #define thegame cube #endif @@ -1551,13 +1627,14 @@ const struct game thegame = { dup_params, TRUE, game_configure, custom_params, validate_params, - new_game_seed, + new_game_desc, game_free_aux_info, - validate_seed, + validate_desc, new_game, dup_game, free_game, - NULL, game_text_format, + FALSE, solve_game, + FALSE, game_text_format, new_ui, free_ui, make_move, @@ -1569,4 +1646,6 @@ const struct game thegame = { game_anim_length, game_flash_length, game_wants_statusbar, + FALSE, game_timing_state, + 0, /* mouse_priorities */ };