Search Unity

Shuffling 2 separate list in the same order.

Discussion in 'Scripting' started by BrewNCode, Dec 8, 2018.

  1. BrewNCode

    BrewNCode

    Joined:
    Feb 17, 2017
    Posts:
    372
    I have a problem with a game that I'm working on. I have 2 Managers that are attached to 2 different scripts. 1 is a GameManger and the other is a SoundManager. These 2 have a list of words. The GameManager holds the strings that compound the words with a List called Alphabet so this list is roughly like this:
    Code (CSharp):
    1. List<words> {"And", "Ilk", "Amp", "Est"};
    The sound manager calls the word sound of each word. So basically is like this:
    Code (CSharp):
    1. List<WordSound>{"WordAnd", "WordIlk", "WordAmp", "WordEst"};
    The game calls the word from top to button in the GameManager and in the Sound Manager. But the game will always call the same words in every gameplay. How can I make a shuffling list with the two lists so they can have the same shuffled order? meaning:
    Code (CSharp):
    1. List<words>{"Amp", "Ilk", "And", "Est"};
    2.  
    3. and Sound Manager:
    4. List<Sound>{"WordAmp", "WordIlk", "WordAnd", "WordEst"};
     
  2. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    Mehrdad995 likes this.
  3. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    A better solution imo is to make a struct like so
    Code (CSharp):
    1. public struct TextToSound{
    2. public string word;
    3. public AudioClip sound;
    4. }

    just have a list of these, always paired, free to F*** with as you wish.
     
    lordofduct likes this.
  4. BrewNCode

    BrewNCode

    Joined:
    Feb 17, 2017
    Posts:
    372
    So if I have 84 words in each list then if I set the Random.Range(0, 84) in each Manager it should match up?
     
  5. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    For a given seed the random number generator gives the same sequence of numbers. So when you put indices at new positions this should give the same order (theoretically).
    I don't know what you mean with RandomRange(0,84). This should depend on the number of entries in the list.

    SparrowsNest suggestion is also worth noting. This would reduce the hassle altogether but probably needs a redesing/rewrite on your managers. If they have not much functionality yet you should consider this.
     
  6. BrewNCode

    BrewNCode

    Joined:
    Feb 17, 2017
    Posts:
    372
    I guess I don't know what random seed means xD. And the info that I got from google doesn't help me that much. Could you please explain it to me?
     
  7. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    The random seed is the seed that the Random class uses to generate numbers, just like with minecraft, if you put the same seed you get the same world, if you put the same seed you get the same number.

    what you said (Random.Range(0, 84)) is a function within the Random class that spits out an integer in the range of 0-84, the seed is what's used to generate said number.

    I strongly advise to use the solution I said in my previous post.

    but start here if you insist on using the RNG method https://docs.unity3d.com/ScriptReference/Random-state.html
     
    lordofduct likes this.
  8. BrewNCode

    BrewNCode

    Joined:
    Feb 17, 2017
    Posts:
    372
    The problem is that if I have to make a struct I have to change a lot of the code from both managers, and when I say is a lot, it is a huge amount. So I would rather find another approach for the two lists.
     
  9. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    Computer random numbers are mostly not really random but are deterministically calculated from an initial state (seed).
    so my sugestion in pseudocode would be:
    Code (csharp):
    1.  
    2. int seed = Random.Range(0, int.max);   // used for a random order of the elements of both lists
    3. Random.InitState(seed);           // initialize the random number generator
    4. thefirstlist.Shuffle();           // use it to reorder the elements of the list
    5. Random.InitState(seed);           // initialize the random number generator to the same value as before
    6. thesecondlist.Shuffle();       // so it generates the same order for the second list
    7. if(thefirstlist.Count != thesecondlist.count)
    8. {
    9.    Debug.Log("You are in trouble!");
    10. }
    11.  
    note that the linked shuffle extension method above does change the order of the original list. If you need to keep it work on a copy!
     
  10. BrewNCode

    BrewNCode

    Joined:
    Feb 17, 2017
    Posts:
    372
    wait a minute, if I have the soundmanager and the gamemanager attached to different scripts I should use that same method in both scripts?
     
  11. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    You can also split it up. How you organise that is up to you and the current manager structure. But my example is the essence of what should happen. You can call that from wherever it suits you.
     
  12. BrewNCode

    BrewNCode

    Joined:
    Feb 17, 2017
    Posts:
    372
    so for example
    Code (CSharp):
    1. int seed = Random.Range(0, int.max);   // used for a random order of the elements of both lists
    2. Random.InitState(seed);           // initialize the random number generator
    3. thefirstlist.Shuffle();           // use it to reorder the elements of the list
    in the GameManager script

    and then
    Code (CSharp):
    1. int seed = Random.Range(0, int.max);
    2. Random.InitState(seed);           // initialize the random number generator to the same value as before
    3. thesecondlist.Shuffle();       // so it generates the same order for the second list
    In the SoundManager script?
    I'm not going to copy-paste the code but I want to understand if that is what you meant with splitting up.


    Also, what is that Shuffle() function? it is a built-in function from Unity? I'm trying to figure out from your pseudo-code where should I put my Lists.
     
  13. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    I would like to reassert @SparrowsNest solution, at the very least something similar to their solution!

    Using a random seed to generate the same sequence twice to result in the same shuffle twice so that you have 2 coincidentally sorted smells odorous of the worst kinds in regards to code smell. Tossing in the anti-pattern design of unity's 'Random' class doesn't help much here either (I'd suggest the .Net System.Random class at the very least if you were to do anything remotely like this). And lastly you're doing twice the amount of work to do something.

    ...

    Where I'm left puzzled is how did your SoundManager and your GameManager get set up with this order? Why is the SoundManager managing this order?

    Why isn't this sorted/shuffled the way you need before hand, and then passed to the appropriate manager's in the correct order before running them.

    And that is where I resort back to SparrowsNest solution. You should be doing something like this. Where you shuffle some relationship between the 2 things, and then hand that data out. The idea that there is no good place to perform this task says to me that something is poorly designed in the structure of GameManager and SoundManager.
     
  14. Yeah, it even badly smells for me. And that's saying somethin'.... :D

    I would refactor to what @SparrowsNest offered. It worth the time. And it will be more performant as well since you don't do the same thing twice.
     
  15. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    I'm sure it's not nearly as much as you think it is.

    Also i agree with @lordofduct and @LurkingNinjaDev , it seems that the way you structure you managers is not optimal
    Espically with the fact the RNG method is fragile as all hell and that its better to use the "normal" Random class znd not unity's
     
  16. BrewNCode

    BrewNCode

    Joined:
    Feb 17, 2017
    Posts:
    372
    1) I don't know what do you mean with order, so I will assume that you meant about the order list. They just handed me the word list like that.

    2) I would love to understand that as well. My bet is that the last programmer who created the level wanted to do the fastest way possible so he just arranged the soundmanager list as the same order of the word list on purpose so the sounds words will play as the order of the word list was set as default. Like everything is mechanized, arranging randomly the word list is pointless becuase the soundmanager will play the sounds as the default order of the sound list regardless.

    3) number 2 answers this question a bit. The last programmer didn't thought about randomization nor shuffling at all.
     
  17. BrewNCode

    BrewNCode

    Joined:
    Feb 17, 2017
    Posts:
    372
    Sorry, I know where to put the Lists, but I still don't know where that Shuffle function appeared.
     
  18. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    The splitting you posted would produce different orders since you use a different seed for both. I don't know how you organice your code and what method is called from where. You create a random number. Set it as seed for the random number generator. Shuffle one list. Seed the rng again with the same numer. shuffle the second list. You can pass the seed as parameter to both of your managers and let them shuffle their lists in a method each. or when the lists are public you do it from another class. does not matter where to call it. just the principle must be in place. Set the seed, shuffle the first list. set the seed again and shuffle will create the same order in the other list.