OSDN Git Service

[Refactor] #3496 optional 型の存在判定 has_value() を撤廃した その6
[hengbandforosx/hengbandosx.git] / src / term / z-rand.cpp
index 7d2b7c6..44b31ff 100644 (file)
@@ -1,4 +1,4 @@
-/* File: z-rand.c */
+/* File: z-rand.c */
 
 /*
  * Copyright (c) 1997 Ben Harrison, and others
 
 /* Purpose: a simple random number generator -BEN- */
 
-#if defined(WINDOWS)
-#include <Windows.h>
-#endif
-
 #include "term/z-rand.h"
+#include "util/rng-xoshiro.h"
+#include "world/world.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+#include <optional>
+#include <random>
 
 /*
  * Angband 2.7.9 introduced a new (optimized) random number generator,
  * RNG algorithm was fully rewritten. Upper comment is OLD.
  */
 
-/*
- * Currently unused
- */
-u16b Rand_place;
-
-/*
- * Current "state" table for the RNG
- * Only index 0 to 3 are used
- */
-u32b Rand_state[RAND_DEG] = {
-    123456789,
-    362436069,
-    521288629,
-    88675123,
-};
-
-static u32b u32b_rotl(const u32b x, int k) { return (x << k) | (x >> (32 - k)); }
-
-/*
- * Initialize RNG state
- */
-static void Rand_seed(u32b seed, u32b *state)
-{
-    int i;
-
-    for (i = 1; i <= 4; ++i) {
-        seed = 1812433253UL * (seed ^ (seed >> 30)) + i;
-        state[i - 1] = seed;
-    }
-}
-
-/*
- * Xoshiro128** Algorithm
- */
-static u32b Rand_Xoshiro128starstar(u32b *state)
-{
-    const u32b result = u32b_rotl(state[1] * 5, 7) * 9;
-
-    const u32b t = state[1] << 9;
-
-    state[2] ^= state[0];
-    state[3] ^= state[1];
-    state[1] ^= state[2];
-    state[0] ^= state[3];
-
-    state[2] ^= t;
-
-    state[3] = u32b_rotl(state[3], 11);
-
-    return result;
-}
-
-static const u32b Rand_Xorshift_max = 0xFFFFFFFF;
-
-/*
- * Initialize the RNG using a new seed
- */
-void Rand_state_set(u32b seed) { Rand_seed(seed, Rand_state); }
-
 void Rand_state_init(void)
 {
-#ifdef RNG_DEVICE
-
-    FILE *fp = fopen(RNG_DEVICE, "r");
-    int n;
+    using element_type = Xoshiro128StarStar::state_type::value_type;
+    constexpr auto a = std::numeric_limits<element_type>::min();
+    constexpr auto b = std::numeric_limits<element_type>::max();
 
-    do {
-        n = fread(Rand_state, sizeof(Rand_state[0]), 4, fp);
-    } while (n != 4 || (Rand_state[0] | Rand_state[1] | Rand_state[2] | Rand_state[3]) == 0);
-
-    fclose(fp);
-
-#elif defined(WINDOWS)
-
-    HCRYPTPROV hProvider;
-
-    CryptAcquireContext(&hProvider, NULL, NULL, PROV_RSA_FULL, 0);
+    std::random_device rd;
+    std::uniform_int_distribution<element_type> dist(a, b);
 
+    Xoshiro128StarStar::state_type Rand_state{};
     do {
-        CryptGenRandom(hProvider, sizeof(Rand_state[0]) * 4, (BYTE *)Rand_state);
-    } while ((Rand_state[0] | Rand_state[1] | Rand_state[2] | Rand_state[3]) == 0);
-
-    CryptReleaseContext(hProvider, 0);
+        std::generate(Rand_state.begin(), Rand_state.end(), [&dist, &rd] { return dist(rd); });
+    } while (std::all_of(Rand_state.begin(), Rand_state.end(), [](auto s) { return s == 0; }));
 
-#else
-
-    /* Basic seed */
-    u32b seed = (time(NULL));
-#ifdef SET_UID
-    /* Mutate the seed on Unix machines */
-    seed = ((seed >> 3) * (getpid() << 1));
-#endif
-    /* Seed the RNG */
-    Rand_state_set(seed);
-
-#endif
-}
-
-/*
- * Backup the RNG state
- */
-void Rand_state_backup(u32b *backup_state)
-{
-    int i;
-
-    for (i = 0; i < 4; ++i) {
-        backup_state[i] = Rand_state[i];
-    }
+    w_ptr->rng.set_state(Rand_state);
 }
 
