RNG patch from Allen King
authorRyan Flegel <rflegel@gmail.com>
Fri, 7 Jul 2006 07:49:14 +0000 (07:49 +0000)
committerRyan Flegel <rflegel@gmail.com>
Fri, 7 Jul 2006 07:49:14 +0000 (07:49 +0000)
SVN-Revision: 3929

src/game_session.cpp
src/game_session.hpp
src/main.cpp
src/mainloop.cpp
src/random_generator.cpp
src/random_generator.hpp

index 4495343..1159d2c 100644 (file)
@@ -179,11 +179,30 @@ GameSession::record_demo(const std::string& filename)
   capture_file = filename;
 
   char buf[30];                            // save the seed in the demo file
-  snprintf(buf, sizeof(buf), "random_seed=%010d", config->random_seed);
+  snprintf(buf, sizeof(buf), "random_seed=%10d", config->random_seed);
   for (int i=0; i==0 || buf[i-1]; i++)
     capture_demo_stream->put(buf[i]);
 }
 
+int
+GameSession::get_demo_random_seed(const std::string& filename)
+{
+  std::istream* test_stream = new std::ifstream(filename.c_str());
+  if(test_stream->good()) {
+    char buf[30];                     // recall the seed from the demo file
+    int seed;
+    for (int i=0; i<30 && (i==0 || buf[i-1]); i++)
+      test_stream->get(buf[i]);
+    if (sscanf(buf, "random_seed=%10d", &seed) == 1) {
+      log_info << "Random seed " << seed << " from demo file" << std::endl;
+         return seed;
+    }
+    else
+      log_info << "Demo file contains no random number" << std::endl;
+  }
+  return 0;
+}
+
 void
 GameSession::play_demo(const std::string& filename)
 {
@@ -201,18 +220,13 @@ GameSession::play_demo(const std::string& filename)
   demo_controller = new CodeController();
   tux.set_controller(demo_controller);
 
-  char buf[30];                            // recall the seed from the demo file
+  // skip over random seed, if it exists in the file
+  char buf[30];                            // ascii decimal seed
   int seed;
   for (int i=0; i<30 && (i==0 || buf[i-1]); i++)
     playback_demo_stream->get(buf[i]);
-  if (sscanf(buf, "random_seed=%010d", &seed) == 1) {
-    config->random_seed = seed;            // save where it will be used
-    log_info << "Taking random seed " << seed << " from demo file" <<std::endl;
-  }
-  else {
+  if (sscanf(buf, "random_seed=%010d", &seed) != 1)
     playback_demo_stream->seekg(0);     // old style w/o seed, restart at beg
-    log_info << "Demo file contains no random number" << std::endl;
-  }
 }
 
 namespace {
index 45e7ad5..59a4642 100644 (file)
@@ -46,6 +46,7 @@ public:
   ~GameSession();
 
   void record_demo(const std::string& filename);
+  int get_demo_random_seed(const std::string& filename);
   void play_demo(const std::string& filename);
 
   void draw(DrawingContext& context);
index 94045d6..3cefdc1 100644 (file)
@@ -445,7 +445,6 @@ int main(int argc, char** argv)
     
   try {
     Console::instance = new Console();
-//  srand(time(0));            // this breaks repeatability in random numbers
     init_physfs(argv[0]);
     init_sdl();
     
@@ -476,16 +475,18 @@ int main(int argc, char** argv)
       std::string dir = FileSystem::dirname(config->start_level);
       PHYSFS_addToSearchPath(dir.c_str(), true);
 
-      init_rand();        // play_demo sets seed, record_demo uses it
-
       if(config->start_level.size() > 4 &&
               config->start_level.compare(config->start_level.size() - 5, 5, ".stwm") == 0) {
+          init_rand();
           main_loop->push_screen(new WorldMapNS::WorldMap(
                       FileSystem::basename(config->start_level)));
       } else {
         std::auto_ptr<GameSession> session (
                 new GameSession(FileSystem::basename(config->start_level)));
         
+        config->random_seed =session->get_demo_random_seed(config->start_demo);
+        init_rand();
+
         if(config->start_demo != "")
           session->play_demo(config->start_demo);
 
@@ -498,6 +499,7 @@ int main(int argc, char** argv)
       main_loop->push_screen(new TitleScreen());
     }
 
+    //init_rand(); PAK: this call might subsume the above 3, but I'm chicken!
     main_loop->run();
 
   } catch(std::exception& e) {
index fb45247..f9a54f1 100644 (file)
@@ -124,7 +124,6 @@ MainLoop::run()
   DrawingContext context; 
   
   unsigned int frame_count = 0;
-  unsigned int rand_prints = 0; 
   float fps_fps = 0;
   Uint32 fps_ticks = SDL_GetTicks();
   Uint32 fps_nextframe_ticks = SDL_GetTicks();
@@ -239,11 +238,8 @@ MainLoop::run()
     }
 
     sound_manager->update();
-    // insert calls for debug (there are few rand calls otherwise)
-    if (0 && rand_prints++ % 20 == 0)
-        log_info << "== periodic rand() call " << systemRandom.rand() << 
-                " at frame " << rand_prints << "==" <<std::endl;
+
+    //log_info << "== periodic rand() = " << systemRandom.rand() << std::endl;
   }
 }
 
