99 Bottles of Beer (Java)

From LiteratePrograms
Jump to: navigation, search
Other implementations: Haskell | Inform 7 | Java

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

[edit] 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).

[edit] 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

[edit] 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;

[edit] 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--;
}

[edit] 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;
}

[edit] Dealing with the Special Cases: Branching

[edit] 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";
}

[edit] 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";

[edit] 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 "";

[edit] 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);

[edit] 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
}

[edit] 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
}

[edit] 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
hijacker
hijacker
hijacker
hijacker