Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

Question Random number with no repetition

Discussion in 'Scripting' started by wechat_og5za0hHUaVztQr2WozuYi-9E7X8, Aug 17, 2020.

  1. wechat_og5za0hHUaVztQr2WozuYi-9E7X8

    wechat_og5za0hHUaVztQr2WozuYi-9E7X8

    Joined:
    Nov 11, 2018
    Posts:
    1
    Hi, I have now made a question answering game, using JSON to connect the questions. Now I need to use button to activate a random number that does not repeat within the range to make the questions appear randomly until all the questions in this question bank have appeared. However, I have encountered some problems, and the random number method I use cannot be completed.
    Code (CSharp):
    1.  public int[] values = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    2.     private int A;
    3.     public void test() {
    4.     int GetRandomIndex(int userindex)
    5.     {
    6.         int modelindex = Random.Range(1, 10);
    7.         if (values[userindex] != modelindex)
    8.         {
    9.             var a = from k in values where k == modelindex select k;
    10.             while (a.ToArray().Length <= 1)
    11.             {
    12.                 return modelindex;
    13.             }
    14.         }
    15.         return GetRandomIndex(userindex);
    16.     }
    17.         A = GetRandomIndex(A);
    18.         Debug.Log(A);
    19.     }
     
  2. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,553
  3. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    692
    I implemented that algorithm and got repeats. Maybe I missed something but was pretty careful.

    Here's what I wrote. Probably can be more compact (?) but works fine. I put it in a static class with other utility functions like remapping a value from one range to another...which should be in the Mathf library, cough, cough... ;)

    Code (CSharp):
    1. public static List<int> randomizeList(List<int> argList) // take list in, randomize order
    2.     {
    3.         int argListCount = argList.Count; // need holder for original length as values are removed in the for loop
    4.         List<int> temp = new List<int>(); // list to hold the randomized values
    5.  
    6.         for (int i = 0; i < argListCount; i++)
    7.         {
    8.             int argListIndex = Random.Range(0, argList.Count);
    9.             temp.Add(argList[argListIndex]);
    10.             argList.RemoveAt(argListIndex); // remove so no repeats
    11.             Debug.Log(temp[i]);
    12.         }
    13.         return temp;
    14.     }
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,412
    Whoa, I dunno what that crazy stuff is... throw that away. Just reason through the code: you choose X numbers and Random never gives you one number (very likely). That number won't be in your series! COMPLETELY broken!

    (Correction: @seejayjames Look at your code, you have a clear bug on the random number. You did not implement the Knuth shuffle. The first argument to Random.Range() cannot be zero. Your bug is on Line 8.)

    Either way, here is what I always use: FAR less memory intensive, no lists, no adding/removing, no garbage collection done.

    Here is what you want:

    1. Make an array, put the numbers 0 to max into each one.

    2. Now implement a Fisher Yates shuffle, pseudocode here:

    https://en.wikipedia.org/wiki/Fisher–Yates_shuffle

    3. and then iterate the items in order.

    Seriously, That's IT. I've been shuffling for a long time and I've worked on a lot of casino titles.
     
    Yanne065 and seejayjames like this.
  5. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    692
    Nice.
    Note: that was my own code, not my implementation of the Knuth shuffle. Looking at Fisher-Yates, I think my code is identical to their original "paper-and-pencil" method:

    1. Take an arbitrary list
    2. Choose one element at random (using the length of the list to pick the random index)
    3. Add that element to another list (that starts empty)
    4. Remove that element from the original list
    5. Repeat steps 2-4 until original list is empty

    Though I imagine adding and removing are wasteful, so swapping works better.
     
    Last edited: Aug 18, 2020
    Kurt-Dekker likes this.
  6. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    692
    Knuth's:

    Code (CSharp):
    1. void List<int> randomizeList(List<int> argList) // take list in, randomize order
    2.     {
    3.         for (int i = 0; i < argList.Count; i++)
    4.         {
    5.             int temp = argList[i];
    6.             int rand = Random.Range(i, argList.Count);
    7.             argList[i] = argList[rand];
    8.             argList[rand] = temp;
    9.             Debug.Log(argList[i]);
    10.         }
    11.         return argList;
    12.     }
     
  7. MaskedMouse

    MaskedMouse

    Joined:
    Jul 8, 2014
    Posts:
    1,094
    Looking up an implementation of Fisher Yates Shuffle in C# and changed it up a slight bit (naming, namespace etc).

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3.  
    4. namespace Utilities
    5. {
    6.     public static class ShuffleUtility
    7.     {
    8.         private static readonly Random random = new Random();
    9.  
    10.         /// <summary>
    11.         /// Shuffle the array.
    12.         /// </summary>
    13.         /// <typeparam name="T">Array element type.</typeparam>
    14.         /// <param name="array">The Array to shuffle.</param>
    15.         public static void Shuffle<T>(IList<T> array)
    16.         {
    17.             var arrayCount = array.Count;
    18.             for (var index = 0; index < (arrayCount - 1); index++)
    19.             {
    20.                 var randomIndex = index + random.Next(arrayCount - index);
    21.                 var arrayValue = array[randomIndex];
    22.                 array[randomIndex] = array[index];
    23.                 array[index] = arrayValue;
    24.             }
    25.         }
    26.     }
    27. }