ref: 46fa25240e2e1609c4431a639f6e9c4bb6f50b39
parent: ec3d23c9d99e5233d40080623c032dfe157d29ac
author: Jacob Nevins <jacobn@chiark.greenend.org.uk>
date: Wed Dec 22 14:27:26 EST 2004
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). [originally from svn r5019]
--- a/gtk.c
+++ b/gtk.c
@@ -73,6 +73,14 @@
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 @@
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) {
--- a/midend.c
+++ b/midend.c
@@ -40,10 +40,14 @@
} \
} 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);
me->nstates = me->statesize = me->statepos = 0;
@@ -60,6 +64,8 @@
me->flash_time = me->flash_pos = 0.0F;
me->dir = 0;
me->ui = NULL;
+
+ sfree(randseed);
return me;
}
--- a/net.c
+++ b/net.c
@@ -344,7 +344,7 @@
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,14 +767,20 @@
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;
}
@@ -781,6 +787,7 @@
void free_ui(game_ui *ui)
{
+ random_free(ui->rs);
sfree(ui);
}
@@ -842,6 +849,10 @@
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,32 +867,55 @@
* 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 @@
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 @@
}
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 @@
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 @@
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;
}
--- a/puzzles.but
+++ b/puzzles.but
@@ -203,6 +203,11 @@
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
--- a/puzzles.h
+++ b/puzzles.h
@@ -106,11 +106,12 @@
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);
--- a/windows.c
+++ b/windows.c
@@ -121,6 +121,14 @@
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 @@
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);