summaryrefslogtreecommitdiff
path: root/src/core/random_func.cpp
blob: ff00fd604f1e1f6d6834874a90df646ef6ef152f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* $Id$ */

/** @file random_func.cpp */

#include "../stdafx.h"
#include "../macros.h"
#include "../variables.h"
#include "random_func.hpp"

uint32 InteractiveRandom()
{
	const uint32 s = _random_seeds[1][0];
	const uint32 t = _random_seeds[1][1];

	_random_seeds[1][0] = s + ROR(t ^ 0x1234567F, 7) + 1;
	return _random_seeds[1][1] = ROR(s, 3) - 1;
}

uint InteractiveRandomRange(uint max)
{
	return GB(InteractiveRandom(), 0, 16) * max >> 16;
}

#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 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

void SetRandomSeed(register uint32 seed)
{
	register uint32 *s = _mt_state;
	_mt_left = 0;

	seed |= 1U;
	seed &= 0xFFFFFFFFU;

	*s = seed;

	for (register uint i = N; i != 0; i--) {
		seed *= 69069U;
		*s++;
		*s = seed & 0xFFFFFFFFU;
	}
}

static uint32 ReloadRandom()
{
	if (_mt_left < -1) SetRandomSeed(4357U);

	_mt_left = N - 1;
	_mt_next = _mt_state + 1;

	register uint32 *p0 = _mt_state;
	register uint32 *p2 = _mt_state + 2;
	register uint32 *pM = _mt_state + M;

	register uint32 s0 = _mt_state[0];
	register uint32 s1 = _mt_state[1];

	register uint i = 0;

	for (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 = _mt_state;

	for (i = M; i != 0; i--) {
		s0 = s1;
		s1 = *p2;
		*p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
		*p0++;
		*p2++;
		*pM++;
	}

	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;
	s1 ^= (s1 >> 18);
	return s1;
}

uint32 Random()
{
	_mt_left--;
	if (_mt_left < 0) return ReloadRandom();

	uint32 y = *_mt_next;
	*_mt_next++;

	y ^= (y >> 11);
	y ^= (y <<  7) & 0x9D2C5680U;
	y ^= (y << 15) & 0xEFC60000U;
	y ^= (y >> 18);
	return y;
}

#else /* MERSENNE_TWISTER */
void SetRandomSeed(uint32 seed)
{
	_random_seeds[0][0] = seed;
	_random_seeds[0][1] = seed;
	_random_seeds[1][0] = seed * 0x1234567;
	_random_seeds[1][1] = _random_seeds[1][0];
}

#ifdef RANDOM_DEBUG
#include "network/network_data.h"
uint32 DoRandom(int line, const char *file)
{
	if (_networking && (DEREF_CLIENT(0)->status != STATUS_INACTIVE || !_network_server))
		printf("Random [%d/%d] %s:%d\n",_frame_counter, (byte)_current_player, file, line);
#else /* RANDOM_DEBUG */
uint32 Random()
{
#endif /* RANDOM_DEBUG */
	const uint32 s = _random_seeds[0][0];
	const uint32 t = _random_seeds[0][1];

	_random_seeds[0][0] = s + ROR(t ^ 0x1234567F, 7) + 1;
	return _random_seeds[0][1] = ROR(s, 3) - 1;
}
#endif /* MERSENNE_TWISTER */

#if defined(RANDOM_DEBUG) && !defined(MERSENNE_TWISTER)
uint DoRandomRange(uint max, int line, const char *file)
{
	return GB(DoRandom(line, file), 0, 16) * max >> 16;
}
#else /* RANDOM_DEBUG & !MERSENNE_TWISTER */
uint RandomRange(uint max)
{
	return GB(Random(), 0, 16) * max >> 16;
}
#endif /* RANDOM_DEBUG & !MERSENNE_TWISTER */