1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-08-16 18:01:40 +00:00

Add API for restoring PseudoRandom and PcgRandom state (#14123)

This commit is contained in:
sfence 2024-01-16 23:20:52 +01:00 committed by GitHub
parent 8093044f07
commit ceaa7e2fb0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 155 additions and 29 deletions

View file

@ -152,6 +152,18 @@ s32 PcgRandom::randNormalDist(s32 min, s32 max, int num_trials)
return myround((float)accum / num_trials);
}
void PcgRandom::getState(u64 state[2]) const
{
state[0] = m_state;
state[1] = m_inc;
}
void PcgRandom::setState(const u64 state[2])
{
m_state = state[0];
m_inc = state[1];
}
///////////////////////////////////////////////////////////////////////////////
float noise2d(int x, int y, s32 seed)

View file

@ -76,6 +76,11 @@ public:
return (next() % (max - min + 1)) + min;
}
// Allow save and restore of state
inline s32 getState() const
{
return m_next;
}
private:
s32 m_next;
};
@ -94,6 +99,9 @@ public:
void bytes(void *out, size_t len);
s32 randNormalDist(s32 min, s32 max, int num_trials=6);
// Allow save and restore of state
void getState(u64 state[2]) const;
void setState(const u64 state[2]);
private:
u64 m_state;
u64 m_inc;

View file