-/*
- * Restore the RNG state
- */
-void Rand_state_restore(u32b *backup_state)
+int rand_range(int a, int b)
 {
-    int i;
-
-    for (i = 0; i < 4; ++i) {
-        Rand_state[i] = backup_state[i];
+    if (a > b) {
+        return a;
     }
+    std::uniform_int_distribution<> d(a, b);
+    return d(w_ptr->rng);
 }
 
 /*
- * Extract a "random" number from 0 to m-1, via "ENERGY_DIVISION"
- */
-static s32b Rand_div_impl(s32b m, u32b *state)
-{
-    u32b scaling;
-    u32b past;
-    u32b ret;
-
-    /* Hack -- simple case */
-    if (m <= 1)
-        return 0;
-
-    scaling = Rand_Xorshift_max / m;
-    past = scaling * m;
-
-    do {
-        ret = Rand_Xoshiro128starstar(state);
-    } while (ret >= past);
-
-    return ret / scaling;
-}
-
-s32b Rand_div(s32b m) { return Rand_div_impl(m, Rand_state); }
-
-/*
- * The number of entries in the "randnor_table"
- */
-#define RANDNOR_NUM 256
-
-/*
- * The standard deviation of the "randnor_table"
- */
-#define RANDNOR_STD 64
-
-/*
- * The normal distribution table for the "randnor()" function (below)
- */
-static s16b randnor_table[RANDNOR_NUM] =
-{
-       206,     613,    1022,    1430,         1838,    2245,    2652,    3058,
-       3463,    3867,    4271,    4673,        5075,    5475,    5874,    6271,
-       6667,    7061,    7454,    7845,        8234,    8621,    9006,    9389,
-       9770,   10148,   10524,   10898,   11269,       11638,   12004,   12367,
-       12727,   13085,   13440,   13792,   14140,      14486,   14828,   15168,
-       15504,   15836,   16166,   16492,   16814,      17133,   17449,   17761,
-       18069,   18374,   18675,   18972,   19266,      19556,   19842,   20124,
-       20403,   20678,   20949,   21216,   21479,      21738,   21994,   22245,
-
-       22493,   22737,   22977,   23213,   23446,      23674,   23899,   24120,
-       24336,   24550,   24759,   24965,   25166,      25365,   25559,   25750,
-       25937,   26120,   26300,   26476,   26649,      26818,   26983,   27146,
-       27304,   27460,   27612,   27760,   27906,      28048,   28187,   28323,
-       28455,   28585,   28711,   28835,   28955,      29073,   29188,   29299,
-       29409,   29515,   29619,   29720,   29818,      29914,   30007,   30098,
-       30186,   30272,   30356,   30437,   30516,      30593,   30668,   30740,
-       30810,   30879,   30945,   31010,   31072,      31133,   31192,   31249,
-
-       31304,   31358,   31410,   31460,   31509,      31556,   31601,   31646,
-       31688,   31730,   31770,   31808,   31846,      31882,   31917,   31950,
-       31983,   32014,   32044,   32074,   32102,      32129,   32155,   32180,
-       32205,   32228,   32251,   32273,   32294,      32314,   32333,   32352,
-       32370,   32387,   32404,   32420,   32435,      32450,   32464,   32477,
-       32490,   32503,   32515,   32526,   32537,      32548,   32558,   32568,
-       32577,   32586,   32595,   32603,   32611,      32618,   32625,   32632,
-       32639,   32645,   32651,   32657,   32662,      32667,   32672,   32677,
-
-       32682,   32686,   32690,   32694,   32698,      32702,   32705,   32708,
-       32711,   32714,   32717,   32720,   32722,      32725,   32727,   32729,
-       32731,   32733,   32735,   32737,   32739,      32740,   32742,   32743,
-       32745,   32746,   32747,   32748,   32749,      32750,   32751,   32752,
-       32753,   32754,   32755,   32756,   32757,      32757,   32758,   32758,
-       32759,   32760,   32760,   32761,   32761,      32761,   32762,   32762,
-       32763,   32763,   32763,   32764,   32764,      32764,   32764,   32765,
-       32765,   32765,   32765,   32766,   32766,      32766,   32766,   32767,
-};
-
-/*
  * Generate a random integer number of NORMAL distribution
- *
- * The table above is used to generate a pseudo-normal distribution,
- * in a manner which is much faster than calling a transcendental
- * function to calculate a true normal distribution.
- *
- * Basically, entry 64*N in the table above represents the number of
- * times out of 32767 that a random variable with normal distribution
- * will fall within N standard deviations of the mean.  That is, about
- * 68 percent of the time for N=1 and 95 percent of the time for N=2.
- *
- * The table above contains a "faked" final entry which allows us to
- * pretend that all values in a normal distribution are strictly less
- * than four standard deviations away from the mean.  This results in
- * "conservative" distribution of approximately 1/32768 values.
- *
- * Note that the binary search takes up to 16 quick iterations.
  */
-s16b randnor(int mean, int stand)
+int16_t randnor(int mean, int stand)
 {
-    s16b tmp;
-    s16b offset;
-
-    s16b low = 0;
-    s16b high = RANDNOR_NUM;
-    if (stand < 1)
-        return (s16b)(mean);
-
-    /* Roll for probability */
-    tmp = (s16b)randint0(32768);
-
-    /* Binary Search */
-    while (low < high) {
-        int mid = (low + high) >> 1;
-
-        /* Move right if forced */
-        if (randnor_table[mid] < tmp) {
-            low = mid + 1;
-        }
-
-        /* Move left otherwise */
-        else {
-            high = (s16b)mid;
-        }
+    if (stand <= 0) {
+        return static_cast<int16_t>(mean);
     }
-
-    /* Convert the index into an offset */
-    offset = (long)stand * (long)low / RANDNOR_STD;
-
-    /* One half should be negative */
-    if (randint0(100) < 50)
-        return (mean - offset);
-
-    /* One half should be positive */
-    return (mean + offset);
+    std::normal_distribution<> d(mean, stand);
+    auto result = std::round(d(w_ptr->rng));
+    return static_cast<int16_t>(result);
 }
 
 /*
  * Generates damage for "2d6" style dice rolls
  */
-s16b damroll(DICE_NUMBER num, DICE_SID sides)
+int16_t damroll(DICE_NUMBER num, DICE_SID sides)
 {
     int i, sum = 0;
-    for (i = 0; i < num; i++)
+    for (i = 0; i < num; i++) {
         sum += randint1(sides);
-    return (s16b)(sum);
+    }
+    return (int16_t)(sum);
 }
 
 /*
  * Same as above, but always maximal
  */
-s16b maxroll(DICE_NUMBER num, DICE_SID sides) { return (num * sides); }
+int16_t maxroll(DICE_NUMBER num, DICE_SID sides)
+{
+    return num * sides;
+}
 
 /*
  * Given a numerator and a denominator, supply a properly rounded result,
  * using the RNG to smooth out remainders.  -LM-
  */
-s32b div_round(s32b n, s32b d)
+int32_t div_round(int32_t n, int32_t d)
 {
-    s32b tmp;
+    int32_t tmp;
 
     /* Refuse to divide by zero */
-    if (!d)
-        return (n);
+    if (!d) {
+        return n;
+    }
 
     /* Division */
     tmp = n / d;
 
     /* Rounding */
-    if ((ABS(n) % ABS(d)) > randint0(ABS(d))) {
+    if ((std::abs(n) % std::abs(d)) > randint0(std::abs(d))) {
         /* Increase the absolute value */
-        if (n * d > 0L)
+        if (n * d > 0L) {
             tmp += 1L;
-        else
+        } else {
             tmp -= 1L;
+        }
     }
 
     /* Return */
-    return (tmp);
+    return tmp;
 }
 
 /*
@@ -358,19 +150,20 @@ s32b div_round(s32b n, s32b d)
  *
  * Could also use rand() from <stdlib.h> directly.
  */
-s32b Rand_external(s32b m)
+int32_t Rand_external(int32_t m)
 {
-    static bool initialized = FALSE;
-    static u32b Rand_state_external[4];
+    if (m <= 0) {
+        return 0;
+    }
+
+    static std::optional<Xoshiro128StarStar> urbg_external;
 
-    if (!initialized) {
+    if (!urbg_external) {
         /* Initialize with new seed */
-        u32b seed = (u32b)time(NULL);
-        Rand_seed(seed, Rand_state_external);
-        initialized = TRUE;
+        auto seed = static_cast<uint32_t>(time(nullptr));
+        urbg_external = Xoshiro128StarStar(seed);
     }
 
-    return Rand_div_impl(m, Rand_state_external);
+    std::uniform_int_distribution<> d(0, m - 1);
+    return d(urbg_external.value());
 }
-
-bool next_bool() { return randint0(2) == 0; }