4 * Copyright (c) 1997 Ben Harrison, and others
6 * This software may be copied and distributed for educational, research,
7 * and not for profit purposes provided that this copyright and statement
8 * are included in all such copies. Other copyrights may also apply.
11 /* Purpose: a simple random number generator -BEN- */
13 #include "term/z-rand.h"
14 #include "util/rng-xoshiro.h"
15 #include "world/world.h"
24 * Angband 2.7.9 introduced a new (optimized) random number generator,
25 * based loosely on the old "random.c" from Berkeley but with some major
26 * optimizations and algorithm changes. See below for more details.
28 * Code by myself (benh@phial.com) and Randy (randy@stat.tamu.edu).
30 * This code provides (1) a "decent" RNG, based on the "BSD-degree-63-RNG"
31 * used in Angband 2.7.8, but rather optimized, and (2) a "simple" RNG,
32 * based on the simple "LCRNG" currently used in Angband, but "corrected"
33 * to give slightly better values. Both of these are available in two
34 * flavors, first, the simple "mod" flavor, which is fast, but slightly
35 * biased at high values, and second, the simple "div" flavor, which is
36 * less fast (and potentially non-terminating) but which is not biased
37 * and is much less subject to low-bit-non-randomness problems.
39 * You can select your favorite flavor by proper definition of the
40 * "randint0()" macro in the "defines.h" file.
42 * Note that, in Angband 2.8.0, the "state" table will be saved in the
43 * savefile, so a special "initialization" phase will be necessary.
45 * Note the use of the "simple" RNG, first you activate it via
46 * "Rand_quick = TRUE" and "Rand_value = seed" and then it is used
47 * automatically used instead of the "complex" RNG, and when you are
48 * done, you de-activate it via "Rand_quick = FALSE" or choose a new
49 * seed via "Rand_value = seed".
52 * RNG algorithm was fully rewritten. Upper comment is OLD.
55 void Rand_state_init(void)
57 using element_type = Xoshiro128StarStar::state_type::value_type;
58 constexpr auto a = std::numeric_limits<element_type>::min();
59 constexpr auto b = std::numeric_limits<element_type>::max();
61 std::random_device rd;
62 std::uniform_int_distribution<element_type> dist(a, b);
64 Xoshiro128StarStar::state_type Rand_state{};
66 std::generate(Rand_state.begin(), Rand_state.end(), [&dist, &rd] { return dist(rd); });
67 } while (std::all_of(Rand_state.begin(), Rand_state.end(), [](auto s) { return s == 0; }));
69 w_ptr->rng.set_state(Rand_state);
72 int rand_range(int a, int b)
77 std::uniform_int_distribution<> d(a, b);
82 * Generate a random integer number of NORMAL distribution
84 int16_t randnor(int mean, int stand)
87 return static_cast<int16_t>(mean);
89 std::normal_distribution<> d(mean, stand);
90 auto result = std::round(d(w_ptr->rng));
91 return static_cast<int16_t>(result);
95 * Generates damage for "2d6" style dice rolls
97 int16_t damroll(DICE_NUMBER num, DICE_SID sides)
100 for (i = 0; i < num; i++) {
101 sum += randint1(sides);
103 return (int16_t)(sum);
107 * Same as above, but always maximal
109 int16_t maxroll(DICE_NUMBER num, DICE_SID sides)
115 * Given a numerator and a denominator, supply a properly rounded result,
116 * using the RNG to smooth out remainders. -LM-
118 int32_t div_round(int32_t n, int32_t d)
122 /* Refuse to divide by zero */
131 if ((std::abs(n) % std::abs(d)) > randint0(std::abs(d))) {
132 /* Increase the absolute value */
145 * Extract a "random" number from 0 to m-1, using the RNG.
147 * This function should be used when generating random numbers in
148 * "external" program parts like the main-*.c files. It preserves
149 * the current RNG state to prevent influences on game-play.
151 * Could also use rand() from <stdlib.h> directly.
153 int32_t Rand_external(int32_t m)
159 static std::optional<Xoshiro128StarStar> urbg_external;
161 if (!urbg_external.has_value()) {
162 /* Initialize with new seed */
163 auto seed = static_cast<uint32_t>(time(nullptr));
164 urbg_external = Xoshiro128StarStar(seed);
167 std::uniform_int_distribution<> d(0, m - 1);
168 return d(urbg_external.value());