Index: src/mersenne.cpp =================================================================== --- src/mersenne.cpp (Revision 11339) +++ src/mersenne.cpp (Arbeitskopie) @@ -4,71 +4,124 @@ #include "stdafx.h" #include "openttd.h" +#include "functions.h" #ifdef MERSENNE_TWISTER // Source code for Mersenne Twister. // A Random number generator with much higher quality random numbers. -#define N (624) // length of _mt_state vector -#define M (397) // a period parameter -#define K (0x9908B0DFU) // a magic constant +#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 { + 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) + void Reload(); + + public: + void Seed(register uint32 seed); + uint32 GetRandom(); + + void Sync(uint32 pos); + uint32 GetSyncValue(); +}; + +uint32 MersenneRandom::GetSyncValue() { - register uint32 x = (seed | 1U) & 0xFFFFFFFFU, *s = _mt_state; - register int j; + return this->left; +} - for (_mt_left=0, *s++=x, j=N; --j; - *s++ = (x*=69069U) & 0xFFFFFFFFU); - } +void MersenneRandom::Sync(uint32 pos) +{ + if ((int16)GB(pos, 0, 16) != this->left) { + int16 offset = this->left - (int16)GB(pos, 0, 16); + assert(this->left + offset < N); -static uint32 ReloadMT() - { - register uint32 *p0=_mt_state, *p2=_mt_state+2, *pM=_mt_state+M, s0, s1; - register int j; + if (offset > 0) { + this->left += offset; + for ( ;offset != 0; offset--) { + *pos++; + } + } else { + /* Might need to sync the seed ? */ + } + } +} - if (_mt_left < -1) - SeedMT(4357U); +void MersenneRandom::Seed(register uint32 seed) +{ + this->left = 0; + seed = (seed | 1U) & UINT32_MAX; - _mt_left=N-1, _mt_next=_mt_state+1; + register uint32 *insert = this->state; - 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); + /* Fill the state vector with new values */ + *insert++ = seed; + for (register uint16 i = N; i != 0; i--) { + seed *= 69069U; + *insert++ = seed & UINT32_MAX; + } +} - for (pM=_mt_state, j=M; --j; s0=s1, s1=*p2++) - *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); +void MersenneRandom::Reload() +{ + if (this->left < -1) + this->Seed(4357U); - 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)); - } + this->left = N-1; + this->pos = this-state + 1; + 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]; -uint32 RandomMT() + for (register uint16 i = N - M + 1; i != 0; i--) { + s0 = s1; + s1 = *p2++; + *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); + } + + 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); + } + + s1 = this->state[0]; + *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U); +} + +uint32 MersenneRandom::GetRandom() { - uint32 y; + uint32 value; + if (--this->left < 0) { + this->Reload(); + value = this->state[0]; + } else { + value = *this->pos++; + } - if (--_mt_left < 0) - return ReloadMT(); + value ^= (value >> 11); + value ^= (value << 7) & 0x9D2C5680U; + value ^= (value << 15) & 0xEFC60000U; + return value ^ (value >> 18); +} - y = *_mt_next++; - y ^= (y >> 11); - y ^= (y << 7) & 0x9D2C5680U; - y ^= (y << 15) & 0xEFC60000U; - return y ^ (y >> 18); -} #else void SeedMT(uint32 seed) {} Index: config.lib =================================================================== --- config.lib (Revision 11339) +++ config.lib (Arbeitskopie) @@ -34,6 +34,7 @@ enable_debug="0" enable_profiling="0" enable_dedicated="0" + enable_mersenne="0" enable_network="1" enable_static="1" enable_translator="0" @@ -62,7 +63,7 @@ with_psp_config="1" with_threads="1" - save_params_array="build host cc_build cc_host cxx_build cxx_host windres strip awk lipo os cpu_type revision endian config_log prefix_dir binary_dir data_dir icon_dir personal_dir install_dir enable_debug enable_profiling enable_dedicated enable_network enable_static enable_translator enable_assert enable_strip with_distcc with_osx_sysroot enable_universal enable_osx_g5 enable_unicode with_application_bundle with_sdl with_cocoa with_zlib with_png with_makedepend with_direct_music with_sort with_iconv with_midi with_midi_arg with_libtimidity with_freetype with_fontconfig with_psp_config with_threads CC CXX CFLAGS LDFLAGS" + save_params_array="build host cc_build cc_host cxx_build cxx_host windres strip awk lipo os cpu_type revision endian config_log prefix_dir binary_dir data_dir icon_dir personal_dir install_dir enable_debug enable_profiling enable_dedicated enable_mersenne enable_network enable_static enable_translator enable_assert enable_strip with_distcc with_osx_sysroot enable_universal enable_osx_g5 enable_unicode with_application_bundle with_sdl with_cocoa with_zlib with_png with_makedepend with_direct_music with_sort with_iconv with_midi with_midi_arg with_libtimidity with_freetype with_fontconfig with_psp_config with_threads CC CXX CFLAGS LDFLAGS" } detect_params() { @@ -146,6 +147,8 @@ --enable-profiling=*) enable_profiling="$optarg";; --enable-dedicated) enable_dedicated="1";; --enable-dedicated=*) enable_dedicated="$optarg";; + --enable-mersenne) enable_mersenne="1";; + --enable-mersenne=*) enable_mersenne="$optarg";; --enable-network=*) enable_network="$optarg";; --disable-network) enable_network="0";; --disable-static) enable_static="0";; @@ -454,6 +457,10 @@ log 1 "checking network... disabled" fi + if [ "$enable_mersenne" != "0" ] && [ "$enable_network" != "0" ]; then + log 1 "WARNING: using mersenne is not multiplayer stable" + fi + if [ "$enable_translator" != "0" ]; then log 1 "checking translator... debug" # -t shows TODO items, normally they are muted @@ -1021,6 +1028,10 @@ CFLAGS="$CFLAGS -DDEDICATED" fi + if [ "$enable_mersenne" != "0" ]; then + CFLAGS="$CFLAGS -DMERSENNE_TWISTER" + fi + if [ "$enable_unicode" != "0" ]; then CFLAGS="$CFLAGS -DUNICODE -D_UNICODE" fi @@ -2140,6 +2151,8 @@ echo " --enable-debug[=LVL] enable debug-mode (LVL=[0123], 0 is release)" echo " --enable-profiling enables profiling" echo " --enable-dedicated compile a dedicated server (without video)" + echo " --enable-mersenne use the mersenne twister for random numbers" + echo " (Not multiplayer save)" echo " --enable-static enable static compile (doesn't work for" echo " all HOSTs)" echo " --enable-translator enable extra output for translators"