• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

C++ Game.randNumber(num1, num2) TFS 1.3

Itutorial

Excellent OT User
Joined
Dec 23, 2014
Messages
2,307
Solutions
68
Reaction score
982
I am not sure if this is better than the lua random but I used the c++ random for this.

Maybe someone can tell me a better way to do this.

luascript.h
find
Lua:
static int luaGameLoadMap(lua_State* L);

add
Lua:
static int luaGameRandNumbers(lua_State* L);

luascript.cpp
find
Lua:
registerMethod("Game", "loadMap", LuaScriptInterface::luaGameLoadMap);

add
Lua:
registerMethod("Game", "randNumbers", LuaScriptInterface::luaGameRandNumbers);

find
Lua:
int LuaScriptInterface::luaGameLoadMap(lua_State* L)

Under all that code add
Lua:
int LuaScriptInterface::luaGameRandNumbers(lua_State* L)
{
    uint64_t num1 = getNumber<uint64_t>(L, 1);
    uint64_t num2 = getNumber<uint64_t>(L, 2);
    uint64_t rand;

    if (!num2) {
        rand = uniform_random(
            static_cast<int64_t>(1),
            static_cast<int64_t>(num1)
        );
    } else {
        rand = uniform_random(
            static_cast<int64_t>(num1),
            static_cast<int64_t>(num2)
        );
    }

    if (!rand) {

        lua_pushnil(L);

    }

    lua_pushnumber(L, rand);

    return 1;
}

Then you can use
Game.randNumbers(num1, num2)
Game.randNumbers(num) -> Will rand 1-num
 
Last edited:
It's working like math.random(A,B) or it's super-duper tricky and amazing thing? 🤔
🤔
 
Last edited:
It's working like math.random(A,B) or it's super tricky and funky thing? 🤔
🤔
math.random is faster but because of how it works, it's very easy to get repeated results without new seed for each random call, e.g. in loops.
Better performance = math.random
Easier usage for better results = normal_random

From sources, behind that function, there is same thing with "seeding" so it's not returning repeated results.
C++:
int32_t normal_random(int32_t minNumber, int32_t maxNumber)
{
    static std::normal_distribution<float> normalRand(0.5f, 0.25f);
    if (minNumber == maxNumber) {
        return minNumber;
    } else if (minNumber > maxNumber) {
        std::swap(minNumber, maxNumber);
    }

    int32_t increment;
    const int32_t diff = maxNumber - minNumber;
    const float v = normalRand(getRandomGenerator());
    if (v < 0.0) {
        increment = diff / 2;
    } else if (v > 1.0) {
        increment = (diff + 1) / 2;
    } else {
        increment = round(v * diff);
    }
    return minNumber + increment;
}
 
math.random is faster but because of how it works, it's very easy to get repeated results without new seed for each random call, e.g. in loops.

That's simply not true. You have no idea how PRNG works.

You cannot seed the PRNG each time it is called to generate a number. That way you do in fact collapse the uniform distribution and in general that PRNG becomes useless as its generated number will heavily depend on the provided seed.

math.random in Lua is more than adequate to generate uniformly distributed numbers. If you don't believe that then run the following simple Lua code to see it for yourself:

Lua:
math.randomseed(os.time())

local results = {}

for i = 1, 100000 do
    local v = math.random(1, 10)
    results[v] = (results[v] or 0) + 1
end

for k,v in pairs(results) do
    print('Number ' .. k .. ' rolled ' .. v .. ' times.')
end


Now move the first line of math.randomseed(os.time()) to inside the for. You will see what will happen.

Also, it's worth to notice that uniform and normal distributions are not the same. They are used for different things (e.g. uniform distribution is mostly used for loot generation while normal distribution can be used for attack damage).
 
Last edited:
Now move the first line of math.randomseed(os.time()) to inside the for. You will see what will happen.
Where did I mention to run randomseed inside loops? I have mentioned using math.random inside loops.
 
