random.cpp

Go to the documentation of this file.
00001 /* $Id: random.cpp 25481 2008-04-02 22:10:35Z jhinrichs $ */
00002 /*
00003    Copyright (C) 2003 by David White <dave@whitevine.net>
00004    Copyright (C) 2005 - 2008 by Yann Dirson <ydirson@altern.org>
00005    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License version 2
00009    or at your option any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 //! @file random.cpp
00017 //! Generate random numbers.
00018 //!
00019 //! There are various ways to get a random number.
00020 //! rand()              This can be used for things that never are send over the
00021 //!                     network e.g. generate a random map (the final result the
00022 //!                     map is send, but the other players don't need to generate
00023 //!                     the map.
00024 //!
00025 //! get_random()        A random generator which is syncronized over the network
00026 //!                     this only seems to work when it's used by 1 player at the
00027 //!                     same time. It's syncronized after an event so if an event
00028 //!                     runs at two clients at the same time it gets out of sync
00029 //!                     and sets the entire game out of sync.
00030 //!
00031 //! game_state::get_random()
00032 //!                     A random generator which is seeded by the host of an MP
00033 //!                     game. This generator is (not yet) synchronized over the
00034 //!                     network. It's only used by [set_variable]rand=. The map
00035 //!                     designer has to make sure it stays in sync. This
00036 //!                     generator can be used at the same time at multiple client
00037 //!                     since the generators are always in sync.
00038 
00039 #include "global.hpp"
00040 
00041 #include "config.hpp"
00042 #include "random.hpp"
00043 #include "util.hpp"
00044 
00045 #include <cassert>
00046 #include <cstdio>
00047 #include <sstream>
00048 
00049 rng::rng() : random_(NULL), random_child_(0)
00050 {}
00051 
00052 int rng::get_random()
00053 {
00054     if (!random_)
00055         return rand() & 0x7FFFFFFF;
00056 
00057     const config::child_list random(random_->get_children("random"));
00058     if (random_child_ >= random.size()) {
00059         random_child_ = random.size() + 1;
00060         int res = rand() & 0x7FFFFFFF;
00061         (random_->add_child("random"))["value"] = lexical_cast<std::string>(res);
00062         return res;
00063     } else {
00064         return lexical_cast_default<int>((*random[random_child_++])["value"], 0);
00065     }
00066 }
00067 
00068 const config* rng::get_random_results()
00069 {
00070     assert(random_ != NULL);
00071 
00072     const config::child_list random(random_->get_children("random"));
00073     if (random_child_ <= 0 ||random_child_ > random.size()) return NULL;
00074     return random[random_child_-1]->child("results");
00075 }
00076 
00077 void rng::set_random_results(const config& cfg)
00078 {
00079     assert(random_ != NULL);
00080 
00081     const config::child_list random(random_->get_children("random"));
00082     if (random_child_ <= 0 || random_child_ > random.size()) return;
00083     random[random_child_-1]->clear_children("results");
00084     random[random_child_-1]->add_child("results",cfg);
00085 }
00086 
00087 config* rng::random()
00088 {
00089     return random_;
00090 }
00091 
00092 void rng::set_random(config* random)
00093 {
00094     random_ = random;
00095     random_child_ = 0;
00096     return;
00097 }
00098 
00099 namespace {
00100 rng* random_generator = NULL;
00101 }
00102 
00103 set_random_generator::set_random_generator(rng* r) : old_(random_generator)
00104 {
00105     random_generator = r;
00106 }
00107 
00108 set_random_generator::~set_random_generator()
00109 {
00110     random_generator = old_;
00111 }
00112 
00113 int get_random()
00114 {
00115     assert(random_generator!=NULL);
00116     return random_generator->get_random();
00117 }
00118 
00119 const config* get_random_results()
00120 {
00121     assert(random_generator!=NULL);
00122     return random_generator->get_random_results();
00123 }
00124 
00125 void set_random_results(const config& cfg)
00126 {
00127     assert(random_generator!=NULL);
00128     random_generator->set_random_results(cfg);
00129 }
00130 
00131 simple_rng::simple_rng() :
00132     random_seed_(rand()),
00133     random_pool_(random_seed_),
00134     random_calls_(0)
00135 {}
00136 
00137 simple_rng::simple_rng(const config& cfg) :
00138     //! @todo  older savegames don't have random_seed stored, evaluate later
00139     //! whether default can be removed again. Look after branching 1.5.
00140     random_seed_(lexical_cast_default<int>(cfg["random_seed"], 42)),
00141     random_pool_(random_seed_),
00142     random_calls_(0)
00143 {}
00144 
00145 //! Get a new random number.
00146 int simple_rng::get_random()
00147 {
00148     random_next();
00149     ++random_calls_;
00150     //DBG_NG << "pulled user random " << random_pool_
00151     //  << " for call " << random_calls_ << '\n';
00152 
00153     return (static_cast<unsigned>(random_pool_ / 65536) % 32768);
00154 }
00155 
00156 //! Seeds the random pool.
00157 //!
00158 //! @param call_count   Upon loading we need to restore the state at saving
00159 //!                     so set the number of times a random number is generated
00160 //!                     for replays the orginal value is required.
00161 void simple_rng::seed_random(const unsigned call_count)
00162 {
00163     seed_random(random_seed_, call_count);
00164 }
00165 
00166 //! Seeds the random pool.
00167 //!
00168 //! @param seed         The initial value for the random engine.
00169 //! @param call_count   Upon loading we need to restore the state at saving
00170 //!                     so set the number of times a random number is generated
00171 //!                     for replays the orginal value is required.
00172 void simple_rng::seed_random(const int seed, const unsigned call_count)
00173 {
00174     random_pool_ = seed;
00175     random_seed_ = seed;
00176     for(random_calls_ = 0; random_calls_ < call_count; ++random_calls_) {
00177         random_next();
00178     }
00179     //DBG_NG << "Seeded random with " << random_seed_ << " with "
00180     //  << random_calls_ << " calls, pool is now at "
00181     //  << random_pool_ << '\n';
00182 }
00183 
00184 //! Sets the next random number in the pool.
00185 void simple_rng::random_next()
00186 {
00187     // Use the simple random generator as shown in man rand(3).
00188     // The division is done separately since we also want to
00189     // quickly go the the wanted index in the random list.
00190     random_pool_ = random_pool_ * 1103515245 + 12345;
00191 }
00192 

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs