mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 16:05:44 -07:00
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]
This commit is contained in:
12
gtk.c
12
gtk.c
@ -73,6 +73,14 @@ struct frontend {
|
|||||||
GtkWidget *cfgbox;
|
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)
|
void frontend_default_colour(frontend *fe, float *output)
|
||||||
{
|
{
|
||||||
GdkColor col = fe->window->style->bg[GTK_STATE_NORMAL];
|
GdkColor col = fe->window->style->bg[GTK_STATE_NORMAL];
|
||||||
@ -772,12 +780,10 @@ static frontend *new_window(char *game_id, char **error)
|
|||||||
GtkBox *vbox;
|
GtkBox *vbox;
|
||||||
GtkWidget *menubar, *menu, *menuitem;
|
GtkWidget *menubar, *menu, *menuitem;
|
||||||
int x, y, n;
|
int x, y, n;
|
||||||
time_t t;
|
|
||||||
|
|
||||||
fe = snew(frontend);
|
fe = snew(frontend);
|
||||||
|
|
||||||
time(&t);
|
fe->me = midend_new(fe);
|
||||||
fe->me = midend_new(fe, &t, sizeof(t));
|
|
||||||
if (game_id) {
|
if (game_id) {
|
||||||
*error = midend_game_id(fe->me, game_id, FALSE);
|
*error = midend_game_id(fe->me, game_id, FALSE);
|
||||||
if (*error) {
|
if (*error) {
|
||||||
|
8
midend.c
8
midend.c
@ -40,9 +40,13 @@ struct midend_data {
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
midend_data *midend_new(frontend *fe, void *randseed, int randseedsize)
|
midend_data *midend_new(frontend *fe)
|
||||||
{
|
{
|
||||||
midend_data *me = snew(midend_data);
|
midend_data *me = snew(midend_data);
|
||||||
|
void *randseed;
|
||||||
|
int randseedsize;
|
||||||
|
|
||||||
|
get_random_seed(&randseed, &randseedsize);
|
||||||
|
|
||||||
me->frontend = fe;
|
me->frontend = fe;
|
||||||
me->random = random_init(randseed, randseedsize);
|
me->random = random_init(randseed, randseedsize);
|
||||||
@ -61,6 +65,8 @@ midend_data *midend_new(frontend *fe, void *randseed, int randseedsize)
|
|||||||
me->dir = 0;
|
me->dir = 0;
|
||||||
me->ui = NULL;
|
me->ui = NULL;
|
||||||
|
|
||||||
|
sfree(randseed);
|
||||||
|
|
||||||
return me;
|
return me;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
59
net.c
59
net.c
@ -344,7 +344,7 @@ game_state *new_game(game_params *params, char *seed)
|
|||||||
state->cx = state->width / 2;
|
state->cx = state->width / 2;
|
||||||
state->cy = state->height / 2;
|
state->cy = state->height / 2;
|
||||||
state->wrapping = params->wrapping;
|
state->wrapping = params->wrapping;
|
||||||
state->last_rotate_dir = +1; /* *shrug* */
|
state->last_rotate_dir = 0;
|
||||||
state->completed = FALSE;
|
state->completed = FALSE;
|
||||||
state->tiles = snewn(state->width * state->height, unsigned char);
|
state->tiles = snewn(state->width * state->height, unsigned char);
|
||||||
memset(state->tiles, 0, state->width * state->height);
|
memset(state->tiles, 0, state->width * state->height);
|
||||||
@ -767,20 +767,27 @@ static unsigned char *compute_active(game_state *state)
|
|||||||
struct game_ui {
|
struct game_ui {
|
||||||
int cur_x, cur_y;
|
int cur_x, cur_y;
|
||||||
int cur_visible;
|
int cur_visible;
|
||||||
|
random_state *rs; /* used for jumbling */
|
||||||
};
|
};
|
||||||
|
|
||||||
game_ui *new_ui(game_state *state)
|
game_ui *new_ui(game_state *state)
|
||||||
{
|
{
|
||||||
|
void *seed;
|
||||||
|
int seedsize;
|
||||||
game_ui *ui = snew(game_ui);
|
game_ui *ui = snew(game_ui);
|
||||||
ui->cur_x = state->width / 2;
|
ui->cur_x = state->width / 2;
|
||||||
ui->cur_y = state->height / 2;
|
ui->cur_y = state->height / 2;
|
||||||
ui->cur_visible = FALSE;
|
ui->cur_visible = FALSE;
|
||||||
|
get_random_seed(&seed, &seedsize);
|
||||||
|
ui->rs = random_init(seed, seedsize);
|
||||||
|
sfree(seed);
|
||||||
|
|
||||||
return ui;
|
return ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_ui(game_ui *ui)
|
void free_ui(game_ui *ui)
|
||||||
{
|
{
|
||||||
|
random_free(ui->rs);
|
||||||
sfree(ui);
|
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')
|
else if (button == 'd' || button == 'D')
|
||||||
button = RIGHT_BUTTON;
|
button = RIGHT_BUTTON;
|
||||||
ui->cur_visible = TRUE;
|
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
|
} else
|
||||||
return nullret;
|
return nullret;
|
||||||
|
|
||||||
@ -856,10 +867,13 @@ game_state *make_move(game_state *state, game_ui *ui, int x, int y, int button)
|
|||||||
* unlocks it.)
|
* unlocks it.)
|
||||||
*/
|
*/
|
||||||
if (button == MIDDLE_BUTTON) {
|
if (button == MIDDLE_BUTTON) {
|
||||||
|
|
||||||
ret = dup_game(state);
|
ret = dup_game(state);
|
||||||
tile(ret, tx, ty) ^= LOCKED;
|
tile(ret, tx, ty) ^= LOCKED;
|
||||||
|
ret->last_rotate_dir = 0;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
|
} else if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The left and right buttons have no effect if clicked on a
|
* The left and right buttons have no effect if clicked on a
|
||||||
@ -882,6 +896,26 @@ game_state *make_move(game_state *state, game_ui *ui, int x, int y, int button)
|
|||||||
ret->last_rotate_dir = -1;
|
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.
|
* 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,
|
void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
|
||||||
game_state *state, int dir, game_ui *ui, float t, float ft)
|
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;
|
unsigned char *active;
|
||||||
float angle = 0.0;
|
float angle = 0.0;
|
||||||
|
|
||||||
@ -1309,9 +1343,11 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
|
|||||||
}
|
}
|
||||||
|
|
||||||
tx = ty = -1;
|
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.
|
* if any.
|
||||||
*/
|
*/
|
||||||
for (x = 0; x < oldstate->width; x++)
|
for (x = 0; x < oldstate->width; x++)
|
||||||
@ -1323,8 +1359,6 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
|
|||||||
break_label:
|
break_label:
|
||||||
|
|
||||||
if (tx >= 0) {
|
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);
|
angle = last_rotate_dir * dir * 90.0F * (t / ROTATE_TIME);
|
||||||
state = oldstate;
|
state = oldstate;
|
||||||
}
|
}
|
||||||
@ -1404,7 +1438,14 @@ void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
|
|||||||
|
|
||||||
float game_anim_length(game_state *oldstate, game_state *newstate, int dir)
|
float game_anim_length(game_state *oldstate, game_state *newstate, int dir)
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y, last_rotate_dir;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't animate if last_rotate_dir is zero.
|
||||||
|
*/
|
||||||
|
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
|
* If there's a tile which has been rotated, allow time to
|
||||||
@ -1416,6 +1457,8 @@ float game_anim_length(game_state *oldstate, game_state *newstate, int dir)
|
|||||||
return ROTATE_TIME;
|
return ROTATE_TIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return 0.0F;
|
return 0.0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,6 +203,11 @@ controls are:
|
|||||||
also unlock it again, but while it's locked you can't accidentally
|
also unlock it again, but while it's locked you can't accidentally
|
||||||
turn it.
|
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.)
|
(All the actions described in \k{common-actions} are also available.)
|
||||||
|
|
||||||
\H{net-params} \I{parameters, for Net}Net parameters
|
\H{net-params} \I{parameters, for Net}Net parameters
|
||||||
|
@ -106,11 +106,12 @@ void end_draw(frontend *fe);
|
|||||||
void deactivate_timer(frontend *fe);
|
void deactivate_timer(frontend *fe);
|
||||||
void activate_timer(frontend *fe);
|
void activate_timer(frontend *fe);
|
||||||
void status_bar(frontend *fe, char *text);
|
void status_bar(frontend *fe, char *text);
|
||||||
|
void get_random_seed(void **randseed, int *randseedsize);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* midend.c
|
* 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_free(midend_data *me);
|
||||||
void midend_set_params(midend_data *me, game_params *params);
|
void midend_set_params(midend_data *me, game_params *params);
|
||||||
void midend_size(midend_data *me, int *x, int *y);
|
void midend_size(midend_data *me, int *x, int *y);
|
||||||
|
12
windows.c
12
windows.c
@ -121,6 +121,14 @@ void fatal(char *fmt, ...)
|
|||||||
exit(1);
|
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)
|
void status_bar(frontend *fe, char *text)
|
||||||
{
|
{
|
||||||
SetWindowText(fe->statusbar, text);
|
SetWindowText(fe->statusbar, text);
|
||||||
@ -352,12 +360,10 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error)
|
|||||||
int x, y;
|
int x, y;
|
||||||
RECT r, sr;
|
RECT r, sr;
|
||||||
HDC hdc;
|
HDC hdc;
|
||||||
time_t t;
|
|
||||||
|
|
||||||
fe = snew(frontend);
|
fe = snew(frontend);
|
||||||
|
|
||||||
time(&t);
|
fe->me = midend_new(fe);
|
||||||
fe->me = midend_new(fe, &t, sizeof(t));
|
|
||||||
|
|
||||||
if (game_id) {
|
if (game_id) {
|
||||||
*error = midend_game_id(fe->me, game_id, FALSE);
|
*error = midend_game_id(fe->me, game_id, FALSE);
|
||||||
|
Reference in New Issue
Block a user