File: random.h

package info (click to toggle)
crawl 2%3A0.34.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 100,188 kB
  • sloc: cpp: 363,709; ansic: 27,765; javascript: 9,516; python: 8,463; perl: 3,293; java: 3,132; xml: 2,380; makefile: 1,835; sh: 611; objc: 250; cs: 15; sed: 9; lisp: 3
file content (352 lines) | stat: -rw-r--r-- 9,704 bytes parent folder | download | duplicates (2)
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
#pragma once

#include <algorithm>  // iter_swap
#include <iterator>   // advance
#include <map>
#include <vector>

#include "debug.h"
#include "fixedvector.h"
#include "hash.h"
#include "rng-type.h"
#include "pcg.h"

class CrawlVector;

namespace rng
{
    class generator
    {
    public:
        generator(rng_type g);
        generator(branch_type b);
        ~generator();
    private:
        rng_type previous;
    };

    class subgenerator
    {
    public:
        subgenerator();
        subgenerator(uint64_t seed);
        subgenerator(uint64_t seed, uint64_t sequence);
        ~subgenerator();
    private:
        PcgRNG current;
        PcgRNG *previous;
        rng_type previous_main;
    };

    rng_type get_branch_generator(const branch_type b);
    CrawlVector generators_to_vector();
    void load_generators(const CrawlVector &v);
    vector<uint64_t> get_states();
    PcgRNG *get_generator(rng_type r);
    PcgRNG &current_generator();

    void seed();
    void seed(uint64_t seed);
    void seed(uint64_t[], int);
    void reset();

    uint32_t get_uint32(rng_type generator);
    uint64_t get_uint64(rng_type generator);
    uint32_t get_uint32();
    uint64_t get_uint64();
    uint32_t peek_uint32();
    uint64_t peek_uint64();

    class ASSERT_stable
    {
    public:
        ASSERT_stable() : initial_peek(peek_uint64()) { }
        ~ASSERT_stable()
        {
            ASSERT(peek_uint64() == initial_peek);
        }

    private:
        uint64_t initial_peek;
    };
}

bool coinflip();
int div_rand_round(int num, int den);
int div_round_up(int num, int den);
int div_round_near(int num, int den);
bool one_chance_in(int a_million);
bool x_chance_in_y(int x, int y);
int random2(int max);
int maybe_random2(int x, bool random_factor);
int maybe_random2_div(int nom, int denom, bool random_factor);
int maybe_roll_dice(int num, int size, bool random);
int random_range(int low, int high);
int random_range(int low, int high, int nrolls);
double random_real();

int random2avg(int max, int rolls);
int random2min(int max, int rolls);
int random2max(int ran, int rolls);
int biased_random2(int max, int n);
int binomial(unsigned n_trials, unsigned trial_prob, unsigned scale = 100);
bool bernoulli(double n_trials, double trial_prob);
int fuzz_value(int val, int lowfuzz, int highfuzz, int naverage = 2);
int roll_dice(int num, int size);
bool decimal_chance(double percent);

int ui_random(int max);

/** Chooses one of the objects passed in at random (by value).
 *  @return One of the arguments.
 *
 *  @note All the arguments must be convertible to the type of the first.
 */
template <typename T, typename... Ts>
T random_choose(T first, Ts... rest)
{
    const T elts[] = { first, rest... };
    return elts[random2(1 + sizeof...(rest))];
}

/** Chooses one of the objects passed in at random (by reference).
 *
 * @return A reference to one of the arguments.
 *
 * @note All the arguments must be of a type compatible with the type of the
 *       first. Specifically, it must be possible to implicitly convert a
 *       pointer to each argument into the same type as a pointer to the first
 *       argument. So, for example, if the first argument is non-const, none
 *       of the subsequent subsequent arguments may be const.
 */
template <typename T, typename... Ts>
T& random_choose_ref(T& first, Ts&... rest)
{
    return *random_choose(&first, &rest...);
}

template <typename C>
auto random_iterator(C &container) -> decltype(container.begin())
{
    int pos = random2(container.size());
    auto it = container.begin();
    advance(it, pos);
    return it;
}

/**
 * Get a random weighted choice.
 *
 * Weights are assumed to be non-negative, but are allowed to be zero.
 * @tparam  V  A map, vector of pairs, etc., with the values of the
 *             map or the second elements of the pairs being integer
 *             weights.
 *
 * @param   choices  The collection of choice-weight pairs to choose from.
 *
 * @return  A pointer to the item in the chosen pair, or nullptr if all
 *          weights are zero. The pointer is const only if necessary.
 */
template <typename V>
auto random_choose_weighted(V &choices) -> decltype(&(begin(choices)->first))
{
    int total = 0;
    for (const auto &entry : choices)
        total += entry.second;
    int r = random2(total);
    int sum = 0;
    for (auto &entry : choices)
    {
        sum += entry.second;
        if (sum > r)
            return &entry.first;
    }
    return nullptr;
}

