1 /++
2 Random number generation utils
3 +/
4 module sily.random;
5 
6 import std.math;
7 import std.random;
8 import std.algorithm.comparison;
9 import std.conv: to;
10 import std.datetime: Clock;
11 import std.traits: isFloatingPoint;
12 
13 
14 /++
15 Random number generator
16 Example:
17 ---
18 // Creates rng with default seed
19 RNG rng = RNG();
20 // Creates rng with custom seed
21 rng = RNG(2511244);
22 // Assigns random seed to seed
23 rng.randomize();
24 // Returns random uint
25 rnd.random();
26 // Returns random float in range of 0..float.max
27 randf();
28 // Returns random float in rangle of 4..20
29 randf(4, 20);
30 // Returns random ulong in range of 0..ulong.max
31 rand!ulong();
32 ---
33 +/
34 struct RNG {
35     private uint _seed = defaultSeed;
36     private Random _rnd;
37     private ulong _calls;
38 
39     /// Creates RNG with set seed
40     this(uint p_seed) {
41         _seed = p_seed;
42         _rnd = Random(_seed);
43     }
44 
45     /// Randomizes seed
46     public void randomize() {
47         seed = randomSeed;
48     }
49     /// Ditto
50     alias randomise = randomize;
51 
52     /// Sets custom seed `p_seed`
53     @property public void seed(uint p_seed) {
54         _seed = p_seed;
55         _rnd.seed(_seed);
56     }
57 
58     /// Returns current seed
59     @property public uint seed() { return _seed; }
60 
61     /// Alias to std.random default seed
62     public static alias defaultSeed = Random.defaultSeed;
63     /// Alias to std.random unpredictable seed
64     public static alias randomSeed = unpredictableSeed;
65 
66     /// Typed alias to get random value between 0 and T.max or custom min and max
67     alias randf = rand!float;
68     /// Ditto
69     alias randr = rand!real;
70     /// Ditto
71     alias randd = rand!double;
72     /// Ditto
73     alias randi = rand!int;
74     /// Ditto
75     alias randl = rand!long;
76     
77     template rand(T) {
78         static if(isFloatingPoint!T) {
79             /// Returns random value between 0 and T.max or custom min and max
80             T rand() {
81                 return random / _rnd.max.to!T;
82             }
83 
84             /// Ditto
85             T rand(T min, T max) {
86                 return min + (rand!T * (max - min));
87             }
88         } else {
89             /// Ditto
90             T rand() {
91                 return (randr * T.max).to!T;
92             }
93 
94             /// Ditto
95             T rand(T min, T max) {
96                 return round(min + (randr * (max - min))).to!T;
97             }
98         }
99     }
100 
101     /// Returns random uint
102     public uint random() {
103         uint r = _rnd.front;
104         skip();
105         return r;
106     }
107 
108     /// Skips current random value
109     public void skip() {
110         _rnd.popFront();
111         _calls ++;
112     }
113 
114     /// Skips N amount of random values
115     public void skipTo(size_t numCalls) {
116         while(_calls < numCalls) {
117             skip();
118         }
119     }
120 }
121