Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by Sendatsu_Yoshimitsu · May 19, 2015 at 01:55 AM · c#listrandom

Selecting random indexes without repetition

I'm writing a flashcard system, every time I generate a question the game needs to look at the flashcards I give it and a) randomly generate 4 answers, b) ensure that ONE of those answers is the correct one, c) make sure that ONLY one card is the correct one.

I started by shuffling the list and selecting the first n entries:

 void GenerateNewCards(){
     targetWordHolder.card = GenerateCard ();        //Select a random flashcard from the deck- this is the card the player will be tested on
     SetButtonText (targetWordHolder, questionFormat); //Depending on which elements of the flashcard the player wants to be tested on, display a prompt

     cardLibrary = ShuffleList (cardLibrary);        //Shuffle the List<Card> of flashcards

     for (int i = 0; i < buttonList.Count; i++) { //For every button the player has to pick from...
         buttonDict[buttonList[i]].card = cardLibrary[i]; //Assign a random card from the library
         SetButtonText(buttonDict[buttonList[i]],answerFormat); //Set that button's text equal to the prompt the player needs to know/guess
     }

From here, the problem is preventing repetition: I could select one of my buttons at random, and set that equal to the answer card...

 buttonDict [buttonList[Random.Range (0, buttonList.Count)]].card = targetWordHolder.card; //Guarantees that the correct card will be an option

...but the correct answer is in the deck I generated choices from, so there's a possibility that the same answer appears twice, which isn't ideal.

Is there any reasonably straightforward way I can keep this from happening? The ideal scenario is four (or however many) different random choices each time, only one of which is the correct choice.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer Wiki

Answer by Michael-Glen-Montague · May 19, 2015 at 10:10 AM

This function returns an array of unique items taken out of an existing array. Its first parameter is the array of items to choose from, and the second parameter is the size of the array you want to return.

 /// <summary> Returns an array of random unique elements from the specified array. </summary>
 public static T[] GetRandomArray<T>(T[] array, int size)
 {
     List<T> list = new List<T>();
     T element;
     int tries = 0;
     int maxTries = array.Length;
 
     while (tries < maxTries && list.Count < size)
     {
         element = array[UnityEngine.Random.Range(0, array.Length)];
 
         if (!list.Contains(element))
         {
             list.Add(element);
         }
         else
         {
             tries++;
         }
     }
 
     if (list.Count > 0)
     {
         return list.ToArray();
     }
     else
     {
         return null;
     }
 }
Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Sendatsu_Yoshimitsu · May 19, 2015 at 10:53 AM 0
Share

Thank you... is there a general guideline as to when it's faster to use if (!element) compared to shuffling the list? I was under the impression that the latter gained in efficiency as the size of the list grew past a certain point.

avatar image FortisVenaliter · May 19, 2015 at 02:07 PM 0
Share

Please note however that that particular implementation generates quite a bit of memory that will leak to the GC, and should not be called every frame.

avatar image
0

Answer by FortisVenaliter · May 19, 2015 at 02:40 AM

You could have a list of used indices. With each new card, clear the list. Each time you set an answer, add the index of the answer from the full deck. Then do something like:

 int newIndex = RandomFunc();
 while(usedIndices.Contains(newIndex))
     newIndex = RandomFunc();
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Sendatsu_Yoshimitsu · May 19, 2015 at 03:12 AM 0
Share

Hmm, what do you think- I adapted this a bit, while keeping my need to retain total control over the target card:

 void GenerateNewCards(){
     targetWordHolder.card = GenerateCard ();        //Select a random flashcard from the deck- this is the card the player will be tested on
     SetButtonText (targetWordHolder, questionFormat); //Depending on which elements of the flashcard the player wants to be tested on, display a prompt

     List<Card> tempList = new List<Card> ();

     tempList.Add (targetWordHolder.card);

 //    cardLibrary = ShuffleList (cardLibrary);        //Shuffle the List<Card> of flashcards

     while (tempList.Count < buttonList.Count){
     
         int randomNumber = Random.Range (0, cardLibrary.Count);
         while (tempList.Contains(cardLibrary[randomNumber]))
                randomNumber = Random.Range (0, cardLibrary.Count);
         tempList.Add (cardLibrary[randomNumber]);

     }

     tempList = ShuffleList (tempList);

     for (int i = 0; i < buttonList.Count; i++) { //For every button the player has to pick from...
         buttonDict[buttonList[i]].card = tempList[i]; 
         SetButtonText(buttonDict[buttonList[i]],answerFormat);
     }
 }

avatar image
0

Answer by shopguy · May 19, 2015 at 02:51 AM

I think you might be making this more complex than it needs to be. If you are shuffling the cards, do you really need to pick random cards also? It should be just as random if you simplify and just take however many cards you need from the top of the pile.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Sendatsu_Yoshimitsu · May 19, 2015 at 02:59 AM 0
Share

I could definitely be overcomplicating it, but I do need to retain some pretty fine-grained control over which cards you're tested on: the default logic is to iterate through the entire deck until the player has gotten each card right, and it uses some spaced repetition stuff on the cards you're getting wrong, so I need to be able to guarantee that certain cards will come up a certain number of times. To that end, setting the target card and then filling in the rest with randoms seemed like the best bet.

I suppose I could just check the cards that had been dealt to ensure that they didn't match the one was I going to set later...

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

21 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Pick between two floats 2 Answers

Printing a GUI selection grid in order 1 Answer

How can I display 4 items in random order but never double? 2 Answers

Printing an ordered list 1 Answer

Add random amount of random items from one list to another? 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges