[PATCH] Re-add seed support, redmond game generation for freecell



Here is my patch to re-add UI seed support and add redmond-style freecell game numbers, I estimate it is clean enough. I hope the UI change is unobtrusive enough, I am not great at designing user interfaces. The code itself was tested using gnome-games 2.16.3 (debian), I have applied my changes to the latest svn revision by hand since updating my build environment would be quite cumbersome using debian, the changes seem minor enough, just be sure to double-check.

PS: The GTK, C, Scheme combo has kind of grown on me, I might use something similar in future personal projects.

Cheers guys, keep up the great work,
Jonathan

Index: AUTHORS
===================================================================
--- AUTHORS	(revision 5970)
+++ AUTHORS	(working copy)
@@ -20,3 +20,4 @@
 Andreas Røsdal <andreasr gnome org>
 Robert Ancell <robert ancell gmail com>
 Thomas Hinkle <Thomas_Hinkle alumni brown edu>
+Jonathan Bastien-Filiatrault <joe x2a org>
Index: aisleriot/dialog.c
===================================================================
--- aisleriot/dialog.c	(revision 5970)
+++ aisleriot/dialog.c	(working copy)
@@ -61,7 +61,8 @@
 			    GTK_STOCK_UNDO, GTK_RESPONSE_REJECT, NULL);
   gtk_dialog_add_buttons (GTK_DIALOG (dialog),
 			  GTK_STOCK_QUIT, GTK_RESPONSE_CLOSE,
-			  _("_New Game"), GTK_RESPONSE_ACCEPT, NULL);
+			  _("_New Game"), GTK_RESPONSE_ACCEPT,
+ 			  _("Choose s_eed"), GTK_RESPONSE_APPLY, NULL);
   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
 
   /* add a stock icon? */
@@ -70,6 +71,10 @@
     gtk_widget_destroy (dialog);
     new_game (NULL, NULL);
     break;
+  case GTK_RESPONSE_APPLY:
+    gtk_widget_destroy (dialog);
+    choose_seed_dialog();
+    break;
   case GTK_RESPONSE_REJECT:
     timer_restart ();
     gtk_widget_destroy (dialog);
@@ -97,6 +102,51 @@
   }
 }
 
+void choose_seed_dialog() {
+  GtkWidget* dialog;
+  GtkWidget* seed_spinner;
+  GtkWidget* label;
+  guint seed;
+  gchar* message;
+
+  dialog = gtk_dialog_new_with_buttons (_("Choose a seed"),
+					GTK_WINDOW (app),
+					GTK_DIALOG_DESTROY_WITH_PARENT,
+					GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+					GTK_STOCK_OK, GTK_RESPONSE_OK,
+					NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+  message = g_strdup_printf (_("Choose a seed from 0 to %u"), G_MAXUINT);
+  label = gtk_label_new(message);
+  g_free (message);
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
+		     label);
+  gtk_widget_show (label);
+
+  seed_spinner = gtk_spin_button_new_with_range(0, G_MAXUINT, 1);
+  gtk_entry_set_activates_default (GTK_ENTRY (seed_spinner), TRUE);
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
+		     seed_spinner);
+  gtk_widget_show (seed_spinner);
+
+  switch (gtk_dialog_run (GTK_DIALOG (dialog)))
+    {
+    case GTK_RESPONSE_OK:
+      seed = (guint)gtk_spin_button_get_value ( GTK_SPIN_BUTTON (seed_spinner));
+      gtk_widget_destroy (label);
+      gtk_widget_destroy (seed_spinner);
+      gtk_widget_destroy (dialog);
+      new_game (NULL, &seed);
+      break;
+    default:
+      gtk_widget_destroy (label);
+      gtk_widget_destroy (seed_spinner);
+      gtk_widget_destroy (dialog);
+      break;
+    }
+}
+
 gchar *filename = NULL;
 
 static void
Index: aisleriot/dialog.h
===================================================================
--- aisleriot/dialog.h	(revision 5970)
+++ aisleriot/dialog.h	(working copy)
@@ -22,6 +22,7 @@
 
 void show_select_game_dialog (void);
 void show_game_over_dialog (void);
+void choose_seed_dialog (void);
 void show_preferences_dialog (void);
 void show_rules_options_dialog (void);
 void show_global_stats_dialog (void);
Index: aisleriot/menu.c
===================================================================
--- aisleriot/menu.c	(revision 5970)
+++ aisleriot/menu.c	(working copy)
@@ -68,6 +68,13 @@
   new_game (NULL, NULL);
 };
 
+static void
+new_game_seed_action ()
+{
+  if (waiting_for_mouse_up())
+    return;
+  choose_seed_dialog ();
+}
 
 static void
 new_recent_game_action (GtkAction * action, gpointer user_data)
@@ -250,6 +257,8 @@
 
   {"NewGame", GAMES_STOCK_NEW_GAME, NULL, NULL, N_("Start a new game"),
    G_CALLBACK (new_game_action)},
