summaryrefslogtreecommitdiff
path: root/src/generic/random.hpp
blob: 5d7a7af6ced25de833ff5f780562806f8d75ba8c (plain) (blame)
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
#ifndef TMWA_GENERIC_RANDOM_HPP
#define TMWA_GENERIC_RANDOM_HPP

# include "random.t.hpp"

# include "../sanity.hpp"

# include <random>

// This is not namespace random since that collides with a C function,
// but this can be revisited when everything goes into namespace tmwa.
namespace random_
{
    /// Get a random number from 0 .. 2**32 - 1
    extern std::mt19937 generate;

    /// Get a random number from 0 .. bound - 1
    inline
    int to(int bound)
    {
        std::uniform_int_distribution<int> dist(0, bound - 1);
        return dist(generate);
    }

    /// Get a random number from low .. high (inclusive!)
    inline
    int in(int low, int high)
    {
        std::uniform_int_distribution<int> dist(low, high);
        return dist(generate);
    }

    inline
    bool coin()
    {
        // sigh, can't specify <bool> directly ...
        std::uniform_int_distribution<int> dist(false, true);
        return dist(generate);
    }

    inline
    bool chance(Fraction f)
    {
        if (f.num <= 0)
            return false;
        if (f.num >= f.den)
            return true;
        return random_::to(f.den) < f.num;
    }

    // C is usually one of:
    //  std::vector<T>
    //  std::initializer_list<T>
    //  std::array<T, n>
    template<class C>
    auto choice(C&& c) -> decltype(*c.begin())
    {
        return *(c.begin() + random_::to(c.size()));
    }

    // allow bare braces
    template<class T>
    T choice(std::initializer_list<T>&& il)
    {
        return random_::choice(il);
    }
} // namespace random_

#endif // TMWA_GENERIC_RANDOM_HPP