Unity random.range value not same as last value

Quick one,

Currently using Unity Random.Range to set a var with the value of an enum state.

State has 4 possible values, up, down, left,right. I call it like :

currentState = (StateType)Random.Range(0, 3);


This gets set at certain conditions.

My issue is though I don't want the new setting to be the same as the current one.

I have taken a look at the random.range on the API but haven't found anything useful.

Is there an easy way to basically say "randomize but not the same as the current state"

EDIT:

Currently im using a while loop.

while (currentState == LastState)
{
currentState = (StateType)Random.Range(0, 3);
}


Is there anything i can do to remove the while loop?

• I think it's fine. What's wrong with "while"? Jul 7, 2016 at 10:32
• although in probable, the fact that I'm asking to randomize again seems silly to me, as in it "could" randomize to one state multiple times in a row. So i was wondering is there a way to rather omit from the range rather than request to randomize all over again. Jul 7, 2016 at 10:36
• By the way, can you edit the title so it better matches what are you asking for? For future reference. Jul 7, 2016 at 11:01

Yes, choose from range 1 unit smaller and if the result is greater or equal to current, add 1 to it.

var newState = Random.Range(0, (3 - 1)); //choose from range 1 smaller
currentState = (StateType)(newState >= (int)currentState ? newState + 1 : newState);


Edit: if you like really fancy syntax, you can also make it generic extension to enums:

public static void Randomized<T>(this T except) where T : struct, IConvertible
{
if (!typeof(T).IsEnum) throw new ArgumentException("T must be an Enum type");

var values = Enum.GetValues(typeof(T));
int @new = Random.Range(0, values.Length - 1);

return (T)values.GetValue(@new >= ((IList)values).IndexOf(except) ? @new + 1 : @new);
}


from now on you can call Randomized() on any enum type variable:

//declared somewhere in your class
private StateType stype = StateType.Anarchy;
// ...
//when you want to randomize it just do:
stype = stype.Randomized();

• Oh that's clever... Nice solution! :-) Jul 7, 2016 at 10:46
• what happens if new state is 2 and current is 2? +1 makes 3 which is invalid in the range right? Jul 7, 2016 at 10:46
• Not looking good at all. Biggest value will (almost) never be returned and last+1 have double chance. Jul 7, 2016 at 10:49
• @Nikaas You are right, it is supposed to be GEQ , the point is - get a value from smaller range and "stretch" it over the current value. Jul 7, 2016 at 10:53
• I dont see how this fixs it? if the new and current are both 2, then it will still do 2+1 for the value of 3 which in your range doesn't exist Jul 7, 2016 at 10:56

Why not just get a random state from the enum and place in the variable. Use something like this.

private static System.Random _Random = new System.Random(Environment.TickCount);

public static T RandomEnumOf<T>(int exclusion)
{
if (!typeof(T).IsEnum)
throw new InvalidOperationException("Must use Enum type");
Array enumValues = Enum.GetValues(typeof(T));
return (T)enumValues.GetValue(_Random.Next(enumValues.Length - exclusion));
}


Usage : EnumType enum = RandomEnumOf<EnumType>(0); You can modify the exclusion param to fit your criteria.

• nice answer i like it Jul 7, 2016 at 11:42
• If your exclsuion is 3, won't this always return 0? Likewise, if my exclusion is 1, then _Random.Next may still return 1, because it will return a value less than 3 (Length - 1) Jul 7, 2016 at 12:16
• I did say he needs to modify the exclusion param to something else. I just pasted my own code that works for my case. Jul 7, 2016 at 14:56

In this case, I would just keep a list of random values to pick from.

Have some sort of index to use:

 int[] Range = new int[Max-1];


Then have a method to update this index when required:

int idx = 0;
for (int i = 0; i < Max; i++)
{
if (i == currentValue) continue;

Range[idx] = i;
idx++;
}


Then use this for your random:

int value = Range[Random.Range(1, Max-1)];