Reputation: 31
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
Reputation: 2444
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.
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
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