Randomness

mtrain

New member
Just a thoughts about this. A long time ago i have notice that random values getting by rand()% is not really random. For example enemies remaps chosen "randomly", but every time i restart a game, in every level, all enemies (in 80%) have the same remaps, and they drop same items (that also chosen "randomly"). Anyone noticed that too?
 
yes we did noticed that and there was supposed to be some new random but its still not coded in.
I think these problems could solve utunnels but hes not around here lately
 
mtrain said:
Just a thoughts about this. A long time ago i have notice that random values getting by rand()% is not really random. For example enemies remaps chosen "randomly", but every time i restart a game, in every level, all enemies (in 80%) have the same remaps, and they drop same items (that also chosen "randomly"). Anyone noticed that too?

This is not a bug in OpenBOR per se, its the nature of Random - rand() - in C language. Rand() have a internal memory which stores a number, lets say "r", made by the past execution of the function. For each new execution, the rand() function uses "r" to calculate a new "random" number. The calculated number becomes the new value of r.

Where did it all begin? The number r corresponding to the first invocation rand is known as "seed". Given the seed, the sequence of numbers produced by rand is completely determined. IOW is NOT that random.

The rand() function returns a pseudo-random integer between 0 and RAND_MAX. In C, you can use "srand(unsigned int seed)" to set a seed. It's common practice to use the % in conjunction with rand() to get a different range (though bear in mind that this throws off the uniformity somewhat). But I don't know if OpenBOR accepts "srand":

Code:
#include <time.h>

//The Randomize function initializes the random number 
//generator so that the results of invocations 
//of RandomInteger is unpredictable. 

void Randomize( void)
{
    srand( time( NULL));
}

Take a look: http://stackoverflow.com/questions/2999075/generate-a-random-number-within-range/2999130#2999130

"Attempts that just use % (or, equivalently, /) to get the numbers in a range almost inevitably introduce skew (i.e., some numbers will be generated more often than others).

Edit: as to why using % produces skewed results: unless the range you want is a divisor of RAND_MAX, skew is inevitable. If you start with small numbers, it's pretty easy to see why. Consider taking 10 pieces of candy and trying to divide it evenly between three children. Clearly it can't be done -- if you hand out all the candy, the closest you can get is for two kids to get three pieces of candy, and one of them getting four."
 
+1. By their nature, computers simply cannot produce truly random values of any sort on their own.

Without some outside random input to work with the best you can do is combine a mathematical formula with some constantly moving seed value (system clock is the typical choice) to simulate randomness in a given range.

This might help a bit.

OpenBOR cannot access the system clock because there may not BE a clock on some platforms, so it uses time elapsed instead. That's why if you test the same thing over and over it might not appear all that random. In most real world conditions though it works fairly well.

DC

 
Well i disagree, computers can emulate randomness easily by linking number with passing time and time is always changing , then you can take it from there to generate random number based on current time and its digits chop them up however you want to generate "Random" value with written formulas, just convert it to acceptable outcome in current situation, time is also emulated in computers , well i do think that randomness its just a word, you can absolutely emulate that with computer.We need controlled randomness not just whatever outcome real life brings.Well thats kinda what you wrote. ???
in 70's and 80's when computers had analog parts then random values could be obtained, just checking voltage flow , electricity is very random and ius changing all the time.
Problem is that openbor randomnes is really really bad, even if you run engine again  and again it will produce exactly the same results with remaps for example, given 10 remaps it will always use 1 2 5 6 and ignore all other ones, every damn time.
Would be great to find solution for that, maybe write workaround or randomness simulator/emulation, also lowering priority of recently selected random values would be nice so it wont repeat itself and skip already used value.
So, currently the only person who can introduce anhother one or improve current random system is utunnels , right ? He can also fix problem with using frame == 0 which very often doesnt work.
 
Yeah, you pretty much said what I did, lol. Analog computers are a different ball game, and they have their own set of problems that go way beyond randomness. There's a reason ENIAC was built back in the 40's.

