scummvm/common/random.h
TehGelly 0992fa9c3b
COMMON: Change PRNG Function to Xorshift* (#3341)
The old RNG method had non-standard periods, ranging from some seeds looping on themselves (seed = 1184201285) to some seeds having periods as low as 11 or 48, as listed in https://github.com/scummvm/scummvm/pull/3340. This is a problem even for games that run the RNG once a frame, as the possibilities for random events is greatly reduced should the initial seed be in one of these sets of small periods.

Xorshift* is a standard, fast, non-cryptographic PRNG with academic backing that has period 2^32-1 (all seeds lead to another seed except 0, which is excluded from the initial seeds).  Many different flavors are possible, as listed in the paper, but the choice implemented in this pull request uses only a single 32-bit integer as a state, like the old PRNG.

Co-authored-by: Thierry Crozat <criezy@scummvm.org>
Co-authored-by: Filippos Karapetis <bluegr@gmail.com>
2021-09-09 21:46:08 +03:00

108 lines
2.9 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef COMMON_RANDOM_H
#define COMMON_RANDOM_H
#include "common/scummsys.h"
namespace Common {
/**
* @defgroup common_rng RNG
* @ingroup common
*
* @brief Random number generator (RNG) implementation.
*
* @{
*/
class String;
/**
* Xorshift* random number generator. Although it is definitely not suitable for
* cryptographic purposes, it serves our purposes just fine.
*/
class RandomSource {
private:
uint32 _randSeed;
public:
/**
* Construct a new randomness source with the specific @p name.
* The name used must be globally unique, and is used to
* register the randomness source with the active event recorder,
* if any.
*/
RandomSource(const String &name);
void setSeed(uint32 seed); /*!< Set the seed used to initialize the RNG. */
uint32 getSeed() const { /*!< Get a random seed that can be used to initialize the RNG. */
return _randSeed;
}
/**
* Generate a random unsigned integer in the interval [0, max].
* @param max The upper bound
* @return A random number in the interval [0, max].
*/
uint getRandomNumber(uint max);
/**
* Generate a random bit, i.e. either 0 or 1.
* Identical to @c getRandomNumber(1), but potentially faster.
* @return A random bit, either 0 or 1.
*/
uint getRandomBit();
/**
* Generate a random unsigned integer in the interval [min, max].
* @param min The lower bound.
* @param max The upper bound.
* @return A random number in the interval [min, max].
*/
uint getRandomNumberRng(uint min, uint max);
/**
* Generates a random signed integer in the interval [min, max].
* @param min the lower bound
* @param max the upper bound
* @return a random number in the interval [min, max]
*/
int getRandomNumberRngSigned(int min, int max);
/**
* Scrambles the seed in order to get a new result.
* Code is shared between getRandomNumber and getRandomBit,
* so it is split off for clarity.
*/
private:
inline void scrambleSeed();
};
/** @} */
} // End of namespace Common
#endif