/**
 * Get an index for a random weighted choice using a fixed vector of
 * weights.
 *
 * Entries with a weight <= 0 are skipped.
 * @param choices The fixed vector with weights for each item.
 *
 * @return  A index corresponding to the selected item, or -1 if all
 *          weights were skipped.
 */
template <typename T, int SIZE>
int random_choose_weighted(const FixedVector<T, SIZE>& choices)
{
    int total = 0;
    for (auto weight : choices)
        if (weight > 0)
            total += weight;

    int r = random2(total);
    int sum = 0;
    for (int i = 0; i < SIZE; ++i)
    {
        if (choices[i] <= 0)
            continue;

        sum += choices[i];
        if (sum > r)
            return i;
    }
    return -1;
}

template <typename T>
T random_choose_weighted(int, T curr)
{
    return curr;
}

template <typename T, typename... Args>
T random_choose_weighted(int cweight, T curr, int nweight, T next, Args... args)
{
    return random_choose_weighted<T>(cweight + nweight,
                                     random2(cweight+nweight) < nweight ? next
                                                                        : curr,
                                     args...);
}

struct dice_def
{
    int num;
    int size;

    constexpr dice_def() : num(0), size(0) {}
    constexpr dice_def(int n, int s) : num(n), size(s) {}
    int roll() const;
};

constexpr dice_def CONVENIENT_NONZERO_DAMAGE{42, 1};

dice_def calc_dice(int num_dice, int max_damage, bool random = true);

template<typename T>
class power_deducer
{
public:
    virtual T operator()(int pow, bool random = true) const = 0;
    virtual ~power_deducer() {}
};

typedef power_deducer<int> tohit_deducer;

template<int adder, int mult_num = 0, int mult_denom = 1>
class tohit_calculator : public tohit_deducer
{
public:
    int operator()(int pow, bool /*random*/) const override
    {
        return adder + pow * mult_num / mult_denom;
    }
};

typedef power_deducer<dice_def> dam_deducer;

template<int numdice, int adder, int mult_num, int mult_denom>
class dicedef_calculator : public dam_deducer
{
public:
    dice_def operator()(int pow, bool /*random*/) const override
    {
        return dice_def(numdice, adder + pow * mult_num / mult_denom);
    }
};

template<int numdice, int adder, int mult_num, int mult_denom>
class calcdice_calculator : public dam_deducer
{
public:
    dice_def operator()(int pow, bool random) const override
    {
        return calc_dice(numdice, adder + pow * mult_num / mult_denom, random);
    }
};

// I must be a random-access iterator.
template <typename I>
void shuffle_array(I begin, I end)
{
    size_t n = end - begin;
    while (n > 1)
    {
        const int i = random2(n);
        n--;
        iter_swap(begin + i, begin + n);
    }
}

template <typename T>
void shuffle_array(T &vec)
{
    shuffle_array(begin(vec), end(vec));
}

template <typename T>
void shuffle_array(T *arr, int n)
{
    shuffle_array(arr, arr + n);
}

/**
 * A defer_rand object represents an infinite tree of random values, allowing
 * for a much more functional approach to randomness. defer_rand values which
 * have been used should not be copy-constructed. Querying the same path
 * multiple times will always give the same result.
 *
 * An important property of defer_rand is that, except for rounding,
 * `float(r.random2(X)) / X == float(r.random2(Y)) / Y` for all `X` and `Y`.
 * In other words:
 *
 * - The parameter you use on any given call does not matter.
 * - The object stores the fraction, not a specific integer.
 * - random2() is monotonic in its argument.
 *
 * Rephrased: The first time any node in the tree has a method called on
 * it, a random float between 0 and 1 (the fraction) is generated and stored,
 * and this float is combined with the method's parameters to arrive at
 * the result. Calling the same method on the same node with the same
 * parameters will always give the same result, while different parameters
 * or methods will give different results (though they'll all use the same
 * float which was generated by the first method call). Each node in the
 * tree has it's own float, so the same method+parameters on different
 * nodes will get different results.
 */
class defer_rand
{
    vector<uint32_t> bits;
    map<int, defer_rand> children;

    bool x_chance_in_y_contd(int x, int y, int index);
public:
    // TODO It would probably be a good idea to have some sort of random
    // number generator API, and the ability to pass RNGs into any function
    // that wants them.
    bool x_chance_in_y(int x, int y) { return x_chance_in_y_contd(x,y,0); }
    bool one_chance_in(int a_million) { return x_chance_in_y(1,a_million); }
    int random2(int maxp1);

    int random_range(int low, int high);
    int random2avg(int max, int rolls);

    defer_rand& operator[] (int i);
};

template<typename Iterator>
int choose_random_weighted(Iterator beg, const Iterator end)
{
    int totalweight = 0;
    int result = -1;
    for (int count = 0; beg != end; ++count, ++beg)
    {
        totalweight += *beg;
        if (random2(totalweight) < *beg)
            result = count;
    }
    ASSERT(result >= 0);
    return result;
}