When ultimate randomness is needed, we DO use analog seeds, usually a discharging capacitor or when it REALLY matters measuring radioactive decay. That's what I meant by outside random input.

I digress though. Back to OpenBOR, as I said above, we use time elapsed time for the seed because that's the only thing we can be sure is available. It's not great but certainly better than nothing.

Per your suggestion it might be possible to record a value already picked and not allow it until X time as passed, and I can try some experiments to see what we get. Seems a bit nitpicky though.

First, the same random system has around since since the original BOR to give the AI its randomness and no one had any complaints. Script didn't change a thing - it simply gave you direct access.

Second, what stops you from just doing that in the script yourself?

DC

 
IF engine is using elapsed time , well its time in miliseconds? id say its randomness of time in 10 second invervals  ;D
I dare anyone  playing game twice to select character, walk 10 steps and punch someone with the same time in miliseconds accuracty and comparing results, you simply cant do that and outcome on timer will be different in both cases so if rand in openbor is using elapsed time or any time at all to generate randomness then its simply broken and maybe could be fixed by adding another time counter to it to change the random value again properly.

Per your suggestion it might be possible to record a value already picked and not allow it until X time as passed, and I can try some experiments to see what we get. Seems a bit nitpicky though.
That could bring some fake randomness to the table, if already used random values would be ignored and unused ones would be selected.
ITs hackaround but it is actually what people want in most cases when using random, avoid selecting the same random value again is also important.Kinda like shuffle when you listen to the music so it wont play the same track which was given very low priority after it was playedback.
 
Hey guys, I have to eat some crow here. Turns out the engine uses its own custom rand function combining bit shifts with a an incrementing seed that that starts as... get this: 1234567890.

Provision was given to modify the seed using a function called srand(int), but at no point is it ever called. Instead the seed is incremented on each call of rand(), producing numbers that are random enough for AI use, but easily detectable as a pattern when viewed directly. See for yourself:

Code:
/*
 * OpenBOR - http://www.chronocrash.com
 * -----------------------------------------------------------------------
 * All rights reserved, see LICENSE in OpenBOR root for details.
 *
 * Copyright (c) 2004 - 2014 OpenBOR Team
 */

#include "rand32.h"
#include "types.h"

unsigned long seed = 1234567890;

unsigned int rand32(void)
{
    u64 t = seed;
    t *= 1103515245ull;
    t += 12345ull;
    seed = t;
    return (t >> 16) & 0xFFFFFFFF;
}

void srand32(int n)
{
    seed = n;
}

To fix this without changing default behavior I added a script function that lets you set the random seed yourself. Presumably you'd want to seed with elapsed time immediately before each rand() call.

The only catch is the seed is global, so it will affect everything that depends on the current generator. I'd like to think more randomness is a good thing - but I also know Roel was a brilliant coder and had to have a reason for what he did, so you never know.

Anyway, here's the devpost. Give it a try and let me know what happens.
 
Thank you, guys for supporting and investigating this question :)

Thank you, DC, for the great addition. I have try a 4079 version, and it is work really good, i mean from the very beginning i have restart level about 10 times, and in each case stuff was truly random.

But i have a question: if a script have several rand()%, do i need to set srand before each of them or the first one will be enough?

...
int time = openborvariant("elapsed_time");

srand(time);
int  Rn1 = rand()%5 + 5;

srand(time);
int  Rn2 = rand()%5 + 5;

srand(time);
int  Rn3 = rand()%5 + 5;
...

or just

...
int time = openborvariant("elapsed_time");

srand(time);
int  Rn1 = rand()%5 + 5;
int  Rn2 = rand()%5 + 5;
int  Rn3 = rand()%5 + 5;
...
 
Once a seed is established, OpenBOR increments it each and every time rand() is called - not just by you, but by the AI - and that could be dozens of calls per second, so once will probably be enough.

That said, to get 100% assurance, I'd reseed with Elapsed Time on each use. Also note in the latest version srand() returns a random number just like rand() does, so you can cut down on calls:

Code:
int rand = srand({seed})

DC
 
Back
Top Bottom