From cbb5549e12c8edfd8b38b642b7b25c1fb8912c9b Mon Sep 17 00:00:00 2001 From: jacob Date: Wed, 22 Dec 2004 19:27:26 +0000 Subject: [PATCH] Add a `jumble' key (`J') to Net, which scrambles the positions of all unlocked tiles randomly. (Rachel asked for this; it's been being tested for a good few months now, and Simon didn't care either way, so in it goes :) As part of this, the front end can now be asked to provide a random random seed (IYSWIM). git-svn-id: svn://svn.tartarus.org/sgt/puzzles@5019 cda61777-01e9-0310-a592-d414129be87e --- gtk.c | 12 +++++-- midend.c | 8 ++++- net.c | 111 +++++++++++++++++++++++++++++++++++++++++------------------- puzzles.but | 5 +++ puzzles.h | 3 +- windows.c | 12 +++++-- 6 files changed, 109 insertions(+), 42 deletions(-) diff --git a/gtk.c b/gtk.c index 72fdcdd..d27f739 100644 --- a/gtk.c +++ b/gtk.c @@ -73,6 +73,14 @@ struct frontend { GtkWidget *cfgbox; }; +void get_random_seed(void **randseed, int *randseedsize) +{ + time_t *tp = snew(time_t); + time(tp); + *randseed = (void *)tp; + *randseedsize = sizeof(time_t); +} + void frontend_default_colour(frontend *fe, float *output) { GdkColor col = fe->window->style->bg[GTK_STATE_NORMAL]; @@ -772,12 +780,10 @@ static frontend *new_window(char *game_id, char **error) GtkBox *vbox; GtkWidget *menubar, *menu, *menuitem; int x, y, n; - time_t t; fe = snew(frontend); - time(&t); - fe->me = midend_new(fe, &t, sizeof(t)); + fe->me = midend_new(fe); if (game_id) { *error = midend_game_id(fe->me, game_id, FALSE); if (*error) { diff --git a/midend.c b/midend.c index a9cd768..4636fa0 100644 --- a/midend.c +++ b/midend.c @@ -40,9 +40,13 @@ struct midend_data { } \ } while (0) -midend_data *midend_new(frontend *fe, void *randseed, int randseedsize) +midend_data *midend_new(frontend *fe) { midend_data *me = snew(midend_data); + void *randseed; + int randseedsize; + + get_random_seed(&randseed, &randseedsize); me->frontend = fe; me->random = random_init(randseed, randseedsize); @@ -61,6 +65,8 @@ midend_data *midend_new(frontend *fe, void *randseed, int randseedsize) me->dir = 0; me->ui = NULL; + sfree(randseed); + return me; } diff --git a/net.c b/net.c index bb9218f..6849dbc 100644 --- a/net.c +++ b/net.c @@ -344,7 +344,7 @@ game_state *new_game(game_params *params, char *seed) state->cx = state->width / 2; state->cy = state->height / 2; state->wrapping = params->wrapping; - state->last_rotate_dir = +1; /* *shrug* */ + state->last_rotate_dir = 0; state->completed = FALSE; state->tiles = snewn(state->width * state->height, unsigned char); memset(state->tiles, 0, state->width * state->height); @@ -767,20 +767,27 @@ static unsigned char *compute_active(game_state *state) struct game_ui { int cur_x, cur_y; int cur_visible; + random_state *rs; /* used for jumbling */ }; game_ui *new_ui(game_state *state) { + void *seed; + int seedsize; game_ui *ui = snew(game_ui); ui->cur_x = state->width / 2; ui->cur_y = state->height / 2; ui->cur_visible = FALSE; + get_random_seed(&seed, &seedsize); + ui->rs = random_init(seed, seedsize); + sfree(seed); return ui; } void free_ui(game_ui *ui) { + random_free(ui->rs); sfree(ui); } @@ -842,6 +849,10 @@ game_state *make_move(game_state *state, game_ui *ui, int x, int y, int button) else if (button == 'd' || button == 'D') button = RIGHT_BUTTON; ui->cur_visible = TRUE; + } else if (button == 'j' || button == 'J') { + /* XXX should we have some mouse control for this? */ + button = 'J'; /* canonify */ + tx = ty = -1; /* shut gcc up :( */ } else return nullret; @@ -856,31 +867,54 @@ game_state *make_move(game_state *state, game_ui *ui, int x, int y, int button) * unlocks it.) */ if (button == MIDDLE_BUTTON) { + ret = dup_game(state); tile(ret, tx, ty) ^= LOCKED; + ret->last_rotate_dir = 0; return ret; - } - /* - * The left and right buttons have no effect if clicked on a - * locked tile. - */ - if (tile(state, tx, ty) & LOCKED) - return nullret; + } else if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { - /* - * Otherwise, turn the tile one way or the other. Left button - * turns anticlockwise; right button turns clockwise. - */ - ret = dup_game(state); - orig = tile(ret, tx, ty); - if (button == LEFT_BUTTON) { - tile(ret, tx, ty) = A(orig); - ret->last_rotate_dir = +1; - } else { - tile(ret, tx, ty) = C(orig); - ret->last_rotate_dir = -1; - } + /* + * The left and right buttons have no effect if clicked on a + * locked tile. + */ + if (tile(state, tx, ty) & LOCKED) + return nullret; + + /* + * Otherwise, turn the tile one way or the other. Left button + * turns anticlockwise; right button turns clockwise. + */ + ret = dup_game(state); + orig = tile(ret, tx, ty); + if (button == LEFT_BUTTON) { + tile(ret, tx, ty) = A(orig); + ret->last_rotate_dir = +1; + } else { + tile(ret, tx, ty) = C(orig); + ret->last_rotate_dir = -1; + } + + } else if (button == 'J') { + + /* + * Jumble all unlocked tiles to random orientations. + */ + int jx, jy; + ret = dup_game(state); + for (jy = 0; jy < ret->height; jy++) { + for (jx = 0; jx < ret->width; jx++) { + if (!(tile(ret, jx, jy) & LOCKED)) { + int rot = random_upto(ui->rs, 4); + orig = tile(ret, jx, jy); + tile(ret, jx, jy) = ROT(orig, rot); + } + } + } + ret->last_rotate_dir = 0; /* suppress animation */ + + } else assert(0); /* * Check whether the game has been completed. @@ -1253,7 +1287,7 @@ static void draw_tile(frontend *fe, game_state *state, int x, int y, int tile, void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, game_state *state, int dir, game_ui *ui, float t, float ft) { - int x, y, tx, ty, frame; + int x, y, tx, ty, frame, last_rotate_dir; unsigned char *active; float angle = 0.0; @@ -1309,9 +1343,11 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, } tx = ty = -1; - if (oldstate && (t < ROTATE_TIME)) { + last_rotate_dir = dir==-1 ? oldstate->last_rotate_dir : + state->last_rotate_dir; + if (oldstate && (t < ROTATE_TIME) && last_rotate_dir) { /* - * We're animating a tile rotation. Find the turning tile, + * We're animating a single tile rotation. Find the turning tile, * if any. */ for (x = 0; x < oldstate->width; x++) @@ -1323,8 +1359,6 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, break_label: if (tx >= 0) { - int last_rotate_dir = dir==-1 ? oldstate->last_rotate_dir : - state->last_rotate_dir; angle = last_rotate_dir * dir * 90.0F * (t / ROTATE_TIME); state = oldstate; } @@ -1404,17 +1438,26 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, float game_anim_length(game_state *oldstate, game_state *newstate, int dir) { - int x, y; + int x, y, last_rotate_dir; /* - * If there's a tile which has been rotated, allow time to - * animate its rotation. + * Don't animate if last_rotate_dir is zero. */ - for (x = 0; x < oldstate->width; x++) - for (y = 0; y < oldstate->height; y++) - if ((tile(oldstate, x, y) ^ tile(newstate, x, y)) & 0xF) { - return ROTATE_TIME; - } + last_rotate_dir = dir==-1 ? oldstate->last_rotate_dir : + newstate->last_rotate_dir; + if (last_rotate_dir) { + + /* + * If there's a tile which has been rotated, allow time to + * animate its rotation. + */ + for (x = 0; x < oldstate->width; x++) + for (y = 0; y < oldstate->height; y++) + if ((tile(oldstate, x, y) ^ tile(newstate, x, y)) & 0xF) { + return ROTATE_TIME; + } + + } return 0.0F; } diff --git a/puzzles.but b/puzzles.but index 44e1ae3..de0bac3 100644 --- a/puzzles.but +++ b/puzzles.but @@ -203,6 +203,11 @@ controls are: also unlock it again, but while it's locked you can't accidentally turn it. +\dt \e{Jumble tiles}: \q{J} key + +\dd This key turns all tiles that are not locked to random +orientations. + (All the actions described in \k{common-actions} are also available.) \H{net-params} \I{parameters, for Net}Net parameters diff --git a/puzzles.h b/puzzles.h index b0947fc..027a973 100644 --- a/puzzles.h +++ b/puzzles.h @@ -106,11 +106,12 @@ void end_draw(frontend *fe); void deactivate_timer(frontend *fe); void activate_timer(frontend *fe); void status_bar(frontend *fe, char *text); +void get_random_seed(void **randseed, int *randseedsize); /* * midend.c */ -midend_data *midend_new(frontend *fe, void *randseed, int randseedsize); +midend_data *midend_new(frontend *fe); void midend_free(midend_data *me); void midend_set_params(midend_data *me, game_params *params); void midend_size(midend_data *me, int *x, int *y); diff --git a/windows.c b/windows.c index 494caae..ac5e20c 100644 --- a/windows.c +++ b/windows.c @@ -121,6 +121,14 @@ void fatal(char *fmt, ...) exit(1); } +void get_random_seed(void **randseed, int *randseedsize) +{ + time_t *tp = snew(time_t); + time(tp); + *randseed = (void *)tp; + *randseedsize = sizeof(time_t); +} + void status_bar(frontend *fe, char *text) { SetWindowText(fe->statusbar, text); @@ -352,12 +360,10 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) int x, y; RECT r, sr; HDC hdc; - time_t t; fe = snew(frontend); - time(&t); - fe->me = midend_new(fe, &t, sizeof(t)); + fe->me = midend_new(fe); if (game_id) { *error = midend_game_id(fe->me, game_id, FALSE); -- 2.11.0