- Home /
How to generate a random number which is different from the last
As the title suggests, what I want is, how to generate a random number which is not equal to the previously generated number. For example, if Unity generates a number say 5, then the next number shouldn't be 5 but something else say 6 but the number after 6 can be 5 so I didn't use Lists. Is there an efficient method to do this? I know there are some resources on the Internet but they didn't give proper answers.
Thank you and any help will be appreciated.
Answer by Namey5 · Sep 23, 2016 at 11:59 AM
private int lastNumber;
int GetRandom (int min, int max)
{
int rand = Random.Range (min, max);
while (rand == lastNumber)
rand = Random.Range (min, max);
lastNumber = rand;
return rand;
}
Something like that should do it, just call this function where you would normally call Random.Range.
This would work perfectly. You just need to make sure that lastNumber has a value to start with. I would recommend giving it a value that is outside of the range of random numbers to choose from. So if $$anonymous$$ = 0 and max = 10. Initialise lastNumber to -1 then this will work every time.
Thank you very much, it worked perfectly and it cut down a lot of lines of code of $$anonymous$$e.
@$$anonymous$$rBrits sir, I didn't make any changes to my lastNumber variable. It is just outside the range. But what happens if my lastNumber is within the range?
Pretty much means that the GetRandom function might need to make multiple Random.Range numbers because the lastNumber was equal to the number that Random.Range made. This is just for efficiency.
If lastNumber is initialised to a number within the range, it would have a small effect on your distribution (the first random number picked can't ever be that particular number) and a tiny effect on your speed (that first number might take a tiny amount more time to get picked).
i'd suggest checking that max > $$anonymous$$ + 1. Random.Range(A, B) will return at most B -1, so if B == A or B == A + 1, this will be an infinite loop.
Fair point. If max == $$anonymous$$+1
it should either a) return $$anonymous$$
because that's the only possible value (Namey5's function assumes that the OP wants an exclusive max value) OR b) throw an exception (because it's not possible to return a random number different to the last one, so the function's implicit contract is not met).
But if you're needing to check for this then you maybe you shouldn't be calling it in the first place. If I thought there was a chance this might be called with inappropriate values then I would also check for max <= $$anonymous$$
and throw an exception then too.
Indeed. How I personally would do it is just inverse the variables, i.e.
private int lastNumber;
int GetRandom (int $$anonymous$$, int max)
{
int l = $$anonymous$$;
int g = max;
if ($$anonymous$$ > max || max < $$anonymous$$)
{
l = max;
g = $$anonymous$$;
}
if (lastNumber == null)
lastNumber = l - 1;
int rand = Random.Range (l, g);
while (rand == lastNumber)
rand = Random.Range (l, g);
lastNumber = rand;
return rand;
}
hm. a couple things -
there's no need to check that $$anonymous$$ < max. that's already a constraint imposed by Random.Range().
if you insist on checking that $$anonymous$$ < max, fwiw, "$$anonymous$$ > max" is equivalent to "max < $$anonymous$$".
re "lastNumber == null", int's cannot be null.
you want to move "lastNumber = rand" inside the while() loop.
here's what i'd suggest:
static int GetRandom(int $$anonymous$$, int max, int butNotThis) {
int maxIters = 20;
for (int n = 0; n < maxIters; ++n) {
int val = Random.Range($$anonymous$$, max);
if (val != butNotThis) {
return val;
}
}
return butNotThis;
}
if this is going to be called frequently and performance is an issue, it would probably make sense to pre-generate a list of all the possible return values, and when getRand() is called choose a random entry between index 1 (not 0) and the end, and then swap that entry with index 0. that would be a big-O of O(1). hm, i'm not sure what the big-O of the unbounded while() approaches would be. i think they might be O(infinity). like it's O(1) + O(1/n) + O(1/n) + .... forever.
No witty comment here, just that this is amazing. Something I can't seem to wrap my head around for the life of me
Answer by amiel_ace · Sep 23, 2016 at 12:12 PM
prevNum = newNum;
newNum = Random.value * range;
if (newNum == prevNum)
newNum = Random.value * range;
//use newNum here
Thank you very much for taking your time to answer my question.
This is wrong. It doesn't work because the new value of newNum could also be equal to prevNum. Namey5 is correct to use while
ins$$anonymous$$d of if
.
Answer by ayhaab-pasha · Oct 24, 2018 at 07:19 AM
Maybe this would be helpful for someone. I was trying to spawn enemy planes in Augmented Reality. I wanted them to be randomly spawned but at a distance. For example, if one plane is spawned at 0,0,0. I wanted the next plane to be spawned at 0+20 or 0-20 on the X-Axis. Like, the new plane should spawn at 20 or more points from the present spawned point in positive and negative direction. Using @Namey5 solution, i came to this:
void RandonDistanceAxis()
{
distanceX = Random.Range (-70, 70);
while (distanceX <= tempx + 20 && distanceX >= tempx - 20 )
{
distanceX = Random.Range (-70, 70);
}
tempx = distanceX;
distanceY = Random.Range (-10,10);
distanceZ = Random.Range (60,90);
}
While declaring the tempx variable, give it a value of something out of the Range. I used 71. And it worked perfectly fine.