index c8eac09..69bd840 100644 (file)
@@ -45,6 +45,7 @@ RandomGenerator systemRandom;               // global random number generator
 RandomGenerator::RandomGenerator() {
     assert(sizeof(int) >= 4);
     initialized = 0;
+    debug = 0;                              // change this by hand for debug
     initialize();
 }
 
@@ -52,19 +53,36 @@ RandomGenerator::~RandomGenerator() {
 }
 
 int RandomGenerator::srand(int x)    {
-    while (x == 0)                          // random seed of zero means
-        x = (time(0) % RAND_MAX);           // randomize with time
-    assert(x < RAND_MAX);                   // only allow posative 31-bit seeds
-    assert(sizeof(int) >= 4);
-    srandom(x);
+    int x0 = x;
+    while (x <= 0)                          // random seed of zero means
+        x = time(0) % RandomGenerator::rand_max; // randomize with time
+
+    if (debug > 0)
+        printf("==== srand(%10d) (%10d) rand_max=%x =====\n", 
+               x, x0, RandomGenerator::rand_max);
+
+    RandomGenerator::srandom(x);
     return x;                               // let caller know seed used
 }
 
-int RandomGenerator::rand()                 {        return random();    }
+int RandomGenerator::rand() {
+    int rv;                                  // a posative int
+    while ((rv = RandomGenerator::random()) <= 0) // neg or zero causes probs
+        ;
+    if (debug > 0)
+        printf("==== rand(): %10d =====\n", rv);
+    return rv;
+}
 
 int RandomGenerator::rand(int v) {
-    assert(v != 0 && v <= RAND_MAX);        // illegal arg: 0 or too big
-    return RandomGenerator::random() % v;
+    assert(v >= 0 && v <= RandomGenerator::rand_max); // illegal arg
+
+     // remove biases, esp. when v is large (e.g. v == (rand_max/4)*3;)
+    int rv, maxV =(RandomGenerator::rand_max / v) * v;
+    assert(maxV <= RandomGenerator::rand_max);
+    while ((rv = RandomGenerator::random()) >= maxV)
+        ;
+    return rv % v;                          // mod it down to 0..(maxV-1)
 }
 
 int RandomGenerator::rand(int u, int v) {
@@ -74,8 +92,12 @@ int RandomGenerator::rand(int u, int v) {
 
 double RandomGenerator::randf(double v) {
     float rv;
-    while ((rv = (double)RandomGenerator::random() / RAND_MAX * v) >= v)
-        ;                                   // never return v!
+    do {
+               rv = ((double)RandomGenerator::random())/RandomGenerator::rand_max * v;
+       } while (rv >= v);                      // rounding might cause rv==v
+
+    if (debug > 0)
+        printf("==== rand(): %f =====\n", rv);
     return rv;
 }
 
index 9ffb0a6..4bf605e 100644 (file)
@@ -81,6 +81,8 @@ private:
     long rand_deg;
     long rand_sep;
     long *end_ptr;
+    int debug;
+    static const int rand_max = 0x7fffffff;         // biggest signed Uint32
 
 public:
     RandomGenerator();
@@ -95,7 +97,7 @@ public:
 
      // generate random 31-bit numbers
     // calls to the following return a value evenly distributed between u (or
-    // 0 if not specified) and v (or RAND_MAX if not specified).  Return
+    // 0 if not specified) and v (or rand_max if not specified).  Return
     // values may include u, but never v.
     int rand();
     int rand(int v);