The Battle for Wesnoth  1.17.17+dev
random.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2023
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #pragma once
17 
18 #include <cstdlib> //needed for RAND_MAX
19 #include <cstdint>
20 #include <iterator> //needed for std::distance
21 #include <limits>
22 
23 namespace randomness
24 {
25  /**
26  this class does not give synced random results derived classes might do.
27  */
28  class rng : private std::numeric_limits<uint32_t>
29  {
30  using base = std::numeric_limits<uint32_t>;
31  public:
32  rng();
33  /**
34  * Provides the next random draw. This is raw PRG output.
35  */
36  uint32_t next_random();
37  virtual ~rng();
38  /**
39  * Provides the number of random calls to the rng in this context.
40  * Note that this may be different from the number of random calls to
41  * the underlying rng, and to the random_calls number in save files!
42  */
43  unsigned int get_random_calls() const;
44 
45  /**
46  * This helper method provides a random int from the underlying generator,
47  * using results of next_random in a manner guaranteed to be cross platform.
48  * The result will be random in range [min,max] inclusive.
49  * @param min The minimum value produced.
50  * @param max The maximum value produced.
51  */
52  int get_random_int(int min, int max)
53  { return min + get_random_int_in_range_zero_to(max - min); }
54 
55  /**
56  * This helper method returns true with the probability supplied as a parameter.
57  * @param probability The probability of returning true, from 0 to 1.
58  */
59  bool get_random_bool(double probability);
60 
61  /**
62  * This helper method returns a floating-point number in the range [0,1[.
63  */
64  double get_random_double();
65 
66  /**
67  * This helper method selects a random element from a container of floating-point numbers.
68  * Every number has a probability to be selected equal to the number itself
69  * (e.g. a number of 0.1 is selected with a probability of 0.1). The sum of numbers
70  * should be one.
71  * @param first Iterator to the beginning of the container
72  * @param last Iterator to the end of the container
73  * @return The index of the selected number
74  */
75  template <typename T>
76  typename T::difference_type get_random_element(T first, T last);
77 
78  // For compatibility with the C++ UniformRandomBitGenerator concept
79  using result_type = uint32_t;
80  using base::min;
81  using base::max;
82  uint32_t operator()() { return next_random(); }
83 
84  static rng& default_instance();
85 
86  /**
87  * Is this random source networked? If it is it's very important we do actually use
88  * this random source to stay in-sync.
89  */
90  virtual bool is_networked() const { return false; }
91 
92  protected:
93  virtual uint32_t next_random_impl() = 0;
94  unsigned int random_calls_;
95 
96  private:
97  /** Does the hard work of get_random_int.
98  * The result will be random in range [0,max] inclusive.
99  * @param max The maximum value produced.
100  */
101  int get_random_int_in_range_zero_to(int max);
102  };
103 
104  /**
105  This generator is automatically synced during synced context.
106  Calling this rng during a synced context automatically makes undoing impossible.
107  Outside a synced context this has the same effect as rand()
108  */
109  extern rng* generator;
110 
111  template <typename T>
112  typename T::difference_type rng::get_random_element(T first, T last)
113  {
114  double target = get_random_double();
115  double sum = 0.0;
116  T it = first;
117  sum += *it;
118  while (sum <= target)
119  {
120  ++it;
121  if (it != last)
122  {
123  sum += *it;
124  }
125  else
126  {
127  break;
128  }
129  }
130  return std::distance(first, it);
131  }
132 }
this class does not give synced random results derived classes might do.
Definition: random.hpp:29
virtual ~rng()
Definition: random.cpp:69
unsigned int get_random_calls() const
Provides the number of random calls to the rng in this context.
Definition: random.cpp:80
uint32_t next_random()
Provides the next random draw.
Definition: random.cpp:85
static rng & default_instance()
Definition: random.cpp:74
std::numeric_limits< uint32_t > base
Definition: random.hpp:30
T::difference_type get_random_element(T first, T last)
This helper method selects a random element from a container of floating-point numbers.
Definition: random.hpp:112
uint32_t result_type
Definition: random.hpp:79
virtual uint32_t next_random_impl()=0
unsigned int random_calls_
Definition: random.hpp:94
virtual bool is_networked() const
Is this random source networked? If it is it's very important we do actually use this random source t...
Definition: random.hpp:90
int get_random_int(int min, int max)
Definition: random.hpp:52
bool get_random_bool(double probability)
This helper method returns true with the probability supplied as a parameter.
Definition: random.cpp:137
double get_random_double()
This helper method returns a floating-point number in the range [0,1[.
Definition: random.cpp:112
int get_random_int_in_range_zero_to(int max)
Does the hard work of get_random_int.
Definition: random.cpp:106
uint32_t operator()()
Definition: random.hpp:82
rng * generator
This generator is automatically synced during synced context.
Definition: random.cpp:61