From: Ryan Flegel Date: Fri, 7 Jul 2006 07:49:14 +0000 (+0000) Subject: RNG patch from Allen King X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=d41074beb3da03264ec115c29ff502729477bf87;p=supertux.git RNG patch from Allen King SVN-Revision: 3929 --- diff --git a/src/game_session.cpp b/src/game_session.cpp index 4495343fd..1159d2ce4 100644 --- a/src/game_session.cpp +++ b/src/game_session.cpp @@ -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" <seekg(0); // old style w/o seed, restart at beg - log_info << "Demo file contains no random number" << std::endl; - } } namespace { diff --git a/src/game_session.hpp b/src/game_session.hpp index 45e7ad54c..59a464280 100644 --- a/src/game_session.hpp +++ b/src/game_session.hpp @@ -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); diff --git a/src/main.cpp b/src/main.cpp index 94045d612..3cefdc1b4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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 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) { diff --git a/src/mainloop.cpp b/src/mainloop.cpp index fb45247c7..f9a54f18d 100644 --- a/src/mainloop.cpp +++ b/src/mainloop.cpp @@ -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 << "==" < 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; } diff --git a/src/random_generator.hpp b/src/random_generator.hpp index 9ffb0a617..4bf605ea0 100644 --- a/src/random_generator.hpp +++ b/src/random_generator.hpp @@ -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);