X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/87ed82be805fe13d9f29dca16e867eaeb9a3fd24..d3a026ed4258c207b6309802cc2c92eb0a812aac:/cube.c diff --git a/cube.c b/cube.c index 1bc08f6..c867471 100644 --- a/cube.c +++ b/cube.c @@ -11,6 +11,7 @@ #include "puzzles.h" const char *const game_name = "Cube"; +const int game_can_configure = TRUE; #define MAXVERTICES 20 #define MAXFACES 20 @@ -238,8 +239,8 @@ int game_fetch_preset(int i, char **name, game_params **params) case 1: str = "Tetrahedron"; ret->solid = TETRAHEDRON; - ret->d1 = 2; - ret->d2 = 1; + ret->d1 = 1; + ret->d2 = 2; break; case 2: str = "Octahedron"; @@ -324,12 +325,12 @@ static void enum_grid_squares(game_params *params, float theight = (float)(sqrt(3) / 2.0); for (row = 0; row < params->d1 + params->d2; row++) { - if (row < params->d1) { + if (row < params->d2) { other = +1; - rowlen = row + params->d2; + rowlen = row + params->d1; } else { other = -1; - rowlen = 2*params->d1 + params->d2 - row; + rowlen = 2*params->d2 + params->d1 - row; } /* @@ -415,7 +416,7 @@ static void enum_grid_squares(game_params *params, sq.flip = FALSE; if (firstix < 0) - firstix = ix; + firstix = (ix - 1) & 3; ix -= firstix; sq.tetra_class = ((row+(ix&1)) & 2) ^ (ix & 3); @@ -443,6 +444,99 @@ static int grid_area(int d1, int d2, int order) return d1*d1 + d2*d2 + 4*d1*d2; } +config_item *game_configure(game_params *params) +{ + config_item *ret = snewn(4, config_item); + char buf[80]; + + ret[0].name = "Type of solid"; + ret[0].type = C_CHOICES; + ret[0].sval = ":Tetrahedron:Cube:Octahedron:Icosahedron"; + ret[0].ival = params->solid; + + ret[1].name = "Width / top"; + ret[1].type = C_STRING; + sprintf(buf, "%d", params->d1); + ret[1].sval = dupstr(buf); + ret[1].ival = 0; + + ret[2].name = "Height / bottom"; + ret[2].type = C_STRING; + sprintf(buf, "%d", params->d2); + ret[2].sval = dupstr(buf); + ret[2].ival = 0; + + ret[3].name = NULL; + ret[3].type = C_END; + ret[3].sval = NULL; + ret[3].ival = 0; + + return ret; +} + +game_params *custom_params(config_item *cfg) +{ + game_params *ret = snew(game_params); + + ret->solid = cfg[0].ival; + ret->d1 = atoi(cfg[1].sval); + ret->d2 = atoi(cfg[2].sval); + + return ret; +} + +static void count_grid_square_callback(void *ctx, struct grid_square *sq) +{ + int *classes = (int *)ctx; + int thisclass; + + if (classes[4] == 4) + thisclass = sq->tetra_class; + else if (classes[4] == 2) + thisclass = sq->flip; + else + thisclass = 0; + + classes[thisclass]++; +} + +char *validate_params(game_params *params) +{ + int classes[5]; + int i; + + if (params->solid < 0 || params->solid >= lenof(solids)) + return "Unrecognised solid type"; + + if (solids[params->solid]->order == 4) { + if (params->d1 <= 0 || params->d2 <= 0) + return "Both grid dimensions must be greater than zero"; + } else { + if (params->d1 <= 0 && params->d2 <= 0) + return "At least one grid dimension must be greater than zero"; + } + + for (i = 0; i < 4; i++) + classes[i] = 0; + if (params->solid == TETRAHEDRON) + classes[4] = 4; + else if (params->solid == OCTAHEDRON) + classes[4] = 2; + else + classes[4] = 1; + enum_grid_squares(params, count_grid_square_callback, classes); + + for (i = 0; i < classes[4]; i++) + if (classes[i] < solids[params->solid]->nfaces / classes[4]) + return "Not enough grid space to place all blue faces"; + + if (grid_area(params->d1, params->d2, solids[params->solid]->order) < + solids[params->solid]->nfaces + 1) + return "Not enough space to place the solid on an empty square"; + + return NULL; +} + struct grid_data { int *gridptrs[4]; int nsquares[4]; @@ -511,15 +605,7 @@ char *new_game_seed(game_params *params) for (i = 0; i < data.nclasses; i++) { for (j = 0; j < facesperclass; j++) { - unsigned long divisor = RAND_MAX / data.nsquares[i]; - unsigned long max = divisor * data.nsquares[i]; - unsigned long n; - - do { - n = rand(); - } while (n >= max); - - n /= divisor; + int n = rand_upto(data.nsquares[i]); assert(!flags[data.gridptrs[i][n]]); flags[data.gridptrs[i][n]] = TRUE; @@ -529,7 +615,7 @@ char *new_game_seed(game_params *params) * better data structure for this, but for such small * numbers it hardly seems worth the effort. */ - while ((int)n < data.nsquares[i]-1) { + while (n < data.nsquares[i]-1) { data.gridptrs[i][n] = data.gridptrs[i][n+1]; n++; } @@ -567,19 +653,7 @@ char *new_game_seed(game_params *params) /* * Choose a non-blue square for the polyhedron. */ - { - unsigned long divisor = RAND_MAX / m; - unsigned long max = divisor * m; - unsigned long n; - - do { - n = rand(); - } while (n >= max); - - n /= divisor; - - sprintf(p, ":%d", data.gridptrs[0][n]); - } + sprintf(p, ":%d", data.gridptrs[0][rand_upto(m)]); sfree(data.gridptrs[0]); sfree(flags); @@ -808,7 +882,7 @@ game_state *new_game(game_params *params, char *seed) state->previous = state->current; state->angle = 0.0; - state->completed = FALSE; + state->completed = 0; state->movecount = 0; return state; @@ -1066,6 +1140,8 @@ game_state *make_move(game_state *from, int x, int y, int button) ret->facecolours = newcolours; } + ret->movecount++; + /* * And finally, swap the colour between the bottom face of the * polyhedron and the face we've just landed on. @@ -1088,7 +1164,7 @@ game_state *make_move(game_state *from, int x, int y, int button) if (ret->facecolours[i]) j++; if (j == ret->solid->nfaces) - ret->completed = TRUE; + ret->completed = ret->movecount; } sfree(poly); @@ -1117,7 +1193,6 @@ game_state *make_move(game_state *from, int x, int y, int button) ret->sgkey[1] = skey[1]; ret->previous = from->current; ret->angle = angle; - ret->movecount++; return ret; } @@ -1313,8 +1388,8 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, } for (j = 0; j < poly->order; j++) { - coords[j*2] = (int)(points[j*2] * GRID_SCALE) + ds->ox; - coords[j*2+1] = (int)(points[j*2+1] * GRID_SCALE) + ds->oy; + coords[j*2] = (int)floor(points[j*2] * GRID_SCALE) + ds->ox; + coords[j*2+1] = (int)floor(points[j*2+1] * GRID_SCALE) + ds->oy; } /* @@ -1349,6 +1424,19 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, draw_update(fe, 0, 0, (int)((bb.r-bb.l+2.0F) * GRID_SCALE), (int)((bb.d-bb.u+2.0F) * GRID_SCALE)); + + /* + * Update the status bar. + */ + { + char statusbuf[256]; + + sprintf(statusbuf, "%sMoves: %d", + (state->completed ? "COMPLETED! " : ""), + (state->completed ? state->completed : state->movecount)); + + status_bar(fe, statusbuf); + } } float game_anim_length(game_state *oldstate, game_state *newstate) @@ -1360,3 +1448,8 @@ float game_flash_length(game_state *oldstate, game_state *newstate) { return 0.0F; } + +int game_wants_statusbar(void) +{ + return TRUE; +}