RNG Issue (Full Version)

All Forums >> [New Releases from Matrix Games] >> Command: Modern Operations series >> Mods and Scenarios >> Lua Legion


vettim89 -> RNG Issue (6/20/2021 9:12:09 PM)

I have this function to randomly assign three Cuban Submarines to a random mission

function CubanSubs(side, unit)
local assign=math.random(1,9)
if assign==1 then
ScenEdit_AssignUnitToMission(unit.name, 'Gulf 1')
elseif assign == 2 then
ScenEdit_AssignUnitToMission(unit.name, 'Gulf 2')
elseif assign ==3 then
ScenEdit_AssignUnitToMission(unit.name, 'Gulf 3')
elseif assign == 4 then
ScenEdit_AssignUnitToMission(unit.name, 'Gulf 4')
elseif assign == 5 then
ScenEdit_AssignUnitToMission(unit.name, 'Gulf 5')
elseif assign ==6 then
ScenEdit_AssignUnitToMission(unit.name, 'Gulf 6')
elseif assign == 7 then
ScenEdit_AssignUnitToMission(unit.name, 'Gulf 7')
elseif assign == 8 then
ScenEdit_AssignUnitToMission(unit.name, 'Gulf 8')
ScenEdit_AssignUnitToMission(unit.name, 'Gulf 9')

The function runs correct but all three subs are assigned to the same mission. I suspect the RNG is not resetting between calls. I know there are issues with the math.random function. Is there a way to reset it between calls? Here is what I am getting:


wirthlin -> RE: RNG Issue (6/20/2021 10:13:16 PM)

The problem is with seeding the RNG within the function call. os.time() which is your seed returns the current time in seconds. The code is probably looping through the three subs in less than a second, seeding the RNG to the same value, and therefore all your subs are getting assigned to the same mission. Below is a copy of the code demonstrating the solution.

function CubanSubs()
local assign=math.random(1,9)
if assign==1 then
print('Gulf 1')
elseif assign == 2 then
print('Gulf 2')
elseif assign ==3 then
print('Gulf 3')
elseif assign == 4 then
print('Gulf 4')
elseif assign == 5 then
print('Gulf 5')
elseif assign ==6 then
print('Gulf 6')
elseif assign == 7 then
print('Gulf 7')
elseif assign == 8 then
print('Gulf 8')
print('Gulf 9')

for i=1,9 do

vettim89 -> RE: RNG Issue (6/22/2021 2:18:14 AM)

I actually found this little tidbit on a lua forum (not a CMO lua forum)

function sleep(n) -- seconds
local clock = os.clock
local t0 = clock()
while clock() - t0 <= n do

So when I set the above function but include the line after loading the above function


I get three different missions for my subs. Yes, it causes a three second delay but this is a one time function at the beginning of the scenario and I suspect most players won't even notice it

KnightHawk75 -> RE: RNG Issue (6/22/2021 3:55:30 AM)

Really should avoid racing the cpu to "sleep" like that when it's not even necessary.
wirthlin provided the right answer, which is move the seeding outside the for, as there should be no need to re-seed it on each call.

This (below) what I use to init seeds, _IF_ it must be set\reset at all in loops (which is rarely needed as already pointed out, and can be counter productive in some cases). Also keep in mind the randomizer is pre-seeded automatically in the Lua Editor environment initialization, only time it technically needs to be init'd is for things running in the Event context (or if you're purposely doing it for a specific reason), there is a thread with some detail on that from the past that is still true today. http://www.matrixgames.com/forums/fb.asp?m=4583853

--snagged long time ago from https://github.com/rjstone/cmano-lua-helpers/blob/master/cmano_helpers.lua
--it doesn't help all that much but it's marginally better than just os.time in tight loops.
function  gKH:improvedRandomseed(quality)
    if quality == nil then quality=10 end
    -- os.time() removes dependency on how long the software has been running currently
    -- os.clock() provides miliseconds, unlike os.time()
    -- we "chain" this with previous math.random() output to retain any accumulated entropy
    -- and "stir" a little by repeating more than once, though not much because the execution time
    -- probably doesn't vary much between calls and spending too much time will be a waste unless we want
    -- to spend several seconds doing this.
    math.randomseed(os.time() + math.random(90071992547)) -- preserve some previous entropy if there was any
    for i = 1, quality do
        -- Retain some previous PRNG state while adding a little jitter entropy, but not much.
        -- Jitter entropy comes from thread preemption, interrupt handing, and stuff like that in the OS that is
        -- somewhat random. This means you might not get much if any on a powerful and calm system.
        -- If we had a higher precision clock with ns instead of just ms then that would be more helpful.
        math.randomseed(((os.clock() * 1000) % 1000) + math.random(900719925470000))

^ Has never given me issues when used appropriately (including in the rare cases where it needs to happen in tight loops).

jkgarner -> RE: RNG Issue (7/1/2021 11:30:55 AM)

Hear! Hear!

It is not necessary to seed the random number generator EVERY time you call a random number.
Generally it is sufficient to seed it a single time a the beginning of a run (or scenario)

Most random number generators are sufficiently random for game purposes to provide an even distribution of numbers between 0 and 1, unless you are dealing with security issues (think finances) in which case you want one that is certified. But even these function the same way. You seed once, and then call repeatedly as needed.

For simulations purposes, there is over seeding the generator. This results in compete loss on control of the randomness and a lack of repeatability.

Repeatability? (You ask) Why do I want that?

OK, for a pleasure game, it is not critical. But for a simulation, repeatability can bes very handy as a validation tool and as a debugging tool. If in my run of the simulation, I encounter an error (or what I believe to be an error halfway through the run. As a simulation developer, I must be able to recreate that series of events and instrument the run to see what happened to correct it.

Debugging becomes much easier if I could simply feed it the same inputs and run, knowing that the error WILL occur. If the ONLY time the random number generator is seeded is the very beginning of the run, and that seed value is saved, then when I run it again, I could give it the same seed and get the same results. As a debugger, then all I need to do is instrument the appropriate code (assuming the instrumenation code it does not call random) and then examine the output after the run. I could stop it seconds before the error occurs to examine the state of the system to gain further insight. This most often leads to the discovery that where the error appears or is reported was the result of something else that was not correct, and may have been incorrect for some time), so I then run again, stopping earlier, working backwards looking for root causes, until I find the true error, and a way to fix it. This is ONLY possible with repeatability. As a simulation grows in complexity, this type of behavior becomes more necessary.

My reccomendation is for the scenario developers to seed the random number generator ONLY at the very beginning of the scenario, when first loaded and store the value of the seed into the Key Values Store (using ScenEdit_SetKeyValue)

That is my two cents worth.

Page: [1]

Valid CSS!

Forum Software © ASPPlayground.NET Advanced Edition 2.4.5 ANSI