replaced glib function calls to g_file_get_contents()
[rocksndiamonds.git] / src / game_bd / bd_random.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* Originally developed and coded by Makoto Matsumoto and Takuji
21  * Nishimura.  Please mail <matumoto@math.keio.ac.jp>, if you're using
22  * code from this file in your own programs or libraries.
23  * Further information on the Mersenne Twister can be found at
24  * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
25  * This code was adapted to glib by Sebastian Wilhelmi.
26  */
27
28 /*
29  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
30  * file for a list of people on the GLib Team.  See the ChangeLog
31  * files for a list of changes.  These files are distributed with
32  * GLib at ftp://ftp.gtk.org/pub/gtk/.
33  */
34
35 #include <math.h>
36 #include <errno.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <unistd.h>
41
42 #if defined(PLATFORM_WINDOWS)
43 #include <process.h>    /* for getpid() */
44 #endif
45
46 #include "main_bd.h"
47
48
49 /**
50  * GdRand:
51  *
52  * The GdRand struct is an opaque data structure. It should only be
53  * accessed through the gd_rand_* functions.
54  **/
55
56 /* Period parameters */
57 #define N 624
58 #define M 397
59 #define MATRIX_A   0x9908b0df /* constant vector a */
60 #define UPPER_MASK 0x80000000 /* most significant w-r bits */
61 #define LOWER_MASK 0x7fffffff /* least significant r bits */
62
63 /* Tempering parameters */
64 #define TEMPERING_MASK_B 0x9d2c5680
65 #define TEMPERING_MASK_C 0xefc60000
66 #define TEMPERING_SHIFT_U(y)  (y >> 11)
67 #define TEMPERING_SHIFT_S(y)  (y << 7)
68 #define TEMPERING_SHIFT_T(y)  (y << 15)
69 #define TEMPERING_SHIFT_L(y)  (y >> 18)
70
71 struct _GdRand
72 {
73   unsigned int mt[N]; /* the array for the state vector  */
74   unsigned int mti;
75 };
76
77 /**
78  * gd_rand_new_with_seed: (constructor)
79  * @seed: a value to initialize the random number generator
80  *
81  * Creates a new random number generator initialized with @seed.
82  *
83  * Returns: (transfer full): the new #GdRand
84  **/
85 GdRand *
86 gd_rand_new_with_seed (unsigned int seed)
87 {
88   GdRand *rand = checked_calloc(sizeof(GdRand));
89   gd_rand_set_seed (rand, seed);
90   return rand;
91 }
92
93 /**
94  * gd_rand_new_with_seed_array: (constructor)
95  * @seed: an array of seeds to initialize the random number generator
96  * @seed_length: an array of seeds to initialize the random number
97  *     generator
98  *
99  * Creates a new random number generator initialized with @seed.
100  *
101  * Returns: (transfer full): the new #GdRand
102  *
103  * Since: 2.4
104  */
105 GdRand *
106 gd_rand_new_with_seed_array (const unsigned int *seed, unsigned int seed_length)
107 {
108   GdRand *rand = checked_calloc(sizeof(GdRand));
109   gd_rand_set_seed_array (rand, seed, seed_length);
110
111   return rand;
112 }
113
114 /**
115  * gd_rand_new: (constructor)
116  *
117  * Creates a new random number generator initialized with a seed taken
118  * either from `/dev/urandom` (if existing) or from the current time
119  * (as a fallback).
120  *
121  * On Windows, the seed is taken from rand_s().
122  *
123  * Returns: (transfer full): the new #GdRand
124  */
125 GdRand *
126 gd_rand_new (void)
127 {
128   unsigned int seed[4];
129
130 #if defined(PLATFORM_UNIX)
131   static boolean dev_urandom_exists = TRUE;
132
133   if (dev_urandom_exists)
134   {
135     FILE *dev_urandom;
136
137     do
138     {
139       dev_urandom = fopen ("/dev/urandom", "rbe");
140     }
141     while (dev_urandom == NULL && errno == EINTR);
142
143     if (dev_urandom)
144     {
145       int r;
146
147       setvbuf (dev_urandom, NULL, _IONBF, 0);
148
149       do
150       {
151         errno = 0;
152         r = fread (seed, sizeof (seed), 1, dev_urandom);
153       }
154       while (errno == EINTR);
155
156       if (r != 1)
157         dev_urandom_exists = FALSE;
158
159       fclose (dev_urandom);
160     }
161     else
162     {
163       dev_urandom_exists = FALSE;
164     }
165   }
166
167   if (!dev_urandom_exists)
168   {
169     struct timespec now;
170
171     clock_gettime(CLOCK_REALTIME, &now);
172
173     seed[0] = now.tv_sec;
174     seed[1] = now.tv_nsec;
175     seed[2] = getpid ();
176     seed[3] = getppid ();
177   }
178 #else /* PLATFORM_WINDOWS */
179   /* rand_s() is only available since Visual Studio 2005 and
180    * MinGW-w64 has a wrapper that will emulate rand_s() if it's not in msvcrt
181    */
182 #if (defined(_MSC_VER) && _MSC_VER >= 1400) || defined(__MINGW64_VERSION_MAJOR)
183   size_t i;
184
185   for (i = 0; i < ARRAY_SIZE(seed); i++)
186     rand_s (&seed[i]);
187 #else
188 #warning Using insecure seed for random number generation because of missing rand_s() in Windows XP
189   GTimeVal now;
190
191   gd_get_current_time (&now);
192
193   seed[0] = now.tv_sec;
194   seed[1] = now.tv_usec;
195   seed[2] = getpid ();
196   seed[3] = 0;
197 #endif
198
199 #endif
200
201   return gd_rand_new_with_seed_array (seed, 4);
202 }
203
204 /**
205  * gd_rand_free:
206  * @rand_: a #GdRand
207  *
208  * Frees the memory allocated for the #GdRand.
209  */
210 void
211 gd_rand_free (GdRand *rand)
212 {
213   if (rand != NULL)
214     checked_free(rand);
215 }
216
217 /**
218  * gd_rand_copy:
219  * @rand_: a #GdRand
220  *
221  * Copies a #GdRand into a new one with the same exact state as before.
222  * This way you can take a snapshot of the random number generator for
223  * replaying later.
224  *
225  * Returns: (transfer full): the new #GdRand
226  *
227  * Since: 2.4
228  */
229 GdRand *
230 gd_rand_copy (GdRand *rand)
231 {
232   GdRand *new_rand;
233
234   if (rand == NULL)
235     return NULL;
236
237   new_rand = checked_calloc(sizeof(GdRand));
238   memcpy(new_rand, rand, sizeof(GdRand));
239
240   return new_rand;
241 }
242
243 /**
244  * gd_rand_set_seed:
245  * @rand_: a #GdRand
246  * @seed: a value to reinitialize the random number generator
247  *
248  * Sets the seed for the random number generator #GdRand to @seed.
249  */
250 void
251 gd_rand_set_seed (GdRand *rand, unsigned int seed)
252 {
253   if (rand == NULL)
254     return;
255
256   /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
257   /* In the previous version (see above), MSBs of the    */
258   /* seed affect only MSBs of the array mt[].            */
259
260   rand->mt[0] = seed;
261   for (rand->mti = 1; rand->mti < N; rand->mti++)
262     rand->mt[rand->mti] = 1812433253UL *
263       (rand->mt[rand->mti - 1] ^ (rand->mt[rand->mti - 1] >> 30)) + rand->mti;
264 }
265
266 /**
267  * gd_rand_set_seed_array:
268  * @rand_: a #GdRand
269  * @seed: array to initialize with
270  * @seed_length: length of array
271  *
272  * Initializes the random number generator by an array of longs.
273  * Array can be of arbitrary size, though only the first 624 values
274  * are taken.  This function is useful if you have many low entropy
275  * seeds, or if you require more then 32 bits of actual entropy for
276  * your application.
277  *
278  * Since: 2.4
279  */
280 void
281 gd_rand_set_seed_array (GdRand *rand, const unsigned int *seed, unsigned int seed_length)
282 {
283   unsigned int i, j, k;
284
285   if (rand == NULL || seed_length < 1)
286     return;
287
288   gd_rand_set_seed (rand, 19650218UL);
289
290   i = 1;
291   j = 0;
292   k = (N > seed_length ? N : seed_length);
293
294   for (; k; k--)
295   {
296     rand->mt[i] = ((rand->mt[i] ^ ((rand->mt[i - 1] ^ (rand->mt[i - 1] >> 30)) * 1664525UL))
297                    + seed[j] + j);      /* non linear */
298     rand->mt[i] &= 0xffffffffUL;        /* for WORDSIZE > 32 machines */
299     i++;
300     j++;
301
302     if (i >= N)
303     {
304       rand->mt[0] = rand->mt[N - 1];
305       i = 1;
306     }
307
308     if (j >= seed_length)
309       j = 0;
310   }
311
312   for (k = N - 1; k; k--)
313   {
314     rand->mt[i] = ((rand->mt[i] ^ ((rand->mt[i - 1] ^ (rand->mt[i - 1] >> 30)) * 1566083941UL))
315                    - i);                /* non linear */
316     rand->mt[i] &= 0xffffffffUL;        /* for WORDSIZE > 32 machines */
317     i++;
318
319     if (i >= N)
320     {
321       rand->mt[0] = rand->mt[N - 1];
322       i = 1;
323     }
324   }
325
326   rand->mt[0] = 0x80000000UL;           /* MSB is 1; assuring non-zero initial array */
327 }
328
329 /**
330  * gd_rand_boolean:
331  * @rand_: a #GdRand
332  *
333  * Returns a random #boolean from @rand_.
334  * This corresponds to an unbiased coin toss.
335  *
336  * Returns: a random #boolean
337  */
338 /**
339  * gd_rand_int:
340  * @rand_: a #GdRand
341  *
342  * Returns the next random unsigned int from @rand_ equally distributed over
343  * the range [0..2^32-1].
344  *
345  * Returns: a random number
346  */
347 unsigned int
348 gd_rand_int (GdRand *rand)
349 {
350   unsigned int y;
351   static const unsigned int mag01[2] = { 0x0, MATRIX_A };
352   /* mag01[x] = x * MATRIX_A  for x=0,1 */
353
354   if (rand == NULL)
355     return 0;
356
357   if (rand->mti >= N)
358   {
359     /* generate N words at one time */
360     int kk;
361
362     for (kk = 0; kk < N - M; kk++)
363     {
364       y = (rand->mt[kk] & UPPER_MASK) | (rand->mt[kk + 1] & LOWER_MASK);
365       rand->mt[kk] = rand->mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1];
366     }
367
368     for (; kk < N - 1; kk++)
369     {
370       y = (rand->mt[kk] & UPPER_MASK) | (rand->mt[kk + 1] & LOWER_MASK);
371       rand->mt[kk] = rand->mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1];
372     }
373
374     y = (rand->mt[N - 1] & UPPER_MASK) | (rand->mt[0] & LOWER_MASK);
375     rand->mt[N - 1] = rand->mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1];
376
377     rand->mti = 0;
378   }
379
380   y = rand->mt[rand->mti++];
381   y ^= TEMPERING_SHIFT_U(y);
382   y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
383   y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
384   y ^= TEMPERING_SHIFT_L(y);
385
386   return y;
387 }
388
389 /**
390  * gd_rand_int_range:
391  * @rand_: a #GdRand
392  * @begin: lower closed bound of the interval
393  * @end: upper open bound of the interval
394  *
395  * Returns the next random #int from @rand_ equally distributed over
396  * the range [@begin..@end-1].
397  *
398  * Returns: a random number
399  */
400 int
401 gd_rand_int_range (GdRand *rand, int begin, int end)
402 {
403   unsigned int dist = end - begin;
404   unsigned int random = 0;
405
406   if (rand == NULL || end <= begin)
407     return begin;
408
409   if (dist == 0)
410     return begin;
411
412   /* maxvalue is set to the predecessor of the greatest
413    * multiple of dist less or equal 2^32.
414    */
415   unsigned int maxvalue;
416   if (dist <= 0x80000000u) /* 2^31 */
417   {
418     /* maxvalue = 2^32 - 1 - (2^32 % dist) */
419     unsigned int leftover = (0x80000000u % dist) * 2;
420     if (leftover >= dist) leftover -= dist;
421     maxvalue = 0xffffffffu - leftover;
422   }
423   else
424   {
425     maxvalue = dist - 1;
426   }
427
428   do
429     random = gd_rand_int (rand);
430   while (random > maxvalue);
431
432   random %= dist;
433
434   return begin + random;
435 }
436
437 static GdRand *
438 get_global_random (void)
439 {
440   static GdRand *global_random;
441
442   /* called while locked */
443   if (!global_random)
444     global_random = gd_rand_new();
445
446   return global_random;
447 }
448
449 /**
450  * gd_random_int_range:
451  * @begin: lower closed bound of the interval
452  * @end: upper open bound of the interval
453  *
454  * Returns a random #int equally distributed over the range
455  * [@begin..@end-1].
456  *
457  * Returns: a random number
458  */
459 int
460 gd_random_int_range (int begin, int end)
461 {
462   int result;
463
464   result = gd_rand_int_range (get_global_random(), begin, end);
465
466   return result;
467 }