James Hadnett
James Hadnett

Reputation: 31

How to select a number from random pool, then make so number can't be reselected

I'm basically trying to write a quiz as part of my classwork for computer programming, and I've ran into a spot of bother.

I want the questions to be selected from a random pool to discourage cheating, I could make it so that it randomly selects between the numbers of 1,8 but that can cause repeats in the questioning, which is something that I don't want.

Random random = new Random(); // We use this random object to choose random icons for the squares.

    List<int> Assignments = new List<int>()
    {

        1,2,3,4,5,6,7,8

    };

    Random RandomlyChooseNumbers = new Random();

    int AssignmentForQ1;
    int AssignmentForQ2;
    int AssignmentForQ3;
    int AssignmentForQ4;
    string CorrectAnswerA1;
    string CorrectAnswerA2;
    string CorrectAnswerA3;
    string CorrectAnswerA4;
    public double timePassed;
    public int calculatedScore;
    public int timeLeft;

    public frmQuizOneHardMode()
    {
        InitializeComponent();

        AssignQuestionToTextQ1();

    }

    private void AssignQuestionToTextQ1()
    {
        int randomNumber = RandomlyChooseNumbers.Next(Assignments.Count);

        AssignmentForQ1 = Assignments[randomNumber];

        Assignments.RemoveAt(randomNumber);

        AssignmentForQ2 = Assignments[randomNumber];

        Assignments.RemoveAt(randomNumber);

        AssignmentForQ3 = Assignments[randomNumber];

        Assignments.RemoveAt(randomNumber);

        AssignmentForQ4 = Assignments[randomNumber];

        Assignments.RemoveAt(randomNumber);
    }

But for some reason, the numbers are always the same, which means that AssignmentForQ1,Q2,Q3 and Q4 all show the exact same question, I have literally no idea what's going wrong here, can someone please help?

EDIT: I would personally like to thank Jamiec, mate you are a complete life-saver, I couldn't have done this without you, thanks!

Upvotes: 3

Views: 2157

Answers (2)

Jim Buck
Jim Buck

Reputation: 2444

TL;DR

Instead of trying to generate a random number each time, you could just randomize the list and grab the first n items that will fulfill your requirements.

Details

If you have a total of 20 questions, but the quiz is only 10, then randomize the list of 20 and select the first 10. I would also suggest you create a datastructure to store this information, instead of just AssignmentForQ1, AssignmentForQ2, etc. Use something like the following:

public class Question
{
    public int Assignment { get; set; }
    public string ActualAnswer { get; set; }
    public string SelectedAnswer { get; set; }

    public bool IsCorrect
    {
        get { return String.Equals(ActualAnswer, SelectedAnswer, 
            StringComparison.InvariantCultureIgnoreCase); }
    }
}

public class Quiz
{
    public List<Question> Questions { get; set; }

    public int CalculatedScore
    {
        get { return Questions.Count(q => q.IsCorrect); }
    }

    public DateTime TimeStarted { get; set; }
    public TimeSpan TimeAllowed { get; set; }

    public TimeSpan TimeRemaining
    {
        get { return DateTime.Now - (TimeStarted + TimeAllowed); }
    }

    public TimeSpan TimeElapsed
    {
        get { return DateTime.Now - TimeStarted; }
    }
}

Then store these in a List<Question> and randomize it like so:

Random rand = new Random();
List<Question> questions = new List<Question>();

var myQuiz = new Quiz
{
    TimeAllowed = TimeSpan.FromMinutes(15),
    Questions = questions.OrderBy((q) => rand.Next()).Take(10).ToList()
};

This will give you 10 random questions, with no repeats! While this is not the most optimized shuffle, it simply gets the job done. Check out this answer for a more detailed description on how to safely and efficiently shuffle a list.

In the end, try to use Classes to encapsulate your data, it will make things a lot easier to understand and expand on when the time comes.

Upvotes: 4

Jamiec
Jamiec

Reputation: 136114

You're half way there. The general idea is to pick a random number, then remove that element so it cant be re-selected. However, you need to pick a new random number after each try from the reduced set in order for all elements to be random.

 int randomNumber1 = RandomlyChooseNumbers.Next(Assignments.Count);

 AssignmentForQ1 = Assignments[randomNumber1];

 Assignments.RemoveAt(randomNumber1);

 // set is reduced
 int randomNumber2 = RandomlyChooseNumbers.Next(Assignments.Count);

 AssignmentForQ2 = Assignments[randomNumber2];

Assignments.RemoveAt(randomNumber2);

This can be simplified by using an array for your assignments and a loop

int[] Questions = new int[4];
for(var i=0;i<Questions.Length;i++)
{
    int randomNumber = RandomlyChooseNumbers.Next(Assignments.Count);
    Questions[i] = Assignments[randomNumber];
    Assignments.removeAt(randomNumber);
}

Upvotes: 6

Related Questions