Die
instances, and there's even an excuse to use an ArrayList
again! For situations where a count-controlled loop is called for, it would be good practice to start using for
loops and reserve while
for event-controlled loops. You can look back at some of the code we wrote in class for inspiration if needed. (For example, Notebook.java and DieRoller.java.)
Consider letting the less experienced member of the group do the typing if it seems like there's a mismatch in experience or comfort levels. That will help make sure they don't get left behind. Worst case, flip a coin to see who does the typing. Or have Java generate a random boolean value. (Type "(new java.util.Random()).nextBoolean()
" in the codepad without the double quotes.)
At the conclusion of the lab, make arrangements for the typer to share a copy of the code with the other member(s) of the group if desired. (E.g. email it, or put it on a shared Google drive, etc.) My solutions to the lab will get posted as well.
Die
code from class is part of this project. You won't need to make any changes to that code. All of your work will be in the LoopPractice
class. There's only one method in it at the moment, and it's broken. Take a look at the rollNTimes
method and see if you can spot the bug without running it. If it's not clear what's wrong with it, try running it and see if that helps. Fix the method and verify that it works before moving on. (You'll need to create a Die
instance on the Object Bench before you can test it, since you need to pass in a Die along with the number of times you'd like to see it rolled.)
while
loop to implement a count-controlled loop. Now that we know about for
loops, try to rewrite the method to use a for
loop instead of a while
.
averageRoll
. It takes a Die and the number of rolls to be performed, rolls the Die the specified number of times, and returns the average of the rolled values. You'll need to keep track of the number of rolls, and their sum, as you go. Both should be int
s, but you'll need to cast one as a double when doing the math on them if you want the average to be precise. Test your method on Die instances with various numbers of sides. Is the average reasonable?
roll
method, it took a bit of work to verify it was picking random numbers within the proper range. Another way to test the Die class would be to make a bunch of rolls and verify that the smallest result is a 1 and the largest corresponds to the number of sides on the Die. Finish the definition of findMinAndMax
, which takes a Die and the desired number of rolls. It should roll the Die the specified number of times, keeping track of the largest and smallest values rolled. The method should print the values after making the rolls. For example:
> Die d = new Die(); > LoopPractice loopy = new LoopPractice(); > loopy.findMinAndMax(d, 4); After 4 rolls, the min was 3 and the max was 5 > loopy.findMinAndMax(d, 200); After 200 rolls, the min was 1 and the max was 6 > d = new Die(10); > loopy.findMinAndMax(d, 200); After 200 rolls, the min was 1 and the max was 10
rollUntilExtremesFound
. It takes a Die, and keeps rolling it until it has produced both a 1 and the largest possible value. (There's a getNumSides()
method in the Die class.) When the method is finished, it should print how many rolls it took to generate both values. (Hint: One way to do this is to use a pair of boolean
variables — one that records whether you've seen a 1 and the other records whether you've seen the max value — and use them both in the boolean expression in the loop.)
> Die d = new Die(); > LoopPractice loopy = new LoopPractice(); > loopy.rollUntilExtremesFound(d); It took 29 rolls until we saw both a 1 and a 6 > d = new Die(10); > loopy.rollUntilExtremesFound(d); It took 9 rolls until we saw both a 1 and a 10
rollUntilAllValuesFound
. It takes a Die instance and rolls it until we've seen it return all possible values from 1 to the Die's number of sides. One way to do this would be to use an ArrayList
of integers to keep track of which values you've seen. On each new roll, check whether the rolled value is already in the list. If not, add it. Keep going until the list gets to the proper length. When you've found them all, print the ArrayList and the number of rolls it took. (Hint, there's a contains
method in the ArrayList class that's worth reading up on. Also, don't forget that you can just print an entire ArrayList.) Recall that you can't store primitive types in an ArrayList
, so you can't do ArrayList<int>
, but you can make a list containing instances of the Integer
wrapper class (ArrayList<Integer>
).
> Die d = new Die(); > LoopPractice loopy = new LoopPractice(); > loopy.rollUntilAllValuesFound(d); It took 17 rolls until all values were produced: [4, 6, 3, 5, 2, 1] > d = new Die(8); It took 22 rolls until all values were produced: [7, 6, 1, 5, 8, 3, 4, 2]
rollUntilDifference
. It rolls a Die instance until the difference between two successive rolls is the value specified by the user. This loop is trickier to set up than those above, since the condition in the loop needs to consider two different rolls, but on each iteration of the loop we only want to make one new roll. In my solution I used two variables, lastRoll
and currentRoll
, to hold the two most recent rolls. Each time through the loop I copy currentRoll
into lastRoll
before making a new roll. (I also used the Math.abs()
method to take the absolute value of the difference between the two.)
> Die d = new Die(); > LoopPractice loopy = new LoopPractice(); > loopy.rollUntilDifference(d,2); Rolled a 6 and then a 4 > loopy.rollUntilDifference(d,2); Rolled a 1 and then a 3
rollUntilExtremesFound
method is a little risky. If it's passed a Die instance that misbehaves, the loop could run forever! (For example, if the Die returned 0-5 rather than 1-6, we'd loop forever waiting to see a 6.) Modify the code so that it stops when we see a 1 and 6, or if we've been trying so long that it seems like we should give up.