99 Bottles of Beer (Java)
From LiteratePrograms
A typical verse of the 99 bottles of beer song is:
Ninety-nine bottles of beer on the wall, Ninety-nine bottles of beer! Take one down, Pass it around, Ninety-eight bottles of beer on the wall!
The last two verses (two and one bottle of beer on the wall) are special cases:
Two bottles of beer on the wall,
Two bottles of beer!
Take one down,
Pass it around,
One bottle of beer on the wall!
One bottle of beer on the wall,
One bottle of beer!
Take it down,
Pass it around,
No more bottles of beer on the wall!
Note that when we get to one bottle of beer the verse changes from the plural bottles to the singular bottle, and the final line No more bottles of beer on the wall! of the song is different from all the preceding verses.
Contents
|
The Implementation
The implementation of the solution in any imperative programming language will require the use of each of the fundamental structures from the list:
- Sequence
- Iteration
- Branching
Although not strictly necessary, the solution also provides an opportunity to use a fourth fundamental which is the subroutine (or function).
Sketch of the Solution
- When implementing a program to print the song in Java (or indeed any other language) we will use iteration to count down from 99 to 0 while using the count to provide the number in each verse. We could be clever and convert the count from a number into a string, but in this version we take the easier option of writing the verse with numbers like this:
99 bottles of beer on the wall,
99 bottles of beer!
Take one down,
Pass it around,
98 bottles of beer on the wall!
- We will define functions to generate the next verse based on the current bottles count.
- We will use branching to cope with the special cases described above
Compile-Time Constants
First we define how many bottles we want to have. For convenience, we make this a compile-time constant so that we can later use the same program to print the 10 bottles of beer song, or even the 999 bottles of beer song simply by changing one statement.
<<how many bottles?>>= private static int NUMBER_BOTTLES_OF_BEER_ON_THE_WALL = 99;
The Algorithm: Iteration
The key to the program is iteration implemented in Java as a simple loop. We could use a for loop, or the new Java 5 foreach loop, but here we'll use the standard while loop. In this loop we start a count from the number of bottles of beer on the wall down to zero, printing a verse of the song each time we iterate.
<<the main loop>>= int nBottles = NUMBER_BOTTLES_OF_BEER_ON_THE_WALL; while (nBottles > 0) { print verse nBottles--; }
Printing a Single Verse: Function
As (most of the time) the verse follows a standard pattern, it is best implemented as a function which takes the current number of bottles as an argument and returns the verse as a string.
<<return a verse for n bottles>>= /** * Return verse for N bottles of beer (where N is > 1) * @param nBottles the current number of bottles of beer on the wall. * @return verse appropriate for the number of bottles of beer on the wall. */ private String verseForNBottles(int nBottles) { validate argument String verse = nBottles + " bottles of beer on the wall,\n" + nBottles + " bottles of beer!\n" + " Take one down,\n" + " Pass it around,\n"; add the bottles that are left return verse; }
Dealing with the Special Cases: Branching
The Final Verse
The final verse (one bottle of beer on the wall) breaks the pattern of the song. If we simply called verseForNBottles(1) the verse returned would be:
1 bottles of beer on the wall,
1 bottles of beer!
Take one down,
Pass it around,
0 bottles of beer on the wall!
rather than the verse required:
1 bottle of beer on the wall,
1 bottle of beer!
Take one down,
Pass it around,
No more bottles of beer on the wall!
To avoid this we have two choices. We can add conditional code to the verseForNBottles to emit a different verse when nBottles == 1 or we can write a special function to write the final verse. Both solutions have merit, but to help the reader and avoid adding additional potentially confusing code to the verseForNBottles function, we choose the latter.
<<return the final verse>>= /** * Print final verse for one bottle of beer. * @return the final verse (one bottle of beer on the wall). */ private String finalVerse() { return "1 bottle of beer on the wall,\n" + "1 bottle of beer!\n" + " Take one down,\n" + " Pass it around,\n" + "No more bottles of beer on the wall!\n\n"; }
The Penultimate Verse
If you naively code the verseForNBottles function (as I did the first time I wrote it!) the song prints fine until you reach the penultimate verse:
2 bottles of beer on the wall,
2 bottles of beer!
Take one down,
Pass it around,
1 bottles of beer on the wall!
The penultimate verse is a special case because it goes from 2 bottles to
1 bottle. As this affects only one line of the song, we handle it with a conditional inside verseForNBottles:
<<add the bottles that are left>>= int bottlesLeft = nBottles - 1; if (bottlesLeft > 1) verse += bottlesLeft + " bottles of beer on the wall!\n\n"; else verse += "1 bottle of beer on the wall!\n\n";
Handling "Corner Cases"
Another special case is when the verse printer is called with an argument representing 0 or a negative number of bottles. This won't happen in the main loop as defined here, but to be sure that it won't become a bug later when the function verseForNBottles(nBottles) is reused in an unanticipated context (defensive programming), I'll ensure that an empty string is returned if nBottles <= 0:
<<validate argument>>= if (nBottles <= 0) return "";
Printing a Verse of the Song
With the verse generation code abstracted into functions our verse generation algorithm becomes a simple conditional:
<<choose verse>>= if (nBottles > 1) verse += verseForNBottles(nBottles); else verse += finalVerse();
To print a verse of the song, we simply take the string returned by the conditional and print it to the console (System.out):
<<print verse>>= String verse = ""; choose verse System.out.println(verse);
Print the Whole Song
To print the whole song, we simply call the main loop inside a printSong() method, like so:
<<print bottles song>>= /** * Print the 99 bottles of beer song to the console. */ public void printSong() { the main loop }
The Program
The program consists of the compile-time constants and functions defined in the solution and a main method that instantiates an object and calls the printSong method.
<<NinetyNineBottles.java>>= public class NinetyNineBottles { how many bottles? print bottles song public static void main(String[] args) { NinetyNineBottles nnb = new NinetyNineBottles(); nnb.printSong(); } //private methods return a verse for n bottles return the final verse }
Suggested Extensions and Similar Problems
An obvious extension, hinted at above, is to convert integer numbers into a string.
The 99 Bottles of Beer article gives several variations of the song. The 99 Bottles of Beer website gives 995 other programs for producing the same output as this program including this Java implementation.
A similar song popular in the UK is 10 Green Bottles which goes:
Ten green bottles Hanging on the wall Ten green bottles Hanging on the wall And if one green bottle Should accident'lly fall There'll be nine green bottles hanging on the wall.
The implementation of this in Java is left as an exercise for the reader.
| Download code |
