Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include "global.hpp"
00042
00043 #include "config.hpp"
00044 #include "log.hpp"
00045 #include "network.hpp"
00046 #include "random.hpp"
00047 #include "rng.hpp"
00048 #include "serialization/string_utils.hpp"
00049 #include "simple_rng.hpp"
00050 #include "util.hpp"
00051
00052 static lg::log_domain log_random("random");
00053 #define DBG_RND LOG_STREAM(debug, log_random)
00054 #define LOG_RND LOG_STREAM(info, log_random)
00055 #define WRN_RND LOG_STREAM(warn, log_random)
00056 #define ERR_RND LOG_STREAM(err, log_random)
00057
00058 namespace {
00059 rand_rng::rng *random_generator = NULL ;
00060 int last_seed;
00061 bool seed_valid = false;
00062 boost::function<void (int)> new_seed_callback;
00063 }
00064
00065
00066 int get_random()
00067 {
00068 assert(random_generator!=NULL);
00069 int r = random_generator->get_random();
00070 return r ;
00071 }
00072
00073 int get_random_nocheck()
00074 {
00075 assert(random_generator!=NULL);
00076 int r = random_generator->get_random_nocheck();
00077 return r ;
00078 }
00079
00080 const config* get_random_results()
00081 {
00082 assert(random_generator!=NULL);
00083 return random_generator->get_random_results();
00084 }
00085
00086
00087 void set_random_results(const config& cfg)
00088 {
00089 assert(random_generator!=NULL);
00090 random_generator->set_random_results(cfg);
00091 }
00092
00093
00094 namespace rand_rng
00095 {
00096
00097 void set_seed(int seed)
00098 {
00099 LOG_RND << "set_seed with " << seed << "\n";
00100 assert(random_generator!=NULL);
00101 last_seed = seed;
00102 seed_valid = true;
00103 random_generator->set_seed(seed);
00104 if (new_seed_callback) {
00105 LOG_RND << "set_seed calling new_seed_callback\n";
00106 new_seed_callback(seed);
00107 }
00108 }
00109
00110 void invalidate_seed()
00111 {
00112 LOG_RND << "invalidate_seed\n";
00113 assert(random_generator!=NULL);
00114 last_seed = rand() & 0x7FFFFFFF;
00115 if (has_valid_seed()) {
00116 random_generator->set_seed(last_seed);
00117 }
00118 seed_valid = false;
00119 }
00120
00121 bool has_valid_seed()
00122 {
00123
00124 return (network::nconnections() == 0) || seed_valid;
00125 }
00126
00127 int get_last_seed()
00128 {
00129 return last_seed;
00130 }
00131
00132 void set_new_seed_callback(boost::function<void (int)> f)
00133 {
00134 DBG_RND << "set_new_seed_callback\n";
00135 new_seed_callback = f;
00136 }
00137
00138 bool has_new_seed_callback()
00139 {
00140 return new_seed_callback != NULL;
00141 }
00142
00143 void clear_new_seed_callback()
00144 {
00145 DBG_RND << "clear_new_seed_callback\n";
00146 new_seed_callback = NULL;
00147 }
00148
00149
00150
00151 rng::rng() : random_(NULL), random_child_(0), generator_()
00152 {
00153 }
00154
00155 int rng::get_random()
00156 {
00157 return get_random_private(true);
00158 }
00159
00160 int rng::get_random_nocheck()
00161 {
00162 return get_random_private(false);
00163 }
00164
00165 int rng::get_random_private(bool check)
00166 {
00167 if (!random_) {
00168 int r = generator_.get_next_random();
00169 LOG_RND << "get_random() returning " << r << " (random_ is null)\n";
00170 return r;
00171 }
00172
00173 size_t random_size = random_->child_count("random");
00174 if (random_child_ >= random_size) {
00175 random_child_ = random_size + 1;
00176 int res = generator_.get_next_random() & 0x7FFFFFFF;
00177 (random_->add_child("random"))["value"] = res;
00178 LOG_RND << "get_random() returning " << res << " (added to random_)\n";
00179 return res;
00180 } else {
00181 int mine = generator_.get_next_random();
00182 int stored = random_->child("random", random_child_++)["value"];
00183 if (mine != stored) {
00184 if (check) {
00185 ERR_RND << "Random number mismatch, mine " << mine << " vs " << stored << "\n";
00186
00187 } else {
00188 LOG_RND << "Random number mismatch (nocheck), mine " << mine << " vs " << stored << "\n";
00189 }
00190 }
00191 LOG_RND << "get_random() returning " << stored << "\n";
00192 return stored;
00193 }
00194 }
00195
00196 const config* rng::get_random_results()
00197 {
00198 assert(random_ != NULL);
00199
00200 if (random_child_ <= 0 ||random_child_ > random_->child_count("random")) return NULL;
00201 const config &res = random_->child("random", random_child_ - 1).child("results");
00202 return res ? &res : NULL;
00203 }
00204
00205 void rng::set_random_results(const config& cfg)
00206 {
00207 assert(random_ != NULL);
00208
00209 if (random_child_ <= 0 ||random_child_ > random_->child_count("random")) return;
00210 config &r = random_->child("random", random_child_ - 1);
00211 r.clear_children("results");
00212 r.add_child("results", cfg);
00213 }
00214
00215 config* rng::random()
00216 {
00217 return random_;
00218 }
00219
00220 void rng::set_random(config* random)
00221 {
00222 random_ = random;
00223 random_child_ = 0;
00224 return;
00225 }
00226
00227 void rng::set_seed(int seed)
00228 {
00229 LOG_RND << "Set random seed to " << seed << "\n";
00230 generator_.seed_random(seed, 0);
00231 }
00232
00233
00234 set_random_generator::set_random_generator(rng* r) : old_(random_generator)
00235 {
00236 random_generator = r;
00237 }
00238
00239 set_random_generator::~set_random_generator()
00240 {
00241 random_generator = old_;
00242 }
00243
00244 simple_rng::simple_rng() :
00245 random_seed_(rand() & 0x7FFFFFFF),
00246 random_pool_(random_seed_),
00247 random_calls_(0)
00248 {
00249 }
00250
00251 simple_rng::simple_rng(const config& cfg) :
00252 random_seed_(cfg["random_seed"]),
00253 random_pool_(random_seed_),
00254 random_calls_(0)
00255 {
00256 }
00257
00258 int simple_rng::get_next_random()
00259 {
00260 random_next();
00261 ++random_calls_;
00262 DBG_RND << "pulled user random " << random_pool_
00263 << " for call " << random_calls_
00264 << " with seed " << random_seed_ << '\n';
00265
00266 return (random_pool_ / 65536) % 32768;
00267 }
00268
00269 void simple_rng::seed_random(const unsigned call_count)
00270 {
00271 seed_random(random_seed_, call_count);
00272 }
00273
00274 void simple_rng::rotate_random()
00275 {
00276 random_seed_ = random_pool_ & 0x7FFFFFFF;
00277 random_calls_ = 0;
00278 }
00279
00280 void simple_rng::seed_random(const int seed, const unsigned call_count)
00281 {
00282 random_pool_ = seed;
00283 random_seed_ = seed;
00284 for(random_calls_ = 0; random_calls_ < call_count; ++random_calls_) {
00285 random_next();
00286 }
00287 DBG_RND << "Seeded random with " << random_seed_ << " with "
00288 << random_calls_ << " calls, pool is now at "
00289 << random_pool_ << '\n';
00290 }
00291
00292 void simple_rng::random_next()
00293 {
00294
00295
00296
00297 random_pool_ = random_pool_ * 1103515245 + 12345;
00298 }
00299
00300
00301 }
00302