From c72ed6261224cc0a1b8aa72f6af966715970ff60 Mon Sep 17 00:00:00 2001
From: Christian Heller <c.heller@plomlompom.de>
Date: Wed, 20 Nov 2013 06:04:10 +0100
Subject: [PATCH] Improved (and simplified) pseudo-randomness.

---
 src/main.c  |  8 +++++---
 src/main.h  |  1 +
 src/map.c   |  3 +--
 src/misc.c  | 23 +++++++++++++++++------
 src/misc.h  |  6 ++++++
 src/rrand.c | 23 -----------------------
 src/rrand.h | 23 -----------------------
 7 files changed, 30 insertions(+), 57 deletions(-)
 delete mode 100644 src/rrand.c
 delete mode 100644 src/rrand.h

diff --git a/src/main.c b/src/main.c
index 86f8507..478f764 100644
--- a/src/main.c
+++ b/src/main.c
@@ -20,10 +20,9 @@
 #include "map.h" /* for struct Map, init_map() */
 #include "misc.h" /* for update_log(), find_passable_pos(), save_game(),
                    * try_calloc(), check_tempfile(), check_xor_files(),
-                   * load_interface_conf(), load_game()
+                   * load_interface_conf(), load_game(), rrand()
                    */
 #include "wincontrol.h" /* get_win_by_id(), get_winconf_by_win() */
-#include "rrand.h" /* for rrand(), rrand_seed() */
 #include "rexit.h" /* for exit_game(), exit_err() */
 #include "command_db.h" /* for init_command_db(), is_command_id_shortdsc() */
 #include "control.h" /* for control_by_id(), player_control(),
@@ -127,12 +126,14 @@ int main(int argc, char *argv[])
             exit_err(write_uint32_bigendian(world.seed, file), err_w);
             try_fclose_unlink_rename(file, recordfile_tmp, recordfile, f_name);
         }
+        world.mapseed = world.seed;
     }
 
     /* Generate map from seed and, if newly generated world, start positions of
      * actors.
      */
-    rrand_seed(world.seed);
+    uint32_t restore_seed = world.seed;
+    world.seed = world.mapseed;
     struct Map map = init_map();
     world.map = &map;
     set_cleanup_flag(CLEANUP_MAP);
@@ -148,6 +149,7 @@ int main(int argc, char *argv[])
         set_cleanup_flag(CLEANUP_MAP_OBJECTS);
         world.turn = 1;
     }
+    world.seed = restore_seed;
 
     /* Initialize window system and windows. */
     WINDOW * screen = initscr();
diff --git a/src/main.h b/src/main.h
index 687dfc8..f3670b2 100644
--- a/src/main.h
+++ b/src/main.h
@@ -25,6 +25,7 @@ struct World
     struct KeyBiData kb_wingeom;      /* Window geometry config keybindings. */
     struct KeyBiData kb_winkeys;      /* Window keybinding config keybindings.*/
     uint32_t seed;                    /* Randomness seed. */
+    uint32_t mapseed;                 /* Initial randomness seed used for map.*/
     uint32_t turn;                    /* Current game turn. */
     uint16_t score;                   /* Player's score. */
     char * log;                       /* Pointer to the game log string. */
diff --git a/src/map.c b/src/map.c
index 1615818..b8c8733 100644
--- a/src/map.c
+++ b/src/map.c
@@ -1,9 +1,8 @@
 #include "map.h"
 #include <stdint.h>      /* for uint16_t, uint32_t */
-#include "misc.h"        /* for try_malloc(), center_offset() */
+#include "misc.h"        /* for try_malloc(), center_offset(), rrand() */
 #include "map_objects.h" /* for get_player() */
 #include "yx_uint16.h"   /* for yx_uint16 and dir enums */
-#include "rrand.h"       /* for rrand() */
 #include "windows.h"     /* for struct Win */
 #include "main.h"        /* for world global */
 #include "wincontrol.h"  /* for get_win_by_id() */
diff --git a/src/misc.c b/src/misc.c
index 0e8abe9..e71770d 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -5,7 +5,7 @@
 #include <unistd.h> /* for unlink(), acess() */
 #include <stdlib.h> /* for size_t, calloc(), free() */
 #include <string.h> /* for strlen(), strcmp(), memcpy() */
-#include <stdint.h> /* for uint8_t, uint16_t */
+#include <stdint.h> /* for uint8_t, uint16_t, uint32_t */
 #include "readwrite.h" /* for [read/write]_uint[8/16/32][_bigendian](),
                         * try_fopen(), try_fclose(), get_linemax()
                         */
@@ -16,7 +16,6 @@
 #include "map.h" /* for Map struct, is_passable() */
 #include "main.h" /* for world global */
 #include "yx_uint16.h" /* for yx_uint16 struct */
-#include "rrand.h" /* for rrand(), rrand_seed() */
 #include "rexit.h" /* for exit_err() */
 #include "wincontrol.h" /* for init_winconfs(), init_wins(), free_winconfs(),
                          * sorted_wintoggle_and_activate()
@@ -26,6 +25,15 @@
 
 
 
+extern uint16_t rrand()
+{
+    /* Constants as recommended by POSIX.1-2001 (see man page rand(3)). */
+    world.seed = ((world.seed * 1103515245) + 12345) % 4294967296;
+    return (world.seed >> 16); /* Ignore less random least significant bits. */
+}
+
+
+
 extern char * trouble_msg(char * parent, char * child)
 {
     char * p1 = "Trouble in ";
@@ -229,7 +237,6 @@ extern void turn_over(char action)
         }
         try_fclose_unlink_rename(file_new, recordfile_tmp, recordfile, f_name);
     }
-    rrand_seed(world.seed * world.turn);
 
     struct MapObj * player = get_player();
     struct MapObj * map_object = player;
@@ -279,11 +286,13 @@ extern void save_game()
     char * savefile     = "savefile";
     FILE * file = try_fopen(savefile_tmp, "w", f_name);
     char line[12];
-    sprintf(line, "%d\n", world.seed);
+    sprintf(line, "%u\n", world.mapseed);
+    try_fwrite(line, strlen(line), 1, file, f_name);
+    sprintf(line, "%u\n", world.seed);
     try_fwrite(line, strlen(line), 1, file, f_name);
-    sprintf(line, "%d\n", world.turn);
+    sprintf(line, "%u\n", world.turn);
     try_fwrite(line, strlen(line), 1, file, f_name);
-    sprintf(line, "%d\n", world.score);
+    sprintf(line, "%u\n", world.score);
     try_fwrite(line, strlen(line), 1, file, f_name);
     write_map_objects(file);
     try_fclose_unlink_rename(file, savefile_tmp, savefile, f_name);
@@ -299,6 +308,8 @@ extern void load_game()
     uint16_t linemax = get_linemax(file, f_name);
     char line[linemax + 1];
     try_fgets(line, linemax + 1, file, f_name);
+    world.mapseed = atoi(line);
+    try_fgets(line, linemax + 1, file, f_name);
     world.seed = atoi(line);
     try_fgets(line, linemax + 1, file, f_name);
     world.turn = atoi(line);
diff --git a/src/misc.h b/src/misc.h
index fad27f6..bc3e274 100644
--- a/src/misc.h
+++ b/src/misc.h
@@ -14,6 +14,12 @@ struct Map;
 
 
 
+/* Return 16-bit number pseudo-randomly generated via Linear Congruential
+ * Generator algorithm with some proven constants. Use instead of rand() to
+ * ensure portability of the same pseudo-randomness across systems.
+ */
+extern uint16_t rrand();
+
 /* Returns message: "Trouble in ".parent." with ".child."." (try_*() helper) */
 extern char * trouble_msg(char * parent, char * child);
 
diff --git a/src/rrand.c b/src/rrand.c
deleted file mode 100644
index e2b459b..0000000
--- a/src/rrand.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "rrand.h"
-#include <stdint.h> /* for uint16_t, uint32_t */
-
-
-
-static uint32_t seed = 0;
-
-
-
-extern uint16_t rrand()
-{
-    /* Constants as recommended by POSIX.1-2001 (see man page rand(3)). */
-    seed = ((seed * 1103515245) + 12345) % 2147483647;
-
-    return (seed >> 16);     /* Ignore less random least significant 16 bits. */
-}
-
-
-
-extern void rrand_seed(uint32_t new_seed)
-{
-    seed = new_seed;
-}
diff --git a/src/rrand.h b/src/rrand.h
deleted file mode 100644
index 056be9b..0000000
--- a/src/rrand.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* rrand.h
- *
- * Provide pseudo-random numbers via a Linear Congruential Generator algorithm
- * with some proven constants. Use these functions instead of rand() and
- * srand() to ensure portable pseudo-randomness portability.
- */
-
-#ifndef RRAND_H
-#define RRAND_H
-
-#include <stdint.h>    /* for uint32_t */
-
-
-
-/* Return 16-bit number pseudo-randomly generated. */
-extern uint16_t rrand();
-
-/* Set seed that rrand() starts from. */
-extern void rrand_seed(uint32_t new_seed);
-
-
-
-#endif
-- 
2.30.2