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. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

Array or list for trivia game? C#

Discussion in 'Scripting' started by Joevonfo, Aug 17, 2018.

  1. Joevonfo

    Joevonfo

    Joined:
    Mar 31, 2015
    Posts:
    95
    Hi guys

    I'm in the process of making a trivia game, and need your opinions on a matter regarding the questions..

    I basically need to have an amount of questions and then, once a question is drawn remove it from the possible questions for the rest of the game..

    As far as I understand lists can expand, but in this case I don't need it to expand.. only decrease..
    Should I still use a list or is an array fine? (or more efficient even?)

    Regardless of whether its an array or a list, what function will I then need to call a random variable from the array/list and then remove that variable from said list/array?

    It's that last part about removing it from the array/list than I'm unsure about.

    Thank you in advance!
     
  2. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    Have a list of questions (or dictionary keys or however you want to structure it).

    Choose a random number between 0 and list.Count()-1.

    Pull that entry from the list using list.RemoveAt(). That's your question. Because it's been pulled from the list, it won't repeat.
     
  3. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    For something like this, it probably doesn't matter (performance-wise) whether you use an array or a List, so I'd still stick with a List.
    Then you can just follow what BlackePete stated above.
     
    Kiwasi likes this.
  4. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Lists are easier to use when their length is going to change over time.
     
  5. Fido789

    Fido789

    Joined:
    Feb 26, 2013
    Posts:
    343
    As others said, use List. This is the right collection for your task.
     
  6. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    Use a queue that you populate by selecting randomly from the global array of all questions.
     
    Kiwasi likes this.
  7. Joevonfo

    Joevonfo

    Joined:
    Mar 31, 2015
    Posts:
    95
    Thank you for the answers guys!

    I still havn't quite found a solution though..
    I'm not very experienced with using lists, so I got a few issues..
    Currently I've made a travia-question system that works like this:

    Each question has three possible answers. Each answer has a script like this:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [System.Serializable]
    6. public class Answer1Data
    7. {
    8.     public string answer1Text;
    9.     public bool isCorrect;
    10. }

    Each question then have this script:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [System.Serializable]
    6. public class QuestionData
    7. {
    8.     public string questionText;
    9.     public Answer1Data answer1;
    10.     public Answer2Data answer2;
    11.     public Answer3Data answer3;
    12. }
    13.  

    I then have this script to define stuff like timelimit, points won or lost and so on.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [System.Serializable]
    6. public class RoundData
    7. {
    8.     public int timeLimitInSeconds;
    9.     public int hiddenTimeLimitInSeconds;
    10.     public int pointsAddedForFirstCorrectAnswer;
    11.     public int pointsAddedForSecondCorrectAnswer;
    12.     public int pointsSustractedForWrongAnswer;
    13.     public QuestionData[] questions;
    14. }
    15.  

    I then finally have a script that tie all the scripts above together, so that the information can be decided from the inspector:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.SceneManagement;
    5.  
    6. public class DataController : MonoBehaviour
    7. {
    8.     public static DataController instance;
    9.     void Awake()
    10.     {
    11.         if (instance == null)
    12.         {
    13.             instance = this;
    14.             DontDestroyOnLoad(gameObject);
    15.         }
    16.         else
    17.         {
    18.             Destroy(gameObject);
    19.         }
    20.     }
    21.  
    22.     public RoundData[] allRoundData;
    23.  
    24.     void Start()
    25.     {
    26.         SceneManager.LoadScene("MenuScreen");
    27.     }
    28.  
    29.     public RoundData GetCurrentRoundData()
    30.     {
    31.         return allRoundData[0];
    32.     }
    33. }
    34.  
    I made the scripts this way, to make the overview in the inspector look somewhat neat, since I won't be the one writing all the questions myself.
    As mentioned, I am by no means a good programmer, so I am sure that this is a very cluncky way to do it and that it probably could be done from a single script, but I just don't know how.

    But in either case..
    How do I turn something like this into lists instead of arrays?
    As mentioned I only really have experience with arrays, and when I try to figure out how to make the same thing with lists instead I keep getting various scripting errors.
     
  8. Joevonfo

    Joevonfo

    Joined:
    Mar 31, 2015
    Posts:
    95
    And I forgot to ask:

    If it is difficult to change the code I posted above into using lists, instead of arrays, should I then use the same "array.RemoveAt()" approach or is it done differently with arrays?
     
  9. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,914
    Arrays are a crude low-level data structure. They're for speed, or for quickly making very simple things. Lists are the good version of arrays. They have an array inside of them. If you use an array, and add extra features to make it more useful, you're just rewriting a worse version of what List's already have.

    Unity uses arrays in lots of places for the same reason it uses floats -- for games worried about FPS. Don't let it give you the wrong impression. Normal programs use doubles, and Lists.
     
  10. Joevonfo

    Joevonfo

    Joined:
    Mar 31, 2015
    Posts:
    95
    But wouldn't that basically mean that games should prefer arrays (I know that my trivia game won't have problems with fps, but on at larger scale?).
     
  11. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Depends. If you are going to resize the collection, then you are going to need to implement your own wrapper for array which won't be all that different from List<T>. If your collection doesn't every change size, use an array.
     
  12. Joevonfo

    Joevonfo

    Joined:
    Mar 31, 2015
    Posts:
    95
    My collection will only have to be able to become smaller.. Never grow in size..
    Are arrays okay for that purpose?

    Lists seems smarter, so I'd rather use them, but I can't figure out how to use lists if I want to make the inspector looking neat (as shown in my coding example above, where each objects in the array has a drop down arrow, that leads to the answers and boleans declaring if they're true or not)
     
  13. Joevonfo

    Joevonfo

    Joined:
    Mar 31, 2015
    Posts:
    95
    So far I've made it work the way I wanted to by using arrays (couldn't figure out how to make it work with lists).

    But I still cannot figure out how to remove the pulled index from the array..
    If I use "RemoveAt" is gives me a "does not contain a definition for RemoveAt"-error.

    When searching I can find some sites saying that c# has no RemoveAt..
    What should I then use instead?
     
  14. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    I believe this should work:
    Code (CSharp):
    1. myList.Remove(myList[<index>]);
    Where <index> = an integer value.
     
  15. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    Lists have a RemoveAt function.

    Can you post code of how you were trying to build a list?

    Here's a very simple example of how to build a list, then remove an item:

    Code (csharp):
    1.  
    2. List<string> someStringList = new List<string>();
    3. someStringList.Add("Hello");
    4. someStringList.Add("Goodbye");
    5. someStringList.Add("World.");
    6.  
    7. someStringList.RemoveAt(1);
    8.  
    9. for (int i = 0; i < someStringList.Count(); ++i)
    10.     Debug.Log(someStringList[i]);
    11.  
     
  16. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    Although, after reading the code you've posted, I do think I see a source of confusion: You may not want to remove stuff from a serializable container at runtime. What I originally was suggesting is you build a temporary list using random questions selected from a master array of questions.

    However, since you have your questions baked into RoundData, it doesn't look like you actually want a random set of questions for each round. Is that correct?
     
  17. Joevonfo

    Joevonfo

    Joined:
    Mar 31, 2015
    Posts:
    95
    Well yes and no..
    I'm making a "game" meant to be used for practicing trivia knowledge on some topics..
    I made a simple version some time ago, but in that version the questions always came in the same order, which made it easier to remember (without necessarily learning the actual answer.. just the order).

    So what I wanted to create was basically the same thing but randomized..

    So that you get a question with 3 possible answers.
    Then you end your turn (there is some board game movement involved) and then again, at the end of your next turn, you get a new question.. But without any risk of the question being repeated and preferably also without the order being the same every time you play.

    The biggest hindrance however, was that I tried to write the code so that it would be costumizable through the inspector and look something like this:

    https://ibb.co/eOH33K


    (Edit: Couldn't figure out how to upload image directly.. but link is to imageshare)

    But if that is much more complicated then writing it in the script will have to do..
    I'm just not going to be writing all the questions myself, so wanted to make it easy for my friends to use :)
     
  18. Joevonfo

    Joevonfo

    Joined:
    Mar 31, 2015
    Posts:
    95
    Remove is not something it will recognize either (It might if I had used list instead of array though)
     
  19. Fido789

    Fido789

    Joined:
    Feb 26, 2013
    Posts:
    343
    @BlackPete is right. There are actually two collection, not one.

    The first one is your predefined array of questions for each round. Let it be array and keep it intact. There is no need to remove anything from this array.

    And the second one is the queue of the questions for actual round. It can be a List, or a Queue, anything. Name it remainingQuestions or questionsQueue or something appropriate, initialze it from your original array and use it, for example like this.

    Code (CSharp):
    1. // questions is your original array of questions, your predefined questions
    2. // this statement will create a list and shuffle it
    3. var shuffledQuestions = questions.OrderBy(q => Guid.NewGuid()).ToList();
    4.  
    5. // this will create a queue from your shuffled questions
    6. var queuedQuestions = new Queue<Question>(shuffledQuestions);
    7.  
    8. // this will assign next question to the questionX variable AND remove it from the queue
    9. var question1 = queuedQuestions.Dequeue();
    10. var question2 = queuedQuestions.Dequeue();
    11. var question3 = queuedQuestions.Dequeue();
     
  20. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    Well yes, Remove is a List method. You cannot remove spaces in an array.
     
    Kiwasi likes this.
  21. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,914
    I never thought too hard about this, and I don't use industrial C# for anything else, but I always assumed Unity serialized reads worked the same as any other file read. Your memory is all copies of the serialized data. Once your variable is initialized from the serialized data, it's no different than anything else -- it isn't "backed" by the saved data. But this is just from noticing I can change public int n; and it snaps back, so I assume larger structures work the same.
     
    Kiwasi likes this.
  22. billmarch

    billmarch

    Joined:
    Apr 17, 2019
    Posts:
    1
    try this detailed tutorial on...C# List
     
  23. Boz0r

    Boz0r

    Joined:
    Feb 27, 2014
    Posts:
    419
    Array is faster, but List is easier to use, has helper methods, and can actually resize.
    Use List, and don't make premature optimizations. If there's no performance issue, there's no need to make your code more complex and less readable, and unless you're reading and writing to the array a thousand times a frame, you're not going to see any difference.