+  { "NewGameSeed", GTK_STOCK_OPEN, N_("Choose s_eed"), "<Ctrl>e",
+    N_("Start a new game with a specific seed"), G_CALLBACK (new_game_seed_action) },
   {"RestartGame", GAMES_STOCK_RESTART_GAME, NULL, NULL,
    N_("Restart the current game"), G_CALLBACK (restart_game)},
   {"Select", GTK_STOCK_INDEX, N_("_Select Game..."), "<Ctrl>o",
@@ -292,6 +301,7 @@
   "  <menubar name='MainMenu'>"
   "    <menu action='GameMenu'>"
   "      <menuitem action='NewGame'/>"
+  "      <menuitem action='NewGameSeed'/>"
   "      <menuitem action='RestartGame'/>"
   "      <menuitem action='Select'/>"
   "      <menu action='RecentlyPlayed'/>"
@@ -322,6 +332,7 @@
   "  </menubar>"
   "  <toolbar name='Toolbar'>"
   "    <toolitem action='NewGame'/>"
+  "    <toolitem action='NewGameSeed'/>"
   "    <toolitem action='RestartGame'/>"
   "    <toolitem action='Select'/>"
   "    <separator/>"
Index: aisleriot/rules/freecell.scm
===================================================================
--- aisleriot/rules/freecell.scm	(revision 5970)
+++ aisleriot/rules/freecell.scm	(working copy)
@@ -81,6 +81,49 @@
 ;; Utilities
 ;;
 
+(define redmond-seed 0)
+
+(define (redmond-srand s)
+  (set! redmond-seed s))
+
+;; Redmond PRNG, parameters from http://www.codeproject.com/useritems/PRNG.asp
+(define (redmond-rand)
+  (set! redmond-seed
+	(+ (* redmond-seed 214013) 2531011))
+  (modulo (ash redmond-seed -16)
+	  (expt 2 15)))
+
+(define (make-redmond-deck)
+  (set! DECK (make-deck-list-redmond 0)))
+
+;; We need the cards in AC AD AH AS 2C 2D 2H 2S 3C... order
+(define (make-deck-list-redmond value)
+  (if (eq? value 51)
+      (list (make-card (+ (quotient value 4) 1) (modulo value 4)))
+      (cons (make-card (+ (quotient value 4) 1) (modulo value 4))
+	    (make-deck-list-redmond (+ 1 value)))))
+
+(define (shuffle-deck-redmond gamenum)
+  (redmond-srand gamenum)
+  (set! DECK (shuffle-deck-list-redmond DECK)))
+
+;; Shuffle the deck with the Redmond PRNG,
+;; inspired by http://www.solitairelaboratory.com/mshuffle.txt
+(define (shuffle-deck-list-redmond deck)
+  (let ((n (modulo (redmond-rand) (length deck))))
+    (if (eq? 1 (length deck))
+	deck
+	(cons (list-ref deck n )
+	      (shuffle-deck-list-redmond
+	       (redmond-adjust-list deck n))))))
+
+(define (redmond-adjust-list deck n)
+  (if (eq? n (- (length deck) 1))
+      (list-head deck (- (length deck) 1))
+      (append (list-head deck n)
+	      (last-pair deck)
+	      (cdr (list-tail (list-head deck (- (length deck) 1)) n)))))
+
 (define (freecell? slot)
   (and (>= slot freecell-1) (<= slot freecell-4)))
 
@@ -318,8 +361,8 @@
 (define (new-game)
   (initialize-playing-area)
   (set-ace-low)
-  (make-standard-deck)
-  (shuffle-deck)
+  (make-redmond-deck)
+  (shuffle-deck-redmond SEED)
   
   ;; set up the board
 
Index: aisleriot/sol.c
===================================================================
--- aisleriot/sol.c	(revision 5970)
+++ aisleriot/sol.c	(working copy)
@@ -249,6 +249,7 @@
 new_game (gchar * file, guint * seedp)
 {
   double width, height;
+  char *title;
 
   /* If we're aborting an old game count it as a failure for
    * statistical purposes. */
@@ -296,6 +297,8 @@
   set_score (0);
   timer_reset ();
 
+  scm_call_1 (scm_variable_ref (scm_c_lookup ("set-seed")), scm_i_uint2big (seed));
+
   cscmi_start_game_lambda (&width, &height);
   scm_c_eval_string ("(start-game)");
 
@@ -313,7 +316,9 @@
     redo_set_sensitive (FALSE);
 
     game_over = FALSE;
-    gtk_window_set_title (GTK_WINDOW (app), _(game_name));
+    title = g_strdup_printf("%s #%u", _(game_name), seed);
+    gtk_window_set_title (GTK_WINDOW (app), title);
+    g_free(title);
   }
   /* We've just started a new game. Add this to the list of games the user likes */
   add_recently_played_game (file);
Index: aisleriot/sol.scm
===================================================================
--- aisleriot/sol.scm	(revision 5970)
+++ aisleriot/sol.scm	(working copy)
@@ -533,12 +533,17 @@
 (define HISTORY '())
 (define FUTURE '())
 (define IN-GAME #f)
+(define SEED #f)
 
 ; called from C:
 (define (start-game)
   (set! IN-GAME #t))
 
 ; called from C:
+(define (set-seed seed)
+  (set! SEED seed))
+
+; called from C:
 (define (end-move)
   (if (not (= 0 (length MOVE)))
       (begin




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]