[aisleriot/gnome-3-2] Fix game restart
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [aisleriot/gnome-3-2] Fix game restart
- Date: Sun, 18 Sep 2011 21:13:29 +0000 (UTC)
commit a46f0a573ce4ca142dd02a201817508dbf594327
Author: Christian Persch <chpe gnome org>
Date: Sun Sep 18 23:10:04 2011 +0200
Fix game restart
Copy the RNG state, and use the saved state when restarting a game.
Remove the --seed option which is useless since while we can create
a GRand for a given seed, there is no way to serialise a GRand.
https://bugzilla.gnome.org/show_bug.cgi?id=657735
src/game.c | 113 +++++++++++++++++++++++++++++++++++++++++----------------
src/game.h | 7 ++--
src/sol.c | 20 ++++------
src/window.c | 57 ++++++++++++++++++-----------
src/window.h | 3 +-
5 files changed, 131 insertions(+), 69 deletions(-)
---
diff --git a/src/game.c b/src/game.c
index cc2181d..bd90652 100644
--- a/src/game.c
+++ b/src/game.c
@@ -70,7 +70,10 @@ struct _AisleriotGame
GPtrArray *slots;
char *game_file;
- guint32 seed;
+
+ GRand *rand;
+ GRand *saved_rand;
+
guint delayed_call_timeout_id;
GTimer *timer;
@@ -294,7 +297,9 @@ cscmi_exception_get_backtrace (SCM tag, SCM throw_args)
message = g_string_sized_new (1024);
g_string_append_printf (message, "Variation: %s\n", aisleriot_game_get_game_file (game));
+#if 0
g_string_append_printf (message, "Seed: %u\n", game->seed);
+#endif
g_string_append (message, "Scheme error:\n\t");
@@ -908,7 +913,9 @@ scm_set_lambda (SCM start_game_lambda,
static SCM
scm_myrandom (SCM range)
{
- return scm_from_uint32 (g_random_int_range (0, scm_to_int (range)));
+ AisleriotGame *game = app_game;
+
+ return scm_from_uint32 (g_rand_int_range (game->rand, 0, scm_to_int (range)));
}
static SCM
@@ -1100,6 +1107,8 @@ cscmi_winning_game_lambda (void)
static void
aisleriot_game_init (AisleriotGame *game)
{
+ game->rand = game->saved_rand = NULL;
+
game->state = GAME_UNINITIALISED;
game->slots = g_ptr_array_sized_new (SLOT_CARDS_N_PREALLOC);
@@ -1145,6 +1154,11 @@ aisleriot_game_finalize (GObject *object)
g_timer_destroy (game->timer);
+ if (game->rand)
+ g_rand_free (game->rand);
+ if (game->saved_rand)
+ g_rand_free (game->saved_rand);
+
app_game = NULL;
G_OBJECT_CLASS (aisleriot_game_parent_class)->finalize (object);
@@ -1710,6 +1724,8 @@ game_scm_new_game (void *user_data)
AisleriotGame *game = user_data;
gboolean game_over;
+ g_assert (game->rand != NULL);
+
/* It is possible for some games to not have any moves right from the
* start. If this happens we redeal.
*/
@@ -1717,6 +1733,11 @@ game_scm_new_game (void *user_data)
do {
SCM size, lambda, over;
+ /* Copy RNG state */
+ if (game->saved_rand)
+ g_rand_free (game->saved_rand);
+ game->saved_rand = g_rand_copy (game->rand);
+
size = scm_call_0 (game->lambdas[START_GAME_LAMBDA]);
game->width = scm_to_double (SCM_CAR (size));
game->height = scm_to_double (SCM_CADR (size));
@@ -1742,18 +1763,20 @@ game_scm_new_game (void *user_data)
return SCM_BOOL_T;
}
-/**
- * aisleriot_game_new_game:
+/*
+ * aisleriot_game_new_game_internal:
* @game:
- * @seed: a pointer to a #guint, or %NULL
+ * @rand: (allow-none) (transfer full): a #GRand, or %NULL
+ * @update_statistics: whether to update statistic
*
* Starts a new game of the currently loaded game type.
- * If @seed is non-%NULL, the value it points to is used
- * as the game number; otherwise a random number is used.
+ *
+ * @game will take ownership of @rand.
*/
-void
-aisleriot_game_new_game (AisleriotGame *game,
- guint *seed)
+static void
+aisleriot_game_new_game_internal (AisleriotGame *game,
+ GRand *rand,
+ gboolean count_loss)
{
GObject *object = G_OBJECT (game);
GError *err = NULL;
@@ -1774,17 +1797,24 @@ aisleriot_game_new_game (AisleriotGame *game,
/* FIXMEchpe: this allows cheating the statistics by doing
* Restart, then New Game.
*/
- if (game->state >= GAME_RUNNING &&
- (!seed || *seed != game->seed)) {
+ if (count_loss &&
+ game->state >= GAME_RUNNING) {
update_statistics (game);
}
- if (seed) {
- game->seed = *seed;
- } else {
- game->seed = 0;
+ if (rand != NULL) {
+ if (game->rand)
+ g_rand_free (game->rand);
+
+ game->rand = rand; /* adopted */
+ } else if (game->rand == NULL) {
+ game->rand = g_rand_new ();
}
+ if (game->saved_rand)
+ g_rand_free (game->saved_rand);
+ game->saved_rand = NULL;
+
clear_delayed_call (game);
/* The game isn't actually in progress until the user makes a move */
set_game_state (game, GAME_BEGIN);
@@ -1811,6 +1841,36 @@ aisleriot_game_new_game (AisleriotGame *game,
}
/**
+ * aisleriot_game_new_game:
+ * @game:
+ *
+ * Starts a new game of the currently loaded game type.
+ *
+ * @game will take ownership of @rand.
+ */
+void
+aisleriot_game_new_game (AisleriotGame *game)
+{
+ aisleriot_game_new_game_internal (game, NULL, TRUE);
+}
+
+/**
+ * aisleriot_game_new_game_with_rand:
+ * @game:
+ * @rand: (allow-none) (transfer full): a #GRand, or %NULL
+ *
+ * Starts a new game of the currently loaded game type.
+ *
+ * @game will take ownership of @rand.
+ */
+void
+aisleriot_game_new_game_with_rand (AisleriotGame *game,
+ GRand *rand)
+{
+ aisleriot_game_new_game_internal (game, rand, TRUE);
+}
+
+/**
* aisleriot_game_restart_game:
* @game:
*
@@ -1819,9 +1879,12 @@ aisleriot_game_new_game (AisleriotGame *game,
void
aisleriot_game_restart_game (AisleriotGame *game)
{
- guint seed = game->seed;
+ GRand *rand;
+
+ rand = game->saved_rand;
+ game->saved_rand = NULL;
- aisleriot_game_new_game (game, &seed);
+ aisleriot_game_new_game_internal (game, rand, FALSE);
}
/**
@@ -1871,20 +1934,6 @@ aisleriot_game_get_geometry (AisleriotGame *game,
}
/**
- * aisleriot_game_get_seed:
- * @game:
- *
- * Returns the seed of the current game.
- *
- * Returns: a number
- */
-guint
-aisleriot_game_get_seed (AisleriotGame *game)
-{
- return game->seed;
-}
-
-/**
* aisleriot_game_drag_valid:
* @game:
* @slot_id:
diff --git a/src/game.h b/src/game.h
index 6d7781e..6b060df 100644
--- a/src/game.h
+++ b/src/game.h
@@ -165,7 +165,10 @@ void aisleriot_game_redo_move (AisleriotGame * game);
gboolean aisleriot_game_load_game (AisleriotGame * game,
const char *filename, GError ** error);
-void aisleriot_game_new_game (AisleriotGame * game, guint * seed);
+void aisleriot_game_new_game (AisleriotGame *game);
+
+void aisleriot_game_new_game_with_rand (AisleriotGame *game,
+ GRand *rand);
void aisleriot_game_restart_game (AisleriotGame * game);
@@ -173,8 +176,6 @@ const char *aisleriot_game_get_game_file (AisleriotGame * game);
char *aisleriot_game_get_name (AisleriotGame * game);
-guint aisleriot_game_get_seed (AisleriotGame * game);
-
gboolean aisleriot_game_drag_valid (AisleriotGame * game,
int slot_id,
guint8 * cards, guint n_cards);
diff --git a/src/sol.c b/src/sol.c
index 77c9573..c868415 100644
--- a/src/sol.c
+++ b/src/sol.c
@@ -52,7 +52,7 @@ N_("About Solitaire")
typedef struct {
AisleriotWindow *window;
char *variation;
- guint seed;
+ gint seed; /* unused */
gboolean freecell;
} AppData;
@@ -66,13 +66,11 @@ save_state_cb (EggSMClient *client,
AisleriotGame *game;
char *argv[5];
const char *game_name;
- char *seed;
int argc = 0;
game = aisleriot_window_get_game (data->window);
game_name = aisleriot_game_get_game_file (game);
- seed = g_strdup_printf ("%u", aisleriot_game_get_seed (game));
argv[argc++] = g_get_prgname ();
@@ -83,14 +81,9 @@ save_state_cb (EggSMClient *client,
argv[argc++] = (char *) game_name;
}
- argv[argc++] = (char *) "--seed";
- argv[argc++] = seed;
-
/* FIXMEchpe: save game state too? */
egg_sm_client_set_restart_command (client, argc, (const char **) argv);
-
- g_free (seed);
}
static void
@@ -110,10 +103,13 @@ add_main_options (GOptionContext *option_context,
const GOptionEntry aisleriot_options[] = {
{ "variation", 'v', 0, G_OPTION_ARG_STRING, &data->variation,
N_("Select the game type to play"), N_("NAME") },
- { "seed", 's', 0, G_OPTION_ARG_STRING, &data->seed,
- N_("Select the game number"), N_("NUMBER") },
{ "freecell", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &data->freecell,
NULL, NULL },
+
+ /* Ignored option, for backward compat with saved session */
+ { "seed", 's', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &data->seed,
+ NULL, NULL },
+
{ NULL }
};
@@ -195,9 +191,9 @@ main_prog (void *closure, int argc, char *argv[])
#endif /* WITH_SMCLIENT */
if (data.freecell) {
- aisleriot_window_set_game (data.window, FREECELL_VARIATION, data.seed);
+ aisleriot_window_set_game (data.window, FREECELL_VARIATION, NULL);
} else {
- aisleriot_window_set_game (data.window, data.variation, data.seed);
+ aisleriot_window_set_game (data.window, data.variation, NULL);
}
gtk_window_present (GTK_WINDOW (data.window));
diff --git a/src/window.c b/src/window.c
index d00ad2b..89df4be 100644
--- a/src/window.c
+++ b/src/window.c
@@ -173,7 +173,7 @@ game_over_dialog_response_cb (GtkWidget *dialog,
aisleriot_game_restart_game (priv->game);
break;
case RESPONSE_NEW_GAME:
- aisleriot_game_new_game (priv->game, NULL);
+ aisleriot_game_new_game (priv->game);
break;
case GTK_RESPONSE_CLOSE:
gtk_widget_destroy (GTK_WIDGET (window)); /* this will quit */
@@ -186,7 +186,7 @@ game_over_dialog_response_cb (GtkWidget *dialog,
* thing to do.
*/
if (game_won) {
- aisleriot_game_new_game (priv->game, NULL);
+ aisleriot_game_new_game (priv->game);
} else {
aisleriot_game_undo_move (priv->game);
}
@@ -307,7 +307,7 @@ new_game_cb (GtkAction *action,
{
AisleriotWindowPrivate *priv = window->priv;
- aisleriot_game_new_game (priv->game, NULL);
+ aisleriot_game_new_game (priv->game);
gtk_widget_grab_focus (GTK_WIDGET (priv->board));
}
@@ -627,7 +627,7 @@ debug_cycle_timeout_cb (AisleriotWindow *window)
return FALSE;
game_file = data->current_game->data;
- aisleriot_window_set_game (data->window, game_file, 0);
+ aisleriot_window_set_game (data->window, game_file, NULL);
return TRUE;
}
@@ -650,7 +650,7 @@ debug_game_first (GtkAction *action,
if (!data->current_game)
return;
- aisleriot_window_set_game (data->window, (const char *) data->current_game->data, 0);
+ aisleriot_window_set_game (data->window, (const char *) data->current_game->data, NULL);
}
static void
@@ -664,7 +664,7 @@ debug_game_last (GtkAction *action,
if (!data->current_game)
return;
- aisleriot_window_set_game (data->window, (const char *) data->current_game->data, 0);
+ aisleriot_window_set_game (data->window, (const char *) data->current_game->data, NULL);
}
static void
@@ -683,7 +683,7 @@ debug_game_next (GtkAction *action,
if (!data->current_game)
return;
- aisleriot_window_set_game (data->window, (const char *) data->current_game->data, 0);
+ aisleriot_window_set_game (data->window, (const char *) data->current_game->data, NULL);
}
static void
@@ -702,7 +702,7 @@ debug_game_prev (GtkAction *action,
if (!data->current_game)
return;
- aisleriot_window_set_game (data->window, (const char *) data->current_game->data, 0);
+ aisleriot_window_set_game (data->window, (const char *) data->current_game->data, NULL);
}
static void
@@ -716,6 +716,7 @@ debug_choose_seed_response_cb (GtkWidget *dialog,
const char *text;
char *endptr;
guint seed;
+ GRand *rand;
entry = g_object_get_data (G_OBJECT (dialog), "entry");
text = gtk_entry_get_text (entry);
@@ -723,7 +724,9 @@ debug_choose_seed_response_cb (GtkWidget *dialog,
errno = 0;
seed = g_ascii_strtoull (text, &endptr, 10);
if (errno == 0 && endptr != text) {
- aisleriot_game_new_game (priv->game, &seed);
+ rand = g_rand_new_with_seed (seed);
+
+ aisleriot_game_new_game_with_rand (priv->game, rand /* adopts */);
gtk_widget_grab_focus (GTK_WIDGET (priv->board));
}
@@ -736,9 +739,7 @@ static void
debug_choose_seed_cb (GtkAction *action,
AisleriotWindow *window)
{
- AisleriotWindowPrivate *priv = window->priv;
GtkWidget *dialog, *entry;
- char str[32];
dialog = gtk_message_dialog_new (GTK_WINDOW (window),
GTK_DIALOG_DESTROY_WITH_PARENT |
@@ -750,9 +751,16 @@ debug_choose_seed_cb (GtkAction *action,
G_CALLBACK (debug_choose_seed_response_cb), window);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
- g_snprintf (str, sizeof (str), "%u", aisleriot_game_get_seed (priv->game));
entry = gtk_entry_new ();
+
+ #if 0
+{
+ char str[32];
+ g_snprintf (str, sizeof (str), "%u", aisleriot_game_get_seed (priv->game));
gtk_entry_set_text (GTK_ENTRY (entry), str);
+}
+#endif
+
gtk_box_pack_end (GTK_BOX (gtk_message_dialog_get_message_area (GTK_MESSAGE_DIALOG (dialog))), entry, FALSE, FALSE, 0);
gtk_widget_show (entry);
g_object_set_data (G_OBJECT (dialog), "entry", entry);
@@ -1057,7 +1065,7 @@ option_cb (GtkToggleAction *action,
aisleriot_conf_set_options (aisleriot_game_get_game_file (priv->game), (int) value);
/* Now re-deal, so the option is applied */
- aisleriot_game_new_game (priv->game, NULL);
+ aisleriot_game_new_game (priv->game);
}
static void
@@ -1210,7 +1218,7 @@ recent_game_cb (GtkAction *action,
game_file = g_object_get_data (G_OBJECT (action), "game");
g_return_if_fail (game_file != NULL);
- aisleriot_window_set_game (window, game_file, 0);
+ aisleriot_window_set_game (window, game_file, NULL);
ar_conf_set_string (NULL, aisleriot_conf_get_key (CONF_VARIATION), game_file);
}
@@ -1696,7 +1704,7 @@ game_exception_response_cb (GtkWidget *dialog,
gtk_widget_destroy (dialog);
/* Start a new game */
- aisleriot_game_new_game (priv->game, NULL);
+ aisleriot_game_new_game (priv->game);
gtk_widget_grab_focus (GTK_WIDGET (priv->board));
}
@@ -2465,7 +2473,7 @@ aisleriot_window_new (gboolean freecell_mode)
typedef struct {
AisleriotWindow *window;
char *game_file;
- guint seed;
+ GRand *rand;
} LoadIdleData;
static void
@@ -2474,7 +2482,7 @@ load_error_response_cb (GtkWidget *dialog,
AisleriotWindow *window)
{
/* Load the default game */
- aisleriot_window_set_game (window, DEFAULT_VARIATION, 0);
+ aisleriot_window_set_game (window, DEFAULT_VARIATION, NULL);
gtk_widget_destroy (dialog);
}
@@ -2484,6 +2492,7 @@ load_idle_cb (LoadIdleData *data)
{
AisleriotWindowPrivate *priv = data->window->priv;
GError *error = NULL;
+ GRand *rand;
if (!aisleriot_game_load_game (priv->game, data->game_file, &error)) {
GtkWidget *dialog;
@@ -2534,7 +2543,10 @@ load_idle_cb (LoadIdleData *data)
ar_conf_set_string (NULL, aisleriot_conf_get_key (CONF_VARIATION), data->game_file);
}
- aisleriot_game_new_game (priv->game, data->seed != 0 ? &data->seed : NULL);
+ rand = data->rand;
+ data->rand = NULL;
+
+ aisleriot_game_new_game_with_rand (priv->game, rand /* adopted */);
gtk_widget_grab_focus (GTK_WIDGET (priv->board));
@@ -2546,6 +2558,9 @@ free_load_idle_data (LoadIdleData *data)
{
data->window->priv->load_idle_id = 0;
+ if (data->rand)
+ g_rand_free (data->rand);
+
g_free (data->game_file);
g_slice_free (LoadIdleData, data);
}
@@ -2554,7 +2569,7 @@ free_load_idle_data (LoadIdleData *data)
* aisleriot_window_set_game:
* @window:
* @game_file: a UTF-8 string
- * @seed:
+ * @rand: (allow-none) (transfer full): a #GRand, or %NULL
*
* Loads the game variation defined in the @game_file file.
* Note that even though @game_file is used as a filename,
@@ -2563,7 +2578,7 @@ free_load_idle_data (LoadIdleData *data)
void
aisleriot_window_set_game (AisleriotWindow *window,
const char *game_file,
- guint seed)
+ GRand *rand)
{
AisleriotWindowPrivate *priv = window->priv;
LoadIdleData *data;
@@ -2576,7 +2591,7 @@ aisleriot_window_set_game (AisleriotWindow *window,
data = g_slice_new (LoadIdleData);
data->window = window;
data->game_file = g_strdup (game_file);
- data->seed = seed;
+ data->rand = rand; /* adopted */
priv->load_idle_id = g_idle_add_full (G_PRIORITY_LOW,
(GSourceFunc) load_idle_cb,
diff --git a/src/window.h b/src/window.h
index 6922127..b3456cd 100644
--- a/src/window.h
+++ b/src/window.h
@@ -48,7 +48,8 @@ GType aisleriot_window_get_type (void);
GtkWidget *aisleriot_window_new (gboolean freecell_mode);
void aisleriot_window_set_game (AisleriotWindow * window,
- const char *game_file, guint seed);
+ const char *game_file,
+ GRand *rand);
AisleriotGame *aisleriot_window_get_game (AisleriotWindow * window);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]