We determined that we needed a method to prepare a question for us; setQuestion seems like a decent name for such a method. Every time our player gives an answer by tapping one of the three multi-choice buttons, a new question will need to be prepared. This method will need to generate values for our partA and partB variables as well as show them in our TextViews referenced by the textObjectPartA and textObjectPartB objects. In addition, the method will need to assign the new correct answer to our correctAnswer variable, which will then be used to calculate some suitable incorrect answers. Finally, the method will show both the correct and incorrect answers on our multi-choice buttons.
Furthermore, our setQuestion method will need to take into account the level held in currentLevel to determine the range or difficulty of the question it will ask. Let's go through the code. If you want to type this code as we go, then just make sure you place it after the closing bracket of onClick but before the closing bracket of our GameActivity class:
1. First of all, we have the method signature and the opening curly brace before the body of our method:
void setQuestion(){
2. This tells us that the return type is void, so setQuestion will not return a value to the code that calls it. Also, there are no parameters here, so it does
not need any value passed for it to work. Let's see what it does. Now we
enter the code to generate the two parts of the question:
//generate the parts of the question int numberRange = currentLevel * 3; Random randInt = new Random();
int partA = randInt.nextInt(numberRange); partA++;//don't want a zero value
int partB = randInt.nextInt(numberRange); partB++;//don't want a zero value
3. In the previous step, we declared a new int variable, numberRange, and
initialized it by multiplying the player's currentLevel value by 3. Then we got a new Random object called randInt and used it to generate new values based on numberRange. We did this to the partA and partB variables. As the value of currentLevel increases, so potentially does the difficulty of the question. Now, just as we have written in the past, we write this:
correctAnswer = partA * partB; int wrongAnswer1 = correctAnswer-2; int wrongAnswer2 = correctAnswer+2; textObjectPartA.setText(""+partA); textObjectPartB.setText(""+partB);
4. We assigned the answer of our new multiplication question to
correctAnswer. Then we declared and assigned two incorrect answers to the new int variables, wrongAnswer1 and wrongAnswer2. We also used the setText method of our TextView objects to display the question to the player. Notice that we have not yet displayed the correct and incorrect answers. Here it is. Try to work out what is happening here:
//A number between 0 and 2
int buttonLayout = randInt.nextInt(3); switch (buttonLayout){ case 0: buttonObjectChoice1.setText(""+correctAnswer); buttonObjectChoice2.setText(""+wrongAnswer1); buttonObjectChoice3.setText(""+wrongAnswer2); break; case 1: buttonObjectChoice2.setText(""+correctAnswer); buttonObjectChoice3.setText(""+wrongAnswer1); buttonObjectChoice1.setText(""+wrongAnswer2); break; case 2: buttonObjectChoice3.setText(""+correctAnswer); buttonObjectChoice1.setText(""+wrongAnswer1); buttonObjectChoice2.setText(""+wrongAnswer2); break; } }
5. In the preceding code, we used our Random object, randInt, to generate a number between 0 and 2, and assigned the value to a new int variable called buttonLayout. We then used buttonLayout to switch between all its possible values: 0, 1, or 2. Each case statement sets the correct and incorrect answers
to the multi-choice buttons in a slightly different order, so the player can't
just keep tapping the same button over and over to achieve a massive score. Notice the extra closing bracket after the closing bracket of the switch. This is the end of our setQuestion method.
We explained the code fairly thoroughly as we went through it but it might be worthwhile to just take a closer look at some parts again.
In step 1, we saw our method signature with a void return type and no parameters. In step 2, we generated some random numbers that will be within a certain range.
This range isn't as obvious as it might seem at first. First, we assigned, declared,
and initialized numberRange like this: int numberRange = currentLevel * 3;
So if the player is at the first question, then currentLevel will hold the value 1 and numberRange will be initialized as 3. Then we made a new Random object as previously discussed and entered this line of code:
int partA = randInt.nextInt(numberRange);
What occurs here is that the nextInt method of the Random object, randInt, will
return a value of either 0, 1, or 2 because we have given it a seed of 3. We don't want
any zeros in our game because they result in very easy multiplication, so we enter this:
partA++;//don't want a zero value
This operator, which you probably remember from Chapter 3, Speaking Java – Your First Game, when we discussed operators, adds 1 to partA. We then do exactly the same to our partB variable, which means that assuming that the player is still on level 1, they will have a question that will be one of the following:
1 x 1, 1 x 2, 1 x 3, 2 x 1, 2 x 2, 2 x 3, 3 x 1, 3 x 2, or 3 x 3
As the level increases, the potential range of the question increases significantly. So at level 2, the options are that either part of the question could be from 1 to 6; for level 3, from 1 to 9; and so on. It is still possible to get an easy question on a higher
level but it becomes less likely as the levels advance. Finally in this step, we display the question to the player using the setText method.
In step 3, we have seen before but this time we varied it slightly. We calculate and assign a value for correctAnswer, and declare and assign values to wrongAnswer1 and wrongAnswer2, which will hold the wrong answer choices for our buttons. Part 3 varies very slightly from what we did in onCreate in the previous chapter because we subtract and add 2 to wrongAnswer1 and wrongAnswer2, respectively. This makes guessing the answer to multiplication questions a little harder because
you can't eliminate answers based on whether they are odd or even.
Step 4 simply randomizes which buttons the correct and incorrect answers will
be placed on. We don't need to keep track of this because when the time comes to
compare the value on the button pressed with the correct answer, we can simply use our Java code to discover it as we did in Chapter 3, Speaking Java – Your First Game.
The updateScoreAndLevel method
The name of this method speaks for itself. Because the keeping of the score is not simple and because we want higher levels to yield higher scores, we will compartmentalize the code to keep our program readable. If we then want to
make modifications to the scoring system, they can all take place in there. Let's write the code.
1. This code can go anywhere within the opening and closing braces of GameActivity {}, but it is good practice to place them in the approximate order they will be used. So why not start adding your code after the closing brace of setQuestion but obviously before the closing brace of GameActivity? Here is the method signature with the opening brace: void updateScoreAndLevel(int answerGiven){
2. This tells us that our method does not return a value but that it does receive an int, which it will require to do its stuff. The name of the parameter is a big clue to what we will be passing. We will see that in action in the body
in a minute, but if passing the player's answer to this method instead of the
isCorrect method is a bit confusing, we will see things become clearer in the next chunk of code. Here is the next part of the code to add:
if(isCorrect(answerGiven)){
for(int i = 1; i <= currentLevel; i++){ currentScore = currentScore + i; }
currentLevel++; }
3. There is a lot happening here, so we will dissect it more once we have the method completed. Basically, it calls the isCorrect method (which we will write soon) and if the response is true, adds to the player's score in a for loop. After that, the method adds 1 to currentLevel. Here comes the else part of the code in case the response from isCorrect is false: else{
currentScore = 0; currentLevel = 1; }
4. If the response is false, that is, if the player got the answer wrong, the currentScore variable is set to 0 and the level back to 1. Finally for this method, we type the following:
//Actually update the two TextViews
textObjectScore.setText("Score: " + currentScore); textObjectLevel.setText("Level: " + currentLevel); }
5. In the previous step, we updated the actual TextViews that the player sees with the newly determined score and level. The method then ended and the control of the program returned to the code that called updateScoreAndLevel to begin with. Save your project.
We explained most of the code as we went but it might be good to quickly review it and dig a bit deeper into certain parts, especially the call to isCorrect in that odd-looking if statement.
In step 1, we began with the method signature. Then in step 2, we began with the aforementioned curious if:
if(isCorrect(answerGiven)){
We have seen this type of statement before in the A working method example in the
Methods section of this chapter. What is happening here is that the call to isCorrect is replacing the statement to be evaluated, or rather it is the statement to be
evaluated. So isCorrect is called with the answerGiven variable. The answerGiven variable, as you might remember, was passed to updateScoreAndLevel. This time, it is passed to the isCorrect method, which will do some work with it and perhaps a few other things. Then it will return to the if statement a value of true or false. The value will be true if the question is answered correctly and false if not.
Assuming the if statement evaluates to true, the program runs this bit of code (also from step 2):
for(int i = 1; i <= currentLevel; i++){ currentScore = currentScore + i; }
currentLevel++;
The code enters a for loop where the starting variable i is initialized to 1 like this: int i = 1;. Furthermore, the loop is instructed to continue as long as i is less than or equal to our currentLevel variable. Then within the for loop, we add i to the
current score. As an example, let's assume that the player has just got a question
correct and we enter the for loop with currentLevel at 1. The player's score is still
At pass 1, we get the following:
• i = 1, so it is equal to currentLevel, which is also 1. So we enter the for loop
• i = 1, so currentScore equals 0 • We add i, which is 1, to currentScore • Our currentScore variable is now equal to 1 At pass 2, the following steps take place:
• i is incremented to 2, so it is now greater than currentLevel, which is 1 • The for loop condition evaluates to false and we continue with the code
after the for loop
• currentLevel is increased by 1 to 2
Now let's look at that for loop again assuming that the player gets the next question correct as well, and we are back in updateScoreAndLevel. This time, isCorrect has evaluated true and we enter the for loop but with a slightly different situation than the last time.
At pass 1, the following steps take place:
• i = 1, so i is less than currentLevel is 2 and we enter the for loop • i = 1, currentScore= 1
• We add i, which is equal to 1, to currentScore • Our currentScore variable is now equal to 2 At pass 2, we have the following steps happening:
• i is incremented to 2 and it is now equal to currentLevel, which is also 2 • i = 2, currentScore = 2
• We add i, which is now equal to 2, to currentScore • Our currentScore variable is now equal to 4
At pass 3, the following steps take place:
• i is incremented to 3 and it is now greater than currentLevel, which is 2. • The for loop condition evaluates to false and we continue with the code after
the for loop.
• The value of currentLevel is increased by 1 to 3. So the next time, we will have an extra pass through our for loop.
What is happening is that with each level, the player is being rewarded with another pass through the for loop, and each pass through the for loop adds a greater value to their score. To summarize what happens in the for loop, here is a brief table of values
showing how the player's score is increased based on the currentLevel variable:
currentLevel Added to currentScore currentScore after for loop
1 1 1
2 3 (1 + 2) 4
3 6 (1 + 2 + 3) 10 4 10 (1 + 2 + 3 + 4) 20 5 15 (1 + 2 + 3 + 4 + 5) 35
Of course, we could have kept it really simple and not used a for
loop. We could just use currentScore = currentScore + level
perhaps, but that doesn't offer an ever increasing reward in the same way as our current solution does and we wouldn't have been able to
practice our for loops either.
If if(isCorrect(answerGiven)) evaluates to false, it simply resets the score to 0 and the level to 1 in step 3. Step 4 then updates our TextViews for the score and the level using the variables we have just discussed.
Now we have just one more method to write. Of course, this is the isCorrect method, which we just called.