Better performance = math.random
Easier usage for better results = normal_random

They don't even do the same, math.random is supposed to be uniform (evenly distributed density), whilst normal_random is, well, normal.
And Iryont is right, you should never seed each time before calling random. You only seed once.
 
That's simply not true. You have no idea how PRNG works.

Multiple invocations Lua running a Lua script from a shell for-loop tell me Lua's random number generation still sucks royal ass, and I know from problems I had when I ran Frozen-Hell ten years ago it has always sucked ass.

In fact, here. This is from Frozen-Hell's global lua, untouched for 8 years

Lua:
function random_bmt(min, max, variance, strict_min, strict_max) -- Credit: AssassinaMutante --
    --[[  uses the polar form of the Box-Muller transformation to return one   ]]--
    --[[  (or two) number with normal distribution (average = 0 and variance = 1)  ]]--
    local function internal_rand_normal()
        local x1, x2, w, y1, y2 ; repeat x1 = (2 * math.random() - 1) ; x2 = (2 * math.random() - 1) ; 
            w = (x1 * x1 + x2 * x2) ; until (w < 1) ; 
        w = math.sqrt((-2 * math.log(w)) / w) ; y1 = (x1 * w) ; y2 = (x2 * w) ; return y1, y2 ; 
    end ; 
    -- The default of 2.4 is used here because it means that 98, 36% from all values will be between min and max.
    local average = ((min + max) / 2) ; if variance == nil then variance = 2.4 end ; 
    local escala = ((max - average) / variance) ; local x = (escala * internal_rand_normal() + average) ; 
    if strict_min ~= nil then x = math.max(x, strict_min) ; end ; 
    if strict_max ~= nil then x = math.min(x, strict_max) ; end ; return(x) ; 
end ;

Why on earth would someone need a Box Muller transform reimplemented in Lua? 🧐 I'll leave that for the reader to speculate.
 
Perhaps because Box Muller is a transformation from uniform distribution to normal distribution.

The point is it doesn't suck, in fact math.random is working perfectly fine for uniformly distributed numbers. You just don't know the difference between different random distributions and how it all works, so that is the only issue.

Lua cannot generate normally distributed numbers on its own, but this is exactly what transformations are for and that is to transform from one distribution to another.
 
You don't seem to understand, I was using the BMT to emulate a uniform distribution because Lua sucked at that so hard, by expanding the range and truncating it. Yes, that actually gave better results.

If I had been any more fed up I'd have just coded a Mersenne Twister binding in the source instead of grabbing a premade function from the forum. I dunno where Lua got it's entropy back then, but it sure wasn't the kernel.

Edit: Not that the kernel is without potential caveats. Also, who can forget this fun little moment.

And for the edification for any coming along later, here is a visual graph to immediately explain normal versus uniform, and the only other distribution you're likely to see outside esoteric contexts, exponential:
1585727610499.png
source
 
Last edited:
Extensions (https://luajit.org/extensions.html) Search for "Enhanced PRNG for math.random()". It seens like standard lua implementation math.random sucks because it uses rand. Are you guys using standard lua implementation or luajit?

@ltutorial
You should use uniform_random instead of normal_random.
 
If you mean me, I'm talking about events long ago now. At the time I had just started making LuaJIT linked binaries and they'd crash in short order and I had just begun investigating the cause when in-real-life factors* took over and I departed the OT community by force of misfortune. 😔 It was like one week after I was given support team status too, which was a brand new thing back then.

But it's kind surprising to see someone suggesting LuaJIT now, given it's state of maintenance-only mode. I sure hope that OpenResty's fork, MoonJit fork, RaptorJit fork, LuaVela fork, and the Ravi spiritual successor aren't some kind of secret.


*: [1][2][3][4][5][6]
 
That just mean we should use one random implementation both for lua and C++. About luajit state of maintenance-only mode, it has been so stable for me that i kinda ignores that and i hope one day those forks be as good as luajit is.
 
Back
Top