Index: src/functions.h =================================================================== --- src/functions.h (Revision 11340) +++ src/functions.h (Arbeitskopie) @@ -45,20 +45,6 @@ //#define RANDOM_DEBUG -// Enable this to produce higher quality random numbers. -// Doesn't work with network yet. -//#define MERSENNE_TWISTER - -// Mersenne twister functions -void SeedMT(uint32 seed); -uint32 RandomMT(); - - -#ifdef MERSENNE_TWISTER - static inline uint32 Random() { return RandomMT(); } - uint RandomRange(uint max); -#else - #ifdef RANDOM_DEBUG #define Random() DoRandom(__LINE__, __FILE__) uint32 DoRandom(int line, const char *file); Index: src/mersenne.cpp =================================================================== --- src/mersenne.cpp (Revision 11340) +++ src/mersenne.cpp (Arbeitskopie) @@ -1,76 +1,205 @@ /* $Id$ */ -/** @file mersenne.cpp */ - #include "stdafx.h" #include "openttd.h" +#include "functions.h" -#ifdef MERSENNE_TWISTER +/** + * ======================= + * Abstract Random class + * ======================= + */ +struct Randomiser { + protected: + uint32 last_seed; -// Source code for Mersenne Twister. -// A Random number generator with much higher quality random numbers. + public: + virtual void Seed(uint32 seed); + virtual uint32 GetRandom(); + virtual void Sync(uint32 p0); + virtual uint32 GetSyncValue(); -#define N (624) // length of _mt_state vector -#define M (397) // a period parameter -#define K (0x9908B0DFU) // a magic constant + uint32 RandomRange(uint8 max); +}; + +uint32 Randomiser::RandomRange(uint8 max) +{ + return GB(this->GetRandom(), 0, 16) * max >> 16; +} + +/** + * ======================= + * Original random + * ======================= + */ +struct BasicRandom : Randomiser { + protected: + uint32 seeds[3]; + public: + /* virtual */ void Seed(uint32 seed); + /* virtual */ uint32 GetRandom(); + + /* virtual */ void Sync(uint32 p0); + /* virtual */ uint32 GetSyncValue() +}; + +BasicRandom::BasicRandom() +{ + this->Seed(GetTickCount()); // win32; unix uses time(null) +} + +void BasicRandom::Seed(uint32 seed) +{ + this->last_seed = seed; // _random_seeds[0][0] + this->seeds[0] = seed; // _random_seeds[0][1] + this->seeds[1] = seed * 0x1234567; // _random_seeds[1][1] + this->seeds[2] = this->seeds[1]; // _random_seeds[1][0] +} + +uint32 BasicRandom::GetRandom() +{ + register uint32 s = this->last_seed; + register uint32 t = this->seeds[0]; + + this->last_seed = s + ROR(t ^ 0x1234567F, 7) + 1; + t = ROR(s, 3) - 1; + this->seeds[0] = t; + + return t; +} + +/** + * ======================= + * Source code for Mersenne Twister. + * A Random number generator with much higher + * quality random numbers. + * ======================= + */ +#define N (624) // length of state array +#define M (397) // a period parameter +#define K (0x9908B0DFU) // a magic constant #define hiBit(u) ((u) & 0x80000000U) // mask all but highest bit of u #define loBit(u) ((u) & 0x00000001U) // mask all but lowest bit of u #define loBits(u) ((u) & 0x7FFFFFFFU) // mask the highest bit of u #define mixBits(u, v) (hiBit(u)|loBits(v)) // move hi bit of u to hi bit of v -static uint32 _mt_state[N+1]; // _mt_state vector + 1 extra to not violate ANSI C -static uint32 *_mt_next; // _mt_next random value is computed from here -static int _mt_left = -1; // can *_mt_next++ this many times before reloading +struct MersenneRandom : Randomiser { + protected: + uint32 state[N+1]; // state vector + 1 extra to not violate ANSI C + uint32 *pos; // pointer to the current state + int16 left; // remaining states -void SeedMT(uint32 seed) -{ - register uint32 x = (seed | 1U) & 0xFFFFFFFFU, *s = _mt_state; - register int j; + void Reload(); - for (_mt_left=0, *s++=x, j=N; --j; - *s++ = (x*=69069U) & 0xFFFFFFFFU); - } + public: + /* virtual */ void Seed(register uint32 seed); + /* virtual */ uint32 GetRandom(); + /* virtual */ void Sync(uint32 p0); + /* virtual */ uint32 GetSyncValue(); + MersenneRandom(); +}; -static uint32 ReloadMT() - { - register uint32 *p0=_mt_state, *p2=_mt_state+2, *pM=_mt_state+M, s0, s1; - register int j; +MersenneRandom::MersenneRandom() +{ + this->last_seed = time(NULL); + this->Seed(this->last_seed); + this->pos = this->state; +} - if (_mt_left < -1) - SeedMT(4357U); +uint32 MersenneRandom::GetSyncValue() +{ + return this->left; +} - _mt_left=N-1, _mt_next=_mt_state+1; +void MersenneRandom::Sync(uint32 p0) +{ + if ((int16)GB(p0, 0, 16) != this->left) { + int16 offset = this->left - (int16)GB(p0, 0, 16); - for (s0=_mt_state[0], s1=_mt_state[1], j=N-M+1; --j; s0=s1, s1=*p2++) - *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); + assert(this->left + offset < N); - for (pM=_mt_state, j=M; --j; s0=s1, s1=*p2++) - *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); + if (offset > 0) { + this->left += offset; + for ( ;offset != 0; offset--) { + *this->pos++; + } + } else { + /* Might need to sync the seed ? */ + } + } +} - s1=_mt_state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); - s1 ^= (s1 >> 11); - s1 ^= (s1 << 7) & 0x9D2C5680U; - s1 ^= (s1 << 15) & 0xEFC60000U; - return(s1 ^ (s1 >> 18)); - } +void MersenneRandom::Seed(register uint32 seed) +{ + this->last_seed = seed; + this->left = 0; + seed = (seed | 1U) & UINT32_MAX; + register uint32 *insert = this->state; -uint32 RandomMT() + /* Fill the state vector with new values */ + *insert = seed; + *insert++; + for (register uint16 i = N; i != 0; i--) { + seed *= 69069U; + insert = seed & UINT32_MAX; + *insert++; + } +} + +void MersenneRandom::Reload() { - uint32 y; + if (this->left < -1) + this->Seed(4357U); - if (--_mt_left < 0) - return ReloadMT(); + this->left = N-1; + this->pos = this-state + 1; - y = *_mt_next++; - y ^= (y >> 11); - y ^= (y << 7) & 0x9D2C5680U; - y ^= (y << 15) & 0xEFC60000U; - return y ^ (y >> 18); + register uint32 *p0, *p2, *pM, s0, s1; + *p0 = this->state; + *p2 = this->state + 2; + *pM = this->state + M; + s0 = this->state[0]; + s1 = this->state[1]; + + for (register uint16 i = N - M + 1; i != 0; i--) { + s0 = s1; + s1 = *p2; + p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); + *p0++; + *p2++; + *pM++; + } + + pM = this->state; + + for (register uint16 i = M; i != 0; i--) { + s0 = s1; + s1 = *p2; + p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); + *p0++; + *p2++; + *pM++; + } + + s1 = this->state[0]; + *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); } -#else -void SeedMT(uint32 seed) {} +uint32 MersenneRandom::GetRandom() +{ + uint32 value; + if (--this->left < 0) { + this->Reload(); + value = this->state[0]; + } else { + value = *this->pos++; + } -#endif /* MERSENNE_TWISTER */ + value ^= (value >> 11); + value ^= (value << 7) & 0x9D2C5680U; + value ^= (value << 15) & 0xEFC60000U; + return value ^ (value >> 18); +} + Index: src/misc.cpp =================================================================== --- src/misc.cpp (Revision 11340) +++ src/misc.cpp (Arbeitskopie) @@ -26,6 +26,8 @@ char _name_array[512][32]; +// XXX + #ifndef MERSENNE_TWISTER #ifdef RANDOM_DEBUG Index: src/win32.cpp =================================================================== --- src/win32.cpp (Revision 11340) +++ src/win32.cpp (Arbeitskopie) @@ -973,7 +973,7 @@ /* setup random seed to something quite random */ _random_seeds[1][0] = _random_seeds[0][0] = GetTickCount(); _random_seeds[1][1] = _random_seeds[0][1] = _random_seeds[0][0] * 0x1234567; - SeedMT(_random_seeds[0][0]); +// SeedMT(_random_seeds[0][0]); argc = ParseCommandLine(cmdline, argv, lengthof(argv)); Index: src/unix.cpp =================================================================== --- src/unix.cpp (Revision 11340) +++ src/unix.cpp (Arbeitskopie) @@ -137,7 +137,7 @@ #endif _random_seeds[1][1] = _random_seeds[1][0] = _random_seeds[0][1] = _random_seeds[0][0] = time(NULL); - SeedMT(_random_seeds[0][1]); +// SeedMT(_random_seeds[0][1]); signal(SIGPIPE, SIG_IGN);