I'm trying to make a program that will ask you random questions from an array. You answer them, and it tells you whether or not you are correct.
I have a questions array:
String[] questions = {"Type A", "Type B", "Type C", "Type D", "Type E", "Type F", "Type G"};
and then I have an answers array. they correspond with each other, so answers[0]
is the answer to questions[0]
String[] answerKey = {"A", "B", "C", "D", "E", "F", "G"};
int questionNum = 0; //Used as a counter for the questions.
Here is my code attempt.
public void setUpQuestion() {
String[] answers = new String[4]; //An array of possible answers.
ArrayList<Integer> usedNumbers = new ArrayList<Integer>(); //An Arraylist of question positions.
ArrayList<Integer> usedQuestions = new ArrayList<Integer>(); //A copy of the usednumbers arraylist
for (int i = 0; i < answerKey.length; i++) //Add 0 through 6 to this arraylist, represents the questions
usedNumbers.add(i);
Collections.shuffle(usedNumbers); // Shuffle the arrayList into a random order
usedQuestions = usedNumbers; //Copy the array
for (int a = 0; a < answers.length; a++) { // This for loop should add random answers to the answers array
if (a == 0) {//For the first time around, add the correct answer into the array
answers[a] = answerKey[usedQuestions.get(questionNum)]; //answers[0] = the correct answer to the question
usedNumbers.remove(questionNum); //remove it from the copied array, so we don't accidentally use it twice
} else if (a != 0) { //For the rest of the spots, randomly pick answers that are wrong
answers[a] = answerKey[usedNumbers.get(0)];//pick a random answer that is next
usedNumbers.remove(0);//Remove it so it isnt used again
}
}
lblQuestion.setText(questions[usedQuestions.get(questionNum)]); // Set the label to the question
shuffleArray(answers);//shuffle the array of answers
btnA.setText(answers[0]); //set the button to one of the answers, etc;
btnB.setText(answers[1]);
btnC.setText(answers[2]);
btnD.setText(answers[3]);
}
Hopefully I've commented it thoroughly enough so you know what the code is doing
This seems like it should work in theory, however, when I run it, this happens: There is no correct answer listed.
If anyone could help me figure out why this isn't working, I would really appreciate it.
Thank you!
Edit:
I have tried a different approach that may work better. I created a Question object that has the parameters of String question, String answer.
So, I made a bunch of new Question objects
public int questionNum = 0; //this is a global variable
Question a = new Question("Type A", "A");
Question b = new Question("Type B", "B");
Question c = new Question("Type C", "C");
Question d = new Question("Type D", "D");
Question e = new Question("Type E", "E");
Question[] questionBank = {a, b, c, d, e};
ArrayList<Question> questionArray = new ArrayList<Question>();
Here's my new attempt at the code:
for (int i = 0; i < questionBank.length; i++) questionArray.add(questionBank[i]);//Add all question objects to an arraylist
String[] answers = new String[4];//possible answers
Collections.shuffle(questionArray);//randomize thequestion array,
for (int a = 0; a < answers.length; a++) {
if (a == 0) {//First time around, add the correct answer to the array
answers[a] = questionArray.get(questionNum).getA();//getA() method gets the answer from the question array
} else if (a != 0) {
answers[a] = questionArray.get(a).getA();
questionArray.remove(a);
}
}
lblQuestion.setText(questionArray.get(questionNum).getQ()); //Gets the current question
btnA.setText(answers[0]);
btnB.setText(answers[1]);
btnC.setText(answers[2]);
btnD.setText(answers[3]); //set the answers on the buttons
questionArray.remove(questionNum);
Change
usedQuestions = usedNumbers;
to
usedQuestions = new ArrayList<>(usedNumbers);
How this works
Observer the following example:
Integer h = 3;
Integer j = h;
h++;
System.out.println(j);
What will the output be? As you might think, it's 3
.
h
got the value of 3. j
got the same value as h
. h
was changed. j
wasn't changed. j
is h
's previous value. Sure enough, you write this:
ArrayList<Integer> usedNumbers = new ArrayList<Integer>();
ArrayList<Integer> usedQuestions = new ArrayList<Integer>();
for (int i = 0; i < 3; i++) // add 0, 1, 2
usedNumbers.add(i);
usedQuestions = usedNumbers;
usedNumbers.remove(0);
System.out.println(usedQuestions);
thinking that the output will be [0, 1, 2]
. Wrong! Let's see the difference from the first case.
usedNumbers
got the values [0, 1, 2]
. usedQuestions
got the same value as usedNumbers
? NOPE! usedQuestions
got the same reference as usedNumbers
. (explanation below) usedNumbers
was changed. usedQuestions
was changed. usedQuestions
has the changed value of [1, 2]
. In Java, most objects are reference types . It means that what the variable it is holding is a reference to the value (a pointer to the address in memory). When you wrote usedQuestions = usedNumbers
what you did is give the "arrow" which is pointing to the list [0, 1, 2]
to usedQuestions
. Now, when you change the list (with remove
), you change the value of the list, but every variable which holds a reference to that list will give the same modified list .
The first example worked as expected because int
is a primitive type where the variable holds a "real" value, and not a pointer to it. In this case changing the number (with ++
) actually changed the value of the number, but all other numbers were remained unchanged.
This goes hand in hand with shallow copy vs deep copy . There are more questions on this site and articles about it than I'd care to link, so just Google it and you'll get more than what you bargained for. The short explanation is that shallow copy only copies the reference which is what you did, while deep copy makes a "real" copy of the value. A "real" copy means that
The line usedQuestions = new ArrayList<>(usedNumbers);
essentially makes a deep copy of the list (only because it's a list of Integer
), while usedQuestions = usedNumbers
is a shallow copy.
There are quite a few fine points I didn't address here, nor was I too technically accurate, but I'm trying to explain a subtle and important topic simply.
If you understood this, you might have understood that the line
ArrayList<Integer> usedQuestions = new ArrayList<Integer>();
can just be
ArrayList<Integer> usedQuestions;
The reason is that you don't need to initialize the list at this point in the code as it will be initialized later with new ArrayList<>(usedNumbers)
. To be specific, in your original code you "threw away" the pointer to the original empty list in the right hand side of
ArrayList<Integer> usedQuestions = new ArrayList<Integer>();
when you gave usedQuestions
the pointer to the list in the right hand side of
ArrayList<Integer> usedNumbers = new ArrayList<Integer>();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.