00001 //---------------------------------------------------------------------------- 00002 /** @file SgRandom.h 00003 Random numbers. 00004 */ 00005 //---------------------------------------------------------------------------- 00006 00007 #ifndef SG_RANDOM_H 00008 #define SG_RANDOM_H 00009 00010 #include <algorithm> 00011 #include <list> 00012 #include <boost/random/mersenne_twister.hpp> 00013 #include "SgArray.h" 00014 00015 //---------------------------------------------------------------------------- 00016 00017 /** Random number generator. 00018 Uses a Mersenne Twister, because this is faster than std::rand() and 00019 game playing programs usually need faster random numbers more than 00020 high quality ones. All random generators are internally registered to 00021 make it possible to change the random seed for all of them. 00022 00023 SgRandom is thread-safe (w.r.t. different instances) after construction 00024 (the constructor is not thread-safe, because it uses a global variable 00025 for registration). 00026 */ 00027 class SgRandom 00028 { 00029 public: 00030 SgRandom(); 00031 00032 ~SgRandom(); 00033 00034 /** Return the global random number generator. 00035 The global generator is stored as a static variable in this function 00036 to ensure that it is initialized at first call if SgRandom is used 00037 in global variables of other compilation units. 00038 @note The global random number generator is not thread-safe. 00039 */ 00040 static SgRandom& Global(); 00041 00042 /** Set random seed for all existing and future instances of SgRandom. 00043 @param seed The seed. If negative, no seed will be set. If zero, a 00044 non-deterministic random seed will be used (e.g. derived from the 00045 current time). 00046 Also calls std::srand() 00047 @note This function is not thread-safe. 00048 */ 00049 static void SetSeed(int seed); 00050 00051 /** Get random seed. 00052 See SetSeed(int) for the special meaning of zero and negative values. 00053 */ 00054 static int Seed(); 00055 00056 /** Get a random integer. 00057 Uses a fast random generator (the Mersenne Twister boost::mt19937), 00058 because in games and Monte Carlo simulations, speed is more important 00059 than quality. 00060 */ 00061 unsigned int Int(); 00062 00063 /** Get a random integer in [0..range - 1]. */ 00064 int Int(int range); 00065 00066 /** Get a random integer in [min, max - 1] */ 00067 int Range(int min, int max); 00068 00069 /** Maximum value. */ 00070 unsigned int Max(); 00071 00072 /** convert percentage between 0 and 99 to a threshold for RandomEvent. 00073 Use as in following example: 00074 const unsigned int percent80 = PercentageThreshold(80); 00075 */ 00076 unsigned int PercentageThreshold(int percentage); 00077 00078 /** return true if random number SgRandom() <= threshold */ 00079 bool RandomEvent(unsigned int threshold); 00080 00081 private: 00082 struct GlobalData 00083 { 00084 /** The random seed. 00085 Zero means not to set a random seed. 00086 */ 00087 boost::mt19937::result_type m_seed; 00088 00089 std::list<SgRandom*> m_allGenerators; 00090 00091 GlobalData(); 00092 }; 00093 00094 /** Return global data. 00095 Global data is stored as a static variable in this function to ensure 00096 that it is initialized at first call if SgRandom is used in global 00097 variables of other compilation units. 00098 */ 00099 static GlobalData& GetGlobalData(); 00100 00101 boost::mt19937 m_generator; 00102 00103 void SetSeed(); 00104 }; 00105 00106 inline unsigned int SgRandom::Int() 00107 { 00108 return m_generator(); 00109 } 00110 00111 inline int SgRandom::Int(int range) 00112 { 00113 SG_ASSERT(range > 0); 00114 SG_ASSERT(static_cast<unsigned int>(range) <= SgRandom::Max()); 00115 int i = Int() % range; 00116 SG_ASSERTRANGE(i, 0, range - 1); 00117 return i; 00118 } 00119 00120 inline unsigned int SgRandom::Max() 00121 { 00122 return m_generator.max(); 00123 } 00124 00125 inline unsigned int SgRandom::PercentageThreshold(int percentage) 00126 { 00127 return (m_generator.max() / 100) * percentage; 00128 } 00129 00130 inline bool SgRandom::RandomEvent(unsigned int threshold) 00131 { 00132 return Int() <= threshold; 00133 } 00134 00135 inline int SgRandom::Range(int min, int max) 00136 { 00137 return min + Int(max - min); 00138 } 00139 00140 //---------------------------------------------------------------------------- 00141 00142 /** Get a random float in [min, max]. 00143 Used std::rand() 00144 */ 00145 float SgRandomFloat(float min, float max); 00146 00147 //---------------------------------------------------------------------------- 00148 00149 #endif // SG_RANDOM_H