Skip to content

Instantly share code, notes, and snippets.

@nkrapivin
Created October 4, 2022 14:38
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nkrapivin/ea4db4abb8a1994c0c1ba88f54196fa6 to your computer and use it in GitHub Desktop.
Save nkrapivin/ea4db4abb8a1994c0c1ba88f54196fa6 to your computer and use it in GitHub Desktop.
RERand - 100% correct GML runtime RNG implementation.... in pure GML!
function rerand() constructor {
state = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
g_nRandSeed = 0;
g_RndIndex = 0;
s_nRandomPoly = $DA442D24;
RND_MAX = $FFFFFFFF;
s_nStateAndMask = RND_MAX;
InitRandom = function(/*uint*/ _seed) {
var uVar3 = _seed;
g_nRandSeed = _seed;
for (var iVar1 = 0; iVar1 < 16; ++iVar1) {
// legacy GM does 7FFFFFFF for some reason...
uVar3 = ((((((uVar3 * 0x343fd) & RND_MAX) + 0x269ec3 & RND_MAX) >> 0x10) & RND_MAX)) & s_nStateAndMask;
state[@ iVar1] = uVar3;
}
g_RndIndex = 0;
return _seed;
};
YYRandom = function()
{
var uVar1 = ((state[g_RndIndex & RND_MAX] & RND_MAX) ^ (state[((g_RndIndex + 0xd) & RND_MAX) & 0xf] & RND_MAX)) & RND_MAX;
var uVar2 = uVar1 ^ ((state[g_RndIndex & RND_MAX] << 0x10) & RND_MAX) ^ ((state[((g_RndIndex + 0xd) & RND_MAX) & 0xf] << 0xf) & RND_MAX);
var uVar3 = (state[((g_RndIndex + 9) & RND_MAX) & 0xf] & RND_MAX) ^ ((state[((g_RndIndex + 9) & RND_MAX) & 0xf] >> 0xb) & RND_MAX);
var uVar4 = ((uVar2 & RND_MAX) ^ (uVar3 & RND_MAX)) & RND_MAX;
state[g_RndIndex & RND_MAX] = uVar4 & RND_MAX;
g_RndIndex = (((g_RndIndex - 1) & RND_MAX) & 0xf) & RND_MAX;
// don't try to understand lol
state[g_RndIndex] =
(state[g_RndIndex] ^ ((uVar2 ^ ((((uVar4 ^ ((s_nRandomPoly & ((uVar4 << 5) & RND_MAX) & RND_MAX))) & RND_MAX) ^ ((state[g_RndIndex] << 2) & RND_MAX)) & RND_MAX) ^
((uVar1 << 0x12) & RND_MAX) ^ ((uVar3 << 0x1c) & RND_MAX)) & RND_MAX)) & RND_MAX;
return state[g_RndIndex];
};
YYRandomRange = function(_range)
{
var uVar1;
var uVar2;
var uVar3;
_range = floor(_range);
uVar2 = YYRandom();
uVar3 = abs(_range);
uVar1 = 0;
if (uVar3 != 0) {
uVar1 = uVar2 div uVar3;
}
return uVar2 - uVar1 * uVar3;
};
ChangeToOldPoly = function(bUseOldPoly)
{
if (!bUseOldPoly) {
s_nRandomPoly = 0xda442d24;
s_nStateAndMask = RND_MAX;
return;
}
s_nRandomPoly = 0xda442d20;
s_nStateAndMask = $7FFFFFFF;
};
fYYRandom = function(_range)
{
var uVar1;
var local_18;
if (_range == 1.0) {
uVar1 = YYRandom();
local_18 = uVar1 / 4294967296.0;
}
else {
uVar1 = YYRandom();
local_18 = (uVar1 / 4294967296.0) * _range;
}
return local_18;
};
/* Function_Math.cpp:1425
DWARF DIE: 3e7a97 */
F_Random = function(argument0)
{
var dVar1;
var dVar2;
dVar1 = fYYRandom(1.0);
dVar2 = argument0;
return dVar1 * dVar2;
};
/* Function_Math.cpp:1436
DWARF DIE: 3e7b3a */
F_RandomRange = function(argument0, argument1)
{
var dVar1;
var dVar2;
var dVar3;
dVar1 = argument0;
dVar2 = argument1;
/* Begin: inline double YYGML_random_range(double _base, double _end) */
dVar3 = dVar2 - dVar1;
if (dVar2 <= dVar1) {
dVar3 = dVar1 - dVar2;
dVar1 = dVar2;
}
dVar2 = fYYRandom(1.0);
return dVar1 + dVar2 * dVar3;
};
/* Function_Math.cpp:1535
DWARF DIE: 68dad6 */
F_RandomGetSeed = function()
{
return g_nRandSeed;
};
/* Function_Math.cpp:1512
DWARF DIE: 68da1f */
F_RandomSetSeed = function(argument0)
{
var _seed;
_seed = floor(argument0) & RND_MAX;
return InitRandom(_seed);
};
iScript_Random = function(_range)
{
var lVar1;
var lVar2;
var uVar3;
var uVar4;
var lVar5;
_range = int64(_range);
uVar3 = int64(YYRandom());
uVar4 = int64(YYRandom());
uVar3 = int64((uVar3 & 0xffffffff) | ((uVar4 & 0x7fffffff) << 0x20));
lVar1 = int64(-1);
if (int64(-1) < _range) {
lVar1 = int64(1);
}
lVar5 = int64(lVar1 * _range);
lVar2 = int64(0);
if (lVar5 != int64(0)) {
lVar2 = int64(uVar3 / lVar5);
}
return int64(int64(int64(uVar3) - int64(lVar2) * int64(lVar5)) * int64(lVar1));
};
/* Function_Math.cpp:1468
DWARF DIE: 68d764 */
F_IRandom = function(argument0)
{
var iVar6 = int64(floor(argument0));
var lVar2 = int64(-1);
if (int64(-1) < int64(iVar6)) {
lVar2 = int64(1);
}
return real(int64(iScript_Random(int64(int64(lVar2) + int64(iVar6)))));
};
/* Function_Math.cpp:1482
DWARF DIE: 68d8ee */
F_IRandomRange = function(argument0, argument1)
{
var lVar6 = int64(floor(argument0));
var iVar7 = int64(floor(argument1));
var lVar3 = int64(int64(iVar7) - int64(lVar6));
if (iVar7 <= lVar6) {
lVar3 = int64(lVar6 - iVar7);
lVar6 = int64(iVar7);
}
return real(int64(lVar6) + int64(iScript_Random(int64(lVar3 + 1))));
};
/* Function_Math.cpp:2277
DWARF DIE: 3e9a34 */
F_Choose = function()
{
var _argc = argument_count;
if (_argc != 0)
{
return argument[floor(YYRandomRange(_argc))];
}
return 0;
};
F_RandomUseOldVersion = function(doUse)
{
// might not be correct???
ChangeToOldPoly(doUse);
};
g_nRandSeed = InitRandom(0);
}
/* -- TESTCASE BEGIN, CUT THIS OFF IF YOU DON'T NEED IT -- */
var r = new rerand();
var s = 0;
repeat (10000) {
random_set_seed(s);
r.F_RandomSetSeed(s);
repeat (100) {
if (r.F_Random(10) != random(10)) {
throw "random() fail!";
}
if (r.F_RandomRange(10, 100) != random_range(10, 100)) {
throw "random_range() fail!";
}
if (r.F_IRandom(100) != irandom(100)) {
throw "irandom() fail!";
}
if (r.F_IRandomRange(10, 100) != irandom_range(10, 100)) {
throw "irandom_range() fail!";
}
if (r.F_Choose(1, 2, 3) != choose(1, 2, 3)) {
throw "choose() fail!";
}
}
++s;
}
show_message("Testcase PASS!");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment