Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Random number chosen except one

Discussion in 'Scripting' started by herbie, Jun 10, 2012.

Thread Status:
Not open for further replies.
  1. herbie

    herbie

    Joined:
    Feb 11, 2012
    Posts:
    237
    With Random.Range (0,10) a number between 0 and 10 is randomly chosen.
    Now I want to have a random number between 0 and 10 except one specific number, for example 5.
    So only from the numbers 0,1,2,3,4,6,7,8 and 9 one number is randomly chosen.

    Does anybody know how to do that?
     
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Code (csharp):
    1. function RandomRangeExcept (min : int, max : int, except : int) : int {
    2.     do {
    3.         var number = Random.Range (min, max);
    4.     } while (number == except);
    5.     return number;
    6. }
    --Eric
     
    ryanterry likes this.
  3. herbie

    herbie

    Joined:
    Feb 11, 2012
    Posts:
    237
    Ok, thanks for quick reply.
     
  4. every

    every

    Joined:
    Sep 10, 2014
    Posts:
    1
    Can you offer C# code,plz?
     
  5. DarkArts-Studios

    DarkArts-Studios

    Joined:
    May 2, 2013
    Posts:
    389
    I'd like to offer an alternate solution:

    Code (CSharp):
    1. public int randomIntExcept( int min, int max, int except )
    2. {
    3.     int result = Random.Range( min, max-1 );
    4.     if (result >= except) result += 1;
    5.     return result;
    6. }
    Also keep in mind that Random.Range when given int values is max exclusive so Random.Range(0,10) will return a number in the range [0..9].


    [EDIT] Here's a reference to Random.Range which goes into more detail about exclusive max for int and inclusive max for float: http://docs.unity3d.com/ScriptReference/Random.Range.html
     
  6. toreau

    toreau

    Joined:
    Feb 8, 2014
    Posts:
    204
    Code (CSharp):
    1. public int RandomExcept ( int fromNr, int exclusiveToNr, int exceptNr ) {
    2.     int randomNr = exceptNr;
    3.  
    4.     while ( randomNr == exceptNr ) {
    5.         randomNr = Random.Range( fromNr, exclusiveToNr );
    6.     }
    7.  
    8.     return randomNr;
    9. }
     
  7. BmxGrilled

    BmxGrilled

    Joined:
    Jan 27, 2014
    Posts:
    238
    A slight variation to DarkArts Studios solution;

    Code (CSharp):
    1. public int RandomExcept(int min, int max, int except)
    2. {
    3.    int random = Random.Range(min, max);
    4.    if (random >= except) random = (random + 1) % max;
    5.    return random;
    6. }
    7.  
    ~
    Another walk in the park.
     
    AlterMannn, aeffoa, nakrthing and 5 others like this.
  8. GarthSmith

    GarthSmith

    Joined:
    Apr 26, 2012
    Posts:
    1,240
    I suggest avoiding while loops when possible. I'm not saying don't use while, just think before you use them. In two of the code samples above, if you set min == max == except, you will get an infinite loop.

    Of course you can check and validate the input first, but I try to make it a habit to avoid possible infinite loops caused by while.
     
  9. DarkArts-Studios

    DarkArts-Studios

    Joined:
    May 2, 2013
    Posts:
    389
    Agreed 100% with @Garth Smith (which is why I proposed the alternate solution above) - not only is there an infinite loop possibility but also, you have a small chance of a random fetch running for a relatively substantial amount of time especially if your min -> max difference is low.

    And _always_ your time-till-return will be unpredictable. I don't like unpredictable code ;)
     
    GarthSmith likes this.
  10. dazapa2894

    dazapa2894

    Joined:
    May 19, 2016
    Posts:
    2
    I edit the answer of @toreau to make a function in C# where you can pass a List of exceptions.

    Code (CSharp):
    1. private int RandomExceptList(int fromNr, int exclusiveToNr, List<int> exceptNr)
    2.     {
    3.         //asigno el primer numero invalido
    4.         int randomNr = exceptNr[0];
    5.  
    6.         // si el numero es invalido entra el en while
    7.         while (exceptNr.Contains(randomNr))
    8.         {
    9.             randomNr = UnityEngine.Random.Range(fromNr, exclusiveToNr);
    10.         }
    11.  
    12.         // cuando el numero sea valido... sale de la funcion
    13.         return randomNr;
    14.     }
    I use it to fill an array of buttons with the wrong answers, the use my answer var to pick a random button an fill it with the correct answewer, hope it help you

    here my code

    Code (CSharp):
    1. private void Update()
    2.     {
    3.             if (!buttonsSet)
    4.             {
    5.                 buttonsSet = true;
    6.                 buttonsPanel.SetActive(true);
    7.                 nextBtn.SetActive(false);
    8.  
    9.                 setWrongAnswers();
    10.                 setCorrectAnswer();
    11.             }
    12.     }
    13.  
    14.     public void setWrongAnswers()
    15.     {
    16.         List<int> excludedNumbers = new List<int>();
    17.         excludedNumbers.Add(answer);
    18.         foreach (Text btnTxt in buttonsPanel.GetComponentsInChildren<Text>())
    19.         {
    20.             int anctaluNumber = RandomExceptList(0, 11, excludedNumbers);
    21.             excludedNumbers.Add(anctaluNumber);
    22.             btnTxt.text = anctaluNumber.ToString();
    23.         }
    24.     }
    25.  
    26.     public void setCorrectAnswer() {
    27.         int randomBtn = UnityEngine.Random.Range(0, buttonsPanel.GetComponentsInChildren<Text>().Length);
    28.         buttonsPanel.GetComponentsInChildren<Text>()[randomBtn].text = answer.ToString();
    29.  
    30.     }
    31.  
    32.     private int RandomExceptList(int fromNr, int exclusiveToNr, List<int> exceptNr)
    33.     {
    34.         int randomNr = exceptNr[0];
    35.  
    36.         while (exceptNr.Contains(randomNr))
    37.         {
    38.             randomNr = UnityEngine.Random.Range(fromNr, exclusiveToNr);
    39.         }
    40.         return randomNr;
    41.     }
     
    nabeelasad2007 likes this.
  11. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,745
    Here's solution with constant speed.

    Code (CSharp):
    1.  
    2. private int RandomExcept(int min, int max, int except) {
    3.    Debug.Assert(max > except, "max > except");
    4.    Debug.Assert(except > min, "except > min");
    5.    Debug.Assert(max < int.MaxValue, "max < int.MaxValue");
    6.  
    7.    if (Random.Range(0, 1 - float.Epsilon) > (except - min) / (float) (max - min)) {
    8.       return Random.Range(min, except);
    9.    }
    10.  
    11.    return 1 + Random.Range(except, max);
    12. }
    13.  
    And if there are more than one excepts, I would first randomly weightened select interval, then just random number within interval.
     
    Last edited: Aug 14, 2019
  12. Marc_Kletz

    Marc_Kletz

    Joined:
    Apr 28, 2021
    Posts:
    6
    I'm going to do a zombie and revive this thread.
    We do not want a while loop for obvious performance reasons and because it could lead to an infinite loop.

    In my solution, I generate a List that holds all allowed random numbers. Then I choose one of the allowed numbers in the array at random. This has decent performance and no while loop.

    Code (CSharp):
    1.  
    2. public static int RandomRangeExcept(int minInclusive, int maxExclusive, List<int> except = null)
    3.     {
    4.         IEnumerable<int> allowedRandomNumbers = Enumerable.Range(minInclusive, maxExclusive - minInclusive);
    5.         if (except != null)
    6.         {
    7.             allowedRandomNumbers = allowedRandomNumbers.Except(except);
    8.         }
    9.         if (allowedRandomNumbers.Count() == 0)
    10.         {
    11.             Debug.LogError("Allowed numbers array is empty! Returning 0");
    12.             return 0;
    13.         }
    14.         int randomIndex = UnityEngine.Random.Range(0, allowedRandomNumbers.Count());
    15.         return allowedRandomNumbers.ElementAt(randomIndex);
    16.     }
    17.  
     
  13. MaciekOaky

    MaciekOaky

    Joined:
    Nov 10, 2016
    Posts:
    6
    Hey there, it's enough to randomize a number between
    [min, max - 1]
    . If the randomized number equals the exception number, we swap it with the value
    (max - 1)
    .
    I take we want to randomize from
    min (inclusive)
    to
    max (exclusive)
    .

    Code (CSharp):
    1. private int GetRandomExcept(int min, int max, int exceptValue) // min (inclusive), max (exclusive)
    2. {
    3.     var r = Random.Range(min, max - 1);
    4.     return r == exceptValue ? (max - 1) : r;
    5. }
     
Thread Status:
Not open for further replies.