@ -425,6 +425,17 @@ int LuaPseudoRandom::l_next(lua_State *L)
return 1;
}
int LuaPseudoRandom::l_get_state(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
LuaPseudoRandom *o = checkObject<LuaPseudoRandom>(L, 1);
PseudoRandom &pseudo = o->m_pseudo;
int val = pseudo.getState();
lua_pushinteger(L, val);
return 1;
}
int LuaPseudoRandom::create_object(lua_State *L)
{
@ -462,6 +473,7 @@ void LuaPseudoRandom::Register(lua_State *L)
const char LuaPseudoRandom::className[] = "PseudoRandom";
const luaL_Reg LuaPseudoRandom::methods[] = {
luamethod(LuaPseudoRandom, next),
luamethod(LuaPseudoRandom, get_state),
{0,0}
};
@ -496,6 +508,45 @@ int LuaPcgRandom::l_rand_normal_dist(lua_State *L)
return 1;
}
int LuaPcgRandom::l_get_state(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
LuaPcgRandom *o = checkObject<LuaPcgRandom>(L, 1);
u64 state[2];
o->m_rnd.getState(state);
std::ostringstream oss;
oss << std::hex << std::setw(16) << std::setfill('0')
<< state[0] << state[1];
lua_pushstring(L, oss.str().c_str());
return 1;
}
int LuaPcgRandom::l_set_state(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
LuaPcgRandom *o = checkObject<LuaPcgRandom>(L, 1);
std::string l_string = readParam<std::string>(L, 2);
if (l_string.size() != 32) {
throw LuaError("PcgRandom:set_state: Expected hex string of 32 characters");
}
std::istringstream s_state_0(l_string.substr(0, 16));
std::istringstream s_state_1(l_string.substr(16, 16));
u64 state[2];
s_state_0 >> std::hex >> state[0];
s_state_1 >> std::hex >> state[1];
o->m_rnd.setState(state);
return 0;
}
int LuaPcgRandom::create_object(lua_State *L)
{
@ -536,6 +587,8 @@ const char LuaPcgRandom::className[] = "PcgRandom";
const luaL_Reg LuaPcgRandom::methods[] = {
luamethod(LuaPcgRandom, next),
luamethod(LuaPcgRandom, rand_normal_dist),
luamethod(LuaPcgRandom, get_state),
luamethod(LuaPcgRandom, set_state),
{0,0}
};

View file

@ -116,6 +116,8 @@ private:
// next(self, min=0, max=32767) -> get next value
static int l_next(lua_State *L);
// save state
static int l_get_state(lua_State *L);
public:
LuaPseudoRandom(s32 seed) : m_pseudo(seed) {}
@ -150,6 +152,9 @@ private:
// get next normally distributed random value
static int l_rand_normal_dist(lua_State *L);
// save and restore state
static int l_get_state(lua_State *L);
static int l_set_state(lua_State *L);
public:
LuaPcgRandom(u64 seed) : m_rnd(seed) {}
LuaPcgRandom(u64 seed, u64 seq) : m_rnd(seed, seq) {}

View file

@ -65,32 +65,39 @@ void TestRandom::testPseudoRandom()
for (u32 i = 0; i != 256; i++)
UASSERTEQ(s32, pr.next(), expected_pseudorandom_results[i]);
PseudoRandom pr2(0);
UASSERTEQ(int, pr2.next(), 0);
UASSERTEQ(int, pr2.next(), 21469);
UASSERTEQ(int, pr2.next(), 9989);
s32 state = pr.getState();
PseudoRandom pr2(state);
PseudoRandom pr3(-101);
UASSERTEQ(int, pr3.next(), 3267);
UASSERTEQ(int, pr3.next(), 2485);
UASSERTEQ(int, pr3.next(), 30057);
for (u32 i = 0; i != 256; i++) {
UASSERTEQ(s32, pr.next(), pr2.next());
}
PseudoRandom pr3(0);
UASSERTEQ(s32, pr3.next(), 0);
UASSERTEQ(s32, pr3.next(), 21469);
UASSERTEQ(s32, pr3.next(), 9989);
PseudoRandom pr4(-101);
UASSERTEQ(s32, pr4.next(), 3267);
UASSERTEQ(s32, pr4.next(), 2485);
UASSERTEQ(s32, pr4.next(), 30057);
}
void TestRandom::testPseudoRandomRange()
{
PseudoRandom pr((int)time(NULL));
PseudoRandom pr((s32)time(NULL));
EXCEPTION_CHECK(PrngException, pr.range(2000, 8600));
EXCEPTION_CHECK(PrngException, pr.range(5, 1));
for (u32 i = 0; i != 32768; i++) {
int min = (pr.next() % 3000) - 500;
int max = (pr.next() % 3000) - 500;
s32 min = (pr.next() % 3000) - 500;
s32 max = (pr.next() % 3000) - 500;
if (min > max)
SWAP(int, min, max);
SWAP(s32, min, max);
int randval = pr.range(min, max);
s32 randval = pr.range(min, max);
UASSERT(randval >= min);
UASSERT(randval <= max);
}
@ -103,12 +110,21 @@ void TestRandom::testPcgRandom()
for (u32 i = 0; i != 256; i++)
UASSERTEQ(u32, pr.next(), expected_pcgrandom_results[i]);
PcgRandom pr2(0, 0);
u64 state[2];
pr.getState(state);
pr2.setState(state);
for (u32 i = 0; i != 256; i++) {
UASSERTEQ(u32, pr.next(), pr2.next());
}
}
void TestRandom::testPcgRandomRange()
{
PcgRandom pr((int)time(NULL));
PcgRandom pr((u64)time(NULL));
EXCEPTION_CHECK(PrngException, pr.range(5, 1));
@ -116,12 +132,12 @@ void TestRandom::testPcgRandomRange()
pr.range(pr.RANDOM_MIN, pr.RANDOM_MAX);
for (u32 i = 0; i != 32768; i++) {
int min = (pr.next() % 3000) - 500;
int max = (pr.next() % 3000) - 500;
s32 min = (pr.next() % 3000) - 500;
s32 max = (pr.next() % 3000) - 500;
if (min > max)
SWAP(int, min, max);
SWAP(s32, min, max);
int randval = pr.range(min, max);
s32 randval = pr.range(min, max);
UASSERT(randval >= min);
UASSERT(randval <= max);
}
@ -147,8 +163,8 @@ void TestRandom::testPcgRandomBytes()
void TestRandom::testPcgRandomNormalDist()
{
static const int max = 120;
static const int min = -120;
static const s32 max = 120;
static const s32 min = -120;
static const int num_trials = 20;
static const u32 num_samples = 61000;
s32 bins[max - min + 1];