|
home—info—exams—lectures—labs—hws
Recipe—Laws—lies—syntax—java.lang docs—java.util docs
99 bottles of rootbeer on the wall,
99 bottles of rootbeer;
take one down,
pass it around,
98 bottles of rootbeer on the wall!
98 bottles of rootbeer on the wall,
98 bottles of rootbeer;
take one down,
pass it around,
97 bottles of rootbeer on the wall!
[etc., ad nauseum]
— anonymous1
Write a function oneVerse, which takes in a number-of-bottles, and returns exactly one verse (exactly 5 lines) of that eternal classic, “99 bottles of rootbeer on the wall”.
Heads up: Make the following its own unit case, separate from the above test case. (That is, end-recording test cases after the above two, and then Create Test Method… just for this one additional call.) The reason is that our code may not pass these test cases, and we'll live with it, but we want to still be sure we're passing the other test cases.Any five-year-old can tell you that oneVerse(1) should return
Known bug: Does not quite give grammatically correct answers for 2 and 1.(You certainly know how to write correct code, but we'll leave that as an optional exercise; for this lab, it's more important to get to the next method.)
If you want to see your result formatted in a screen-specific way
on the console,
you can go to BlueJ's code pad and call the static method
System.out.println yourself,
passing it the result of calling your function.
For example, call
BlueJ Terminal Window tip: It's helpful to select the menu options Options > Unlimited buffering as well as Options > Clear screen at method call. These options are only in the menu when BlueJ's terminal window has focus2
You might wonder why we don't have our function not bother returning a String, but just print directly to the console window. That's fine, if all you ever want to do is turn console-window pixels on and off. However, by returning a String instead, our code is much more flexible: People can call our method and then use the resulting string for whatever it wants (sending it to a speech-synthesizer, writing it to System.out, writing it to a file or a web-page, or even email a single verse of the song to your parents each minute for 100 minutes). If our method hadn't returned a String, we'd be pre-emptively crippling future uses of our method.
Note: if BlueJ's progress-bar is churning away and you think your program is an infinite loop, you can right-click on the progress bar to stop it.
Write a function entireSong which takes no inputs, and returns the entire lyrics to the song. Don't repeat any code!; instead just call a method which already computes sub-answer this method wants.
Use a named-constant to represent where the song starts. For testing, change the named-constant from 99 to (say) 4. No unit tests are needed; just call your method and give the result to System.out.println.
ITEC120 does not condone underage drinking, nor in peer pressure to drink rootbeer. It would be nice to provide users with a version of our function which allows the caller to specify what sort of drink they'd like 99 bottles of. For example,
oneVerse_v2( 17, "ginger ale" ) = "17 bottles of ginger ale on the wall, 17 bottles of ginger ale; take one down, pass it around, 16 bottles of ginger ale on the wall! " |
Your task
Make “_v2” versions
all each of your three previous methods so that it they each
take a second argument (the beverage to drink).
(You'll temporarily have repeated code, as each method
will have a lot of code in common with each _v2 method.
Don't worry; we'll fix that in the following steps.)
Similarly, get rid of repeated code by gutting the old versesFromTo and completeSong, replacing their body with a single call their “_v2” cousins.
Make a named-constant to hold the default-drink (“rootbeer”, or whatever you want the default to be.) The goal: If you want to change the default drink to “lemonade”, you need only have to change one line of your program, and suddenly all three methods involving the default drink will automatically use that new value.
For each of the above functions, we have two parallel versions. A week later, it might be hard to remember which-is-which, between (say) oneVerse and oneVerse_v2.
Java actually allows us to use the same name, for these two methods! that is, instead of signatures
String oneVerse(int); String oneVerse_v2(int, String); |
String oneVerse(int); String oneVerse(int, String); |
Note that overloading is a shallow concept: If your language didn't have overloading (like Java does), you wouldn't really mind; you'd just call the methods oneVerse_v1(int) and oneVerse_v2(int,String). When other people call your method, they are fully aware of whether they are passing in one argument or two, so they are fully able to decide whether to call _v1 or _v2. However, overloading is convenient: it means people need to remember fewer method names, especially for closely-related functions.
You probably noticed this in java documentation already, that there were multiple methods with the same name. For example, class Scanner has three different methods all named hasNext, and eight different constructors (all with different signatures).
Extra-credit is individual work only. You can turn this in (or get it checked off) up through lab on Apr.18 (Wed).
Make sure your output is always grammatical (no “1 bottles”),
and yet you don't repeat data.
(That is, if the song were modified to use carafes instead of bottles,
you should only have to change one word of your program.)
Hint: I have functions verseShortLine(int),
verseLongLine(int),
and
pluralSuffixFor(int).
Your code should now finally the test cases in Step 1.
1Anonymous, and extremely annoying ↩
2You can give the terminal window focus by either (a) calling System.out.println, or (b) selecting View > Terminal. ↩
3If you really wanted no blank line after the last verse, it's a bit annoying. Approaches include: (a) Have your loop handle the first verse (if it exists) specially; then have a loop which handles all the rest (prepending a newline each time). (b) including an 'if' statement inside the loop, to check for the last verse specially; (c) adding a newline after every single verse, and then remove the last character (retroactively un-doing part of the last iteration). All three of these are aesthetically distasteful, but (a) is the least annoying. You'll have some repeated code; you can factor that out into its own method to regain a single-point-of-control. ↩
home—info—exams—lectures—labs—hws
Recipe—Laws—lies—syntax—java.lang docs—java.util docs
©2007, Ian Barland, Radford University Last modified 2007.Aug.27 (Mon) |
Please mail any suggestions (incl. typos, broken links) to ibarlandradford.edu |