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
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

[solved] Fill array with random integers without having any three in succession be the same

Discussion in 'Scripting' started by ralf_b, Aug 30, 2017.

  1. ralf_b

    ralf_b

    Joined:
    Jul 9, 2013
    Posts:
    48
    Hello everybody,

    although filling an array with ints is rather easy I am stuck with the following problem:
    I would like to fill an array with ints in a certain random range between for example 2-12 but I would also like to have not the same ints for any three successive indexes. So [4,5,4,8,11,5,10] would not be ok.

    My current approach works to a certain extend but is not very ellegant and still fails sometimes for obvious reasons. As soon as my array holds more than two ints the if checks if any new int is the same as the two before the new one, if so it just does another Random.Range. Sure I could now just copy past that last if several times, but to my surprise I still sometimes get doublicates.

    What am I missing?
    Is there a more elegant sollution for a non programmer like me? :p

    Code (CSharp):
    1.  
    2. void Start() {
    3. for (int i = 0; i < tile_last; i++) {
    4.             tile_stream[i] = Random.Range(2,tile_amount);
    5.  
    6.            if (i > 2) {
    7.                 int g = i - 2;
    8.                 int h = i - 1;
    9.                 tile_before_2 = tile_stream[g];
    10.                 tile_before_1 = tile_stream[h];
    11.                 tile_current = tile_stream[i];
    12.                 if (tile_before_2 == tile_current || tile_before_1 == tile_current) {
    13.                     tile_stream[i] = (Random.Range(1, tile_amount));
    14.                     print("random_2");
    15.                 }
    16.                 if (tile_before_2 == tile_current || tile_before_1 == tile_current) {
    17.                     tile_stream[i] = (Random.Range(1, tile_amount));
    18.                     print("random_3");
    19.                 }
    20.                 if (tile_before_2 == tile_current || tile_before_1 == tile_current) {
    21.                     tile_stream[i] = (Random.Range(1, tile_amount));
    22.                     print("random_4");
    23.                 }
    24.             }
    25.         }
    26. }
    27.  
     
  2. Errorsatz

    Errorsatz

    Joined:
    Aug 8, 2012
    Posts:
    555
    You can just access the tiles directly in tile_stream, and use an inner loop instead of multiple ifs. So for example:
    Code (csharp):
    1. public static int[] GenerateRandomInts(int amount, int noRepeatZone, int rangeLow, int rangeHigh) {
    2.     var output = new int[amount];
    3.     bool repeats;
    4.  
    5.     for (int i = 0; i < amount; i++) {
    6.         do {
    7.             repeats = false;
    8.             output[i] = Random.Range(rangeLow, rangeHigh);
    9.             for (int j = i - 1; j >= 0 && j >= i - noRepeatZone; j--) {
    10.                 repeats = repeats || output[j] == output[i];
    11.             }
    12.         } while (repeats);
    13.     }
    14.  
    15.     return output;
    16. }
    The j >= 0 on line 9 is why it doesn't need to check if i > noRepeatZone.
     
    ralf_b likes this.
  3. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,146
    You'll want to do a while loop

    Code (CSharp):
    1.  
    2. while(tile_stream[i] == tile_before_2 || tile_stream[i] == tile_before_1)
    3. {
    4. tile_stream[i] = Random.Range(2, tile_amount);
    5. }
    6.  
    7.  
    I could probably improve this more, but this is the basic idea.
     
    Last edited: Aug 30, 2017
    ralf_b likes this.
  4. ralf_b

    ralf_b

    Joined:
    Jul 9, 2013
    Posts:
    48
    Thanks Errorsatz and Brathnann for your quick replies.
    In the end I went with Brahtnann´s variant, because for me it is easier to read and understand and just three lines :p Also it works like a charm.

    Code (CSharp):
    1. void Start() {
    2. for (int i = 0; i < tile_last; i++) {
    3.             tile_stream[i] = Random.Range(2,tile_amount);
    4.            if (i > 2) {
    5.                 int g = i - 2;
    6.                 int h = i - 1;
    7.                 tile_before_2 = tile_stream[g];
    8.                 tile_before_1 = tile_stream[h];
    9.                 tile_current = tile_stream[i];
    10.  
    11.                 while (tile_stream[i] == tile_before_2 || tile_stream[i] == tile_before_1) {
    12.                     tile_stream[i] = (Random.Range(1, tile_amount));
    13.                 }
    14.             }
    15.         }
    16. }
     
  5. Simo

    Simo

    Joined:
    Sep 16, 2012
    Posts:
    85
    I think there is a better solution for your problem

    Code (CSharp):
    1. void Start()
    2.     {
    3.         int tile_amount = 12;
    4.         int tile_last = 7;
    5.         int[] tile_stream = new int[tile_last];
    6.      
    7.         List<int> tmpList = new List<int>();
    8.         for (int i = 2; i < tile_amount+1; i++)
    9.         {
    10.             tmpList.Add(i);
    11.         }
    12.  
    13.         tile_stream[0] = tmpList[Random.Range(0, tmpList.Count - 1)];
    14.         tmpList.Remove(tile_stream[0]);
    15.         tile_stream[1] = tmpList[Random.Range(0, tmpList.Count - 1)];
    16.         tmpList.Remove(tile_stream[1]);
    17.         tile_stream[2] = tmpList[Random.Range(0, tmpList.Count - 1)];
    18.  
    19.         tmpList.Add(tile_stream[0]);
    20.         tmpList.Add(tile_stream[1]);
    21.  
    22.         for (int i = 3; i < tile_last; i++)
    23.         {
    24.  
    25.             tmpList.Remove(tile_stream[i - 2]);
    26.             tmpList.Remove(tile_stream[i - 1]);
    27.  
    28.             tile_stream[i] = tmpList[Random.Range(0, tmpList.Count - 1)];
    29.  
    30.             tmpList.Add(tile_stream[i - 2]);
    31.             tmpList.Add(tile_stream[i - 1]);
    32.         }
    33.     }