mirror of
https://github.com/love2d/love.git
synced 2026-08-16 08:11:02 +02:00
Added RandomGenerator:getState and RandomGenerator:setState (resolves issue #831.)
getState returns an implementation-dependent string representing the current state of the RandomGenerator's PRNG. setState sets the PRNG's state to an implementation-dependent string.
This commit is contained in:
@@ -53,26 +53,6 @@ public:
|
||||
virtual ~Math()
|
||||
{}
|
||||
|
||||
inline void setRandomSeed(RandomGenerator::Seed seed)
|
||||
{
|
||||
rng.setSeed(seed);
|
||||
}
|
||||
|
||||
inline void setRandomSeed(uint32 low, uint32 high)
|
||||
{
|
||||
rng.setSeed(low, high);
|
||||
}
|
||||
|
||||
inline RandomGenerator::Seed getRandomSeed() const
|
||||
{
|
||||
return rng.getSeed();
|
||||
}
|
||||
|
||||
inline void getRandomSeed(uint32 &low, uint32 &high) const
|
||||
{
|
||||
rng.getSeed(low, high);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc RandomGenerator::random()
|
||||
**/
|
||||
@@ -105,6 +85,26 @@ public:
|
||||
return rng.randomNormal(stddev);
|
||||
}
|
||||
|
||||
inline void setRandomSeed(RandomGenerator::Seed seed)
|
||||
{
|
||||
rng.setSeed(seed);
|
||||
}
|
||||
|
||||
inline RandomGenerator::Seed getRandomSeed() const
|
||||
{
|
||||
return rng.getSeed();
|
||||
}
|
||||
|
||||
inline void setRandomState(const std::string &statestr)
|
||||
{
|
||||
rng.setState(statestr);
|
||||
}
|
||||
|
||||
inline std::string getRandomState() const
|
||||
{
|
||||
return rng.getState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new random number generator.
|
||||
**/
|
||||
|
||||
@@ -20,8 +20,13 @@
|
||||
|
||||
#include "RandomGenerator.h"
|
||||
|
||||
// STL
|
||||
// C++
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
// C
|
||||
#include <cstdlib>
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -36,25 +41,10 @@ RandomGenerator::RandomGenerator()
|
||||
{
|
||||
// because it is too big for some compilers to handle ... if you know what
|
||||
// i mean
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
seed.b32.a = 0x0139408D;
|
||||
seed.b32.b = 0xCBBF7A44;
|
||||
#else
|
||||
seed.b32.b = 0x0139408D;
|
||||
seed.b32.a = 0xCBBF7A44;
|
||||
#endif
|
||||
|
||||
rng_state = seed;
|
||||
}
|
||||
|
||||
void RandomGenerator::setSeed(RandomGenerator::Seed newseed)
|
||||
{
|
||||
// 0 xor 0 is still 0, so Xorshift can't generate new numbers.
|
||||
if (newseed.b64 == 0)
|
||||
throw love::Exception("Invalid random seed.");
|
||||
|
||||
seed = newseed;
|
||||
rng_state = seed;
|
||||
Seed newseed;
|
||||
newseed.b32.low = 0xCBBF7A44;
|
||||
newseed.b32.high = 0x0139408D;
|
||||
setSeed(newseed);
|
||||
}
|
||||
|
||||
uint64 RandomGenerator::rand()
|
||||
@@ -83,5 +73,71 @@ double RandomGenerator::randomNormal(double stddev)
|
||||
return r * sin(phi) * stddev;
|
||||
}
|
||||
|
||||
void RandomGenerator::setSeed(RandomGenerator::Seed newseed)
|
||||
{
|
||||
// 0 xor 0 is still 0, so Xorshift can't generate new numbers.
|
||||
if (newseed.b64 == 0)
|
||||
throw love::Exception("Invalid random seed.");
|
||||
|
||||
seed = newseed;
|
||||
rng_state = seed;
|
||||
}
|
||||
|
||||
RandomGenerator::Seed RandomGenerator::getSeed() const
|
||||
{
|
||||
return seed;
|
||||
}
|
||||
|
||||
void RandomGenerator::setState(const std::string &statestr)
|
||||
{
|
||||
// For this implementation we'll accept a hex string representing the
|
||||
// 64-bit state integer xorshift uses.
|
||||
|
||||
Seed state = {};
|
||||
|
||||
// Hex string must start with 0x.
|
||||
if (statestr.find("0x") != 0 || statestr.size() < 3)
|
||||
throw love::Exception("Invalid random state.");
|
||||
|
||||
// standardized strtoull (or 64 bit integer support for stringstream)
|
||||
// requires C++11's standard library, which we can't use yet.
|
||||
// I use strtol like this not because it's the best solution, but because
|
||||
// it's "good enough".
|
||||
|
||||
// Convert the hex string to the state integer character-by-character.
|
||||
for (size_t i = 2; i < statestr.size(); i++)
|
||||
{
|
||||
char hex[2] = {statestr[i], 0};
|
||||
char *end = nullptr;
|
||||
|
||||
// Convert the current hex character to a number.
|
||||
int nibble = strtol(hex, &end, 16);
|
||||
|
||||
// Check if strtol failed to convert it.
|
||||
if (end != nullptr && *end != 0)
|
||||
throw love::Exception("Invalid random state.");
|
||||
|
||||
state.b64 = (state.b64 << 4) + nibble;
|
||||
}
|
||||
|
||||
rng_state = state;
|
||||
}
|
||||
|
||||
std::string RandomGenerator::getState() const
|
||||
{
|
||||
// For this implementation we'll return a hex string representing the 64-bit
|
||||
// state integer xorshift uses.
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "0x";
|
||||
|
||||
// Again with the stringstream not dealing with 64 bit integers...
|
||||
ss << std::setfill('0') << std::setw(8) << std::hex << rng_state.b32.high;
|
||||
ss << std::setfill('0') << std::setw(8) << std::hex << rng_state.b32.low;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // math
|
||||
} // love
|
||||
|
||||
@@ -28,8 +28,9 @@
|
||||
#include "common/int.h"
|
||||
#include "common/Object.h"
|
||||
|
||||
// STL
|
||||
// C++
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -45,54 +46,19 @@ public:
|
||||
uint64 b64;
|
||||
struct
|
||||
{
|
||||
uint32 a;
|
||||
uint32 b;
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
uint32 high;
|
||||
uint32 low;
|
||||
#else
|
||||
uint32 low;
|
||||
uint32 high;
|
||||
#endif
|
||||
} b32;
|
||||
};
|
||||
|
||||
RandomGenerator();
|
||||
virtual ~RandomGenerator() {}
|
||||
|
||||
/**
|
||||
* Set pseudo-random seed.
|
||||
* It's up to the implementation how to use this.
|
||||
**/
|
||||
void setSeed(Seed seed);
|
||||
|
||||
/**
|
||||
* Separately set the low and high bits of the pseudo-random seed.
|
||||
**/
|
||||
inline void setSeed(uint32 low, uint32 high)
|
||||
{
|
||||
Seed newseed;
|
||||
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
newseed.b32.a = high;
|
||||
newseed.b32.b = low;
|
||||
#else
|
||||
newseed.b32.b = high;
|
||||
newseed.b32.a = low;
|
||||
#endif
|
||||
|
||||
setSeed(newseed);
|
||||
}
|
||||
|
||||
inline Seed getSeed() const
|
||||
{
|
||||
return seed;
|
||||
}
|
||||
|
||||
inline void getSeed(uint32 &low, uint32 &high) const
|
||||
{
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
high = seed.b32.a;
|
||||
low = seed.b32.b;
|
||||
#else
|
||||
high = seed.b32.b;
|
||||
low = seed.b32.a;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Return uniformly distributed pseudo random integer.
|
||||
*
|
||||
@@ -138,6 +104,28 @@ public:
|
||||
**/
|
||||
double randomNormal(double stddev);
|
||||
|
||||
/**
|
||||
* Set pseudo-random seed.
|
||||
* It's up to the implementation how to use this.
|
||||
**/
|
||||
void setSeed(Seed seed);
|
||||
|
||||
/**
|
||||
* Get the previously set pseudo-random seed.
|
||||
**/
|
||||
Seed getSeed() const;
|
||||
|
||||
/**
|
||||
* Set the internal implementation-dependent state value based on a string.
|
||||
**/
|
||||
void setState(const std::string &statestr);
|
||||
|
||||
/**
|
||||
* Get a string representation of the implementation-dependent internal
|
||||
* state value.
|
||||
**/
|
||||
std::string getState() const;
|
||||
|
||||
private:
|
||||
|
||||
Seed seed;
|
||||
|
||||
@@ -32,21 +32,6 @@ namespace love
|
||||
namespace math
|
||||
{
|
||||
|
||||
int w_setRandomSeed(lua_State *L)
|
||||
{
|
||||
EXCEPT_GUARD(Math::instance.setRandomSeed(luax_checkrandomseed(L, 1));)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_getRandomSeed(lua_State *L)
|
||||
{
|
||||
uint32 low = 0, high = 0;
|
||||
Math::instance.getRandomSeed(low, high);
|
||||
lua_pushnumber(L, (lua_Number) low);
|
||||
lua_pushnumber(L, (lua_Number) high);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_random(lua_State *L)
|
||||
{
|
||||
return luax_getrandom(L, 1, Math::instance.random());
|
||||
@@ -62,6 +47,32 @@ int w_randomNormal(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_setRandomSeed(lua_State *L)
|
||||
{
|
||||
EXCEPT_GUARD(Math::instance.setRandomSeed(luax_checkrandomseed(L, 1));)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_getRandomSeed(lua_State *L)
|
||||
{
|
||||
RandomGenerator::Seed s = Math::instance.getRandomSeed();
|
||||
lua_pushnumber(L, (lua_Number) s.b32.low);
|
||||
lua_pushnumber(L, (lua_Number) s.b32.high);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_setRandomState(lua_State *L)
|
||||
{
|
||||
EXCEPT_GUARD(Math::instance.setRandomState(luax_checkstring(L, 1));)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_getRandomState(lua_State *L)
|
||||
{
|
||||
luax_pushstring(L, Math::instance.getRandomState());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_newRandomGenerator(lua_State *L)
|
||||
{
|
||||
RandomGenerator::Seed s;
|
||||
@@ -341,10 +352,12 @@ int w_noise(lua_State *L)
|
||||
// List of functions to wrap.
|
||||
static const luaL_Reg functions[] =
|
||||
{
|
||||
{ "setRandomSeed", w_setRandomSeed },
|
||||
{ "getRandomSeed", w_getRandomSeed },
|
||||
{ "random", w_random },
|
||||
{ "randomNormal", w_randomNormal },
|
||||
{ "setRandomSeed", w_setRandomSeed },
|
||||
{ "getRandomSeed", w_getRandomSeed },
|
||||
{ "setRandomState", w_setRandomState },
|
||||
{ "getRandomState", w_getRandomState },
|
||||
{ "newRandomGenerator", w_newRandomGenerator },
|
||||
{ "newBezierCurve", w_newBezierCurve },
|
||||
{ "triangulate", w_triangulate },
|
||||
|
||||
@@ -30,10 +30,12 @@ namespace love
|
||||
namespace math
|
||||
{
|
||||
|
||||
int w_setRandomSeed(lua_State *L);
|
||||
int w_getRandomSeed(lua_State *L);
|
||||
int w_random(lua_State *L);
|
||||
int w_randomNormal(lua_State *L);
|
||||
int w_setRandomSeed(lua_State *L);
|
||||
int w_getRandomSeed(lua_State *L);
|
||||
int w_setRandomState(lua_State *L);
|
||||
int w_getRandomState(lua_State *L);
|
||||
int w_newRandomGenerator(lua_State *L);
|
||||
int w_newBezierCurve(lua_State *L);
|
||||
int w_triangulate(lua_State *L);
|
||||
|
||||
@@ -47,16 +47,8 @@ RandomGenerator::Seed luax_checkrandomseed(lua_State *L, int idx)
|
||||
|
||||
if (!lua_isnoneornil(L, idx + 1))
|
||||
{
|
||||
uint32 low = checkrandomseed_part<uint32>(L, idx);
|
||||
uint32 high = checkrandomseed_part<uint32>(L, idx + 1);
|
||||
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
s.b32.a = high;
|
||||
s.b32.b = low;
|
||||
#else
|
||||
s.b32.b = high;
|
||||
s.b32.a = low;
|
||||
#endif
|
||||
s.b32.low = checkrandomseed_part<uint32>(L, idx);
|
||||
s.b32.high = checkrandomseed_part<uint32>(L, idx + 1);
|
||||
}
|
||||
else
|
||||
s.b64 = checkrandomseed_part<uint64>(L, idx);
|
||||
@@ -95,25 +87,6 @@ RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx)
|
||||
return luax_checktype<RandomGenerator>(L, idx, "RandomGenerator", MATH_RANDOM_GENERATOR_T);
|
||||
}
|
||||
|
||||
int w_RandomGenerator_setSeed(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
EXCEPT_GUARD(rng->setSeed(luax_checkrandomseed(L, 2));)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_RandomGenerator_getSeed(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
|
||||
uint32 low = 0, high = 0;
|
||||
rng->getSeed(low, high);
|
||||
|
||||
lua_pushnumber(L, (lua_Number) low);
|
||||
lua_pushnumber(L, (lua_Number) high);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_RandomGenerator_random(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
@@ -132,12 +105,44 @@ int w_RandomGenerator_randomNormal(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_RandomGenerator_setSeed(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
EXCEPT_GUARD(rng->setSeed(luax_checkrandomseed(L, 2));)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_RandomGenerator_getSeed(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
RandomGenerator::Seed s = rng->getSeed();
|
||||
lua_pushnumber(L, (lua_Number) s.b32.low);
|
||||
lua_pushnumber(L, (lua_Number) s.b32.high);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_RandomGenerator_setState(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
EXCEPT_GUARD(rng->setState(luax_checkstring(L, 2));)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_RandomGenerator_getState(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
luax_pushstring(L, rng->getState());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg functions[] =
|
||||
{
|
||||
{ "setSeed", w_RandomGenerator_setSeed },
|
||||
{ "getSeed", w_RandomGenerator_getSeed },
|
||||
{ "random", w_RandomGenerator_random },
|
||||
{ "randomNormal", w_RandomGenerator_randomNormal },
|
||||
{ "setSeed", w_RandomGenerator_setSeed },
|
||||
{ "getSeed", w_RandomGenerator_getSeed },
|
||||
{ "setState", w_RandomGenerator_setState },
|
||||
{ "getState", w_RandomGenerator_getState },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
@@ -36,10 +36,12 @@ RandomGenerator::Seed luax_checkrandomseed(lua_State *L, int idx);
|
||||
int luax_getrandom(lua_State *L, int startidx, double r);
|
||||
|
||||
RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx);
|
||||
int w_RandomGenerator_setSeed(lua_State *L);
|
||||
int w_RandomGenerator_getSeed(lua_State *L);
|
||||
int w_RandomGenerator_random(lua_State *L);
|
||||
int w_RandomGenerator_randomNormal(lua_State *L);
|
||||
int w_RandomGenerator_setSeed(lua_State *L);
|
||||
int w_RandomGenerator_getSeed(lua_State *L);
|
||||
int w_RandomGenerator_setState(lua_State *L);
|
||||
int w_RandomGenerator_getState(lua_State *L);
|
||||
extern "C" int luaopen_randomgenerator(lua_State *L);
|
||||
|
||||
} // math
|
||||
|
||||
Reference in New Issue
Block a user