1
\$\begingroup\$

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?

\$\endgroup\$
3
  • 1
    \$\begingroup\$ I think it's fine. What's wrong with "while"? \$\endgroup\$
    – Nikaas
    Jul 7, 2016 at 10:32
  • \$\begingroup\$ 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. \$\endgroup\$
    – lemunk
    Jul 7, 2016 at 10:36
  • \$\begingroup\$ By the way, can you edit the title so it better matches what are you asking for? For future reference. \$\endgroup\$
    – wondra
    Jul 7, 2016 at 11:01

3 Answers 3

4
\$\begingroup\$

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();
\$\endgroup\$
8
  • \$\begingroup\$ Oh that's clever... Nice solution! :-) \$\endgroup\$
    – hobnob
    Jul 7, 2016 at 10:46
  • \$\begingroup\$ what happens if new state is 2 and current is 2? +1 makes 3 which is invalid in the range right? \$\endgroup\$
    – lemunk
    Jul 7, 2016 at 10:46
  • \$\begingroup\$ Not looking good at all. Biggest value will (almost) never be returned and last+1 have double chance. \$\endgroup\$
    – Nikaas
    Jul 7, 2016 at 10:49
  • \$\begingroup\$ @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. \$\endgroup\$
    – wondra
    Jul 7, 2016 at 10:53
  • \$\begingroup\$ 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 \$\endgroup\$
    – lemunk
    Jul 7, 2016 at 10:56
1
\$\begingroup\$

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.

\$\endgroup\$
3
  • \$\begingroup\$ nice answer i like it \$\endgroup\$
    – lemunk
    Jul 7, 2016 at 11:42
  • 1
    \$\begingroup\$ 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) \$\endgroup\$
    – hobnob
    Jul 7, 2016 at 12:16
  • \$\begingroup\$ I did say he needs to modify the exclusion param to something else. I just pasted my own code that works for my case. \$\endgroup\$
    – Uri Popov
    Jul 7, 2016 at 14:56
0
\$\begingroup\$

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)];
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .