99 bottles of beer: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|C++}}: Changed to cpp tag instead of c)
m (→‎Sound: I made the second note too high)
Line 38: Line 38:
PRINT x-1; "bottles of beer on the wall"
PRINT x-1; "bottles of beer on the wall"
PRINT
PRINT
PLAY "e-8e-8e-8<b8b8b8>e-8e-8e-8e-4"'X bottles of beer on the wall
PLAY "e-8e-8e-8<b-8b-8b-8>e-8e-8e-8e-4"'X bottles of beer on the wall
PLAY "f8f8f8c8c8c8f4"'X bottles of beer
PLAY "f8f8f8c8c8c8f4"'X bottles of beer
PLAY "d4d8d8 N0 d8d8d8d4"'take one down, pass it around
PLAY "d4d8d8 N0 d8d8d8d4"'take one down, pass it around

Revision as of 03:53, 3 March 2008

99 bottles of beer is a programming puzzle. It lays out a problem which Rosetta Code users are encouraged to solve, using languages and techniques they know. Multiple approaches are not discouraged, so long as the puzzle guidelines are followed. For other Puzzles, see Category:Puzzles.

In this puzzle, write code to print out the entire "99 bottles of beer on the wall" song. For those who do not know the song, the lyrics follow this form:

X bottles of beer on the wall
X bottles of beer
Take one down, pass it around
X-1 bottles of beer on the wall

X-1 bottles of beer on the wall
...
Take one down, pass it around
0 bottles of beer on the wall

Where X and X-1 are replaced by numbers of course. Grammatical support for "1 bottle of beer" is optional. As with any puzzle, try to do it in as creative/concise/comical a way as possible (simple, obvious solutions allowed, too).

See also: http://99-bottles-of-beer.net/

Ada

<ada>with Ada.Text_Io; use Ada.Text_Io;

procedure Bottles is
begin
   for X in reverse 1..99 loop
      Put_Line(Integer'Image(X) & " bottles of beer on the wall");
      Put_Line(Integer'Image(X) & " bottles of beer");
      Put_Line("Take one down, pass it around");
      Put_Line(Integer'Image(X - 1) & " bottles of beer on the wall");
      New_Line;
   end loop;
end Bottles;</ada>

BASIC

Works with: QuickBasic version 4.5

Sound

This version plays the tune 100 times while printing out the lyrics (not synchronized). <qbasic>PLAY "<" FOR x = 99 TO 0 STEP -1

 PRINT x; "bottles of beer on the wall"
 PRINT x; "bottles of beer"
 PRINT "Take one down, pass it around"
 PRINT x-1; "bottles of beer on the wall"
 PRINT
 PLAY "e-8e-8e-8<b-8b-8b-8>e-8e-8e-8e-4"'X bottles of beer on the wall
 PLAY "f8f8f8c8c8c8f4"'X bottles of beer
 PLAY "d4d8d8 N0 d8d8d8d4"'take one down, pass it around
 PLAY "<a+8a+8a+8>c8c8d8d+8d+8d+8d+4"'X-1 bottles of beer on the wall

NEXT x</qbasic>

Text

<qbasic>FOR x = 99 TO 1 STEP -1

 PRINT x; "bottles of beer on the wall"
 PRINT x; "bottles of beer"
 PRINT "Take one down, pass it around"
 PRINT x-1; "bottles of beer on the wall"
 PRINT

NEXT x</qbasic>

C++

The simple solution

<cpp>#include<iostream> using namespace std; int main() {

  for (int x = 99; x > 0; --x) {
    cout << x << " bottles of beer on the wall" << endl;
    cout << x << " bottles of beer" << endl;
    cout << "Take one down, pass it around" << endl;
    cout << x-1 << " bottles of beer on the wall" << endl << endl;
  }

}</cpp>

An object-oriented solution

Another solution, which in addition correctly handles the grammar. This solution is object-oiented. Of course that's completely overkill for this problem, but then, some people demand that code must be OO to be good. Oh, and the used OO itself may seem bloated as well, but then, OO is all about abstraction, isn't it? Therefore this is obviously the better solution! :-)

Works with: GCC version 4.1.2 20061115 (prerelease) (SUSE Linux)

<cpp>#include <iostream>

  1. include <ostream>
  2. include <string>
  3. include <sstream>

namespace bottle_song {

 // =================================================================
 // ***********************************
 // * Abstract base class for things. *
 // ***********************************
 class thing
 {
 public:
   // return the singular of the thing
   virtual std::string singular() const = 0;
   // return the plural of the thing
   virtual std::string plural() const = 0;
   // we need a virtual destructor, too
   virtual ~thing() {}
 };
 // =================================================================
 // ***************
 // * Containers. *
 // ***************
 // Containers are things which can contain other things. The
 // following class makes any thing into a container. The container
 // class is actually a decorator which makes any thing into a
 // container. Note that the contained thing is actually mutable,
 // even if the container is not. Note that the container can only
 // contain a single thing; if it shall contain several things, make
 // it contain a collection instead.
 class container: public thing
 {
 public:
   // The format gives the name. %self% is replaced by the containing
   // object's name (in proper pluralization), %contained% is
   // replaced by the contained object's name.
   container(std::string fmt, thing const& what, thing const& contained);
   std::string singular() const;
   std::string plural() const;
 private:
   std::string format;
   thing const& self;
   thing const& contained_thing;
   // helper function to replace strings
   static void replace(std::string& str, std::string from, std::string to);
 };
 container::container(std::string fmt,
                      thing const& what,
                      thing const& contained):
   format(fmt),
   self(what),
   contained_thing(contained)
 {
 }
 std::string container::singular() const
 {
   std::string result = format;
   replace(result, "%self%", self.singular());
   replace(result, "%contained%", contained_thing.singular());
   return result;
 }
 std::string container::plural() const
 {
   std::string result = format;
   replace(result, "%self%", self.plural());
   replace(result, "%contained%", contained_thing.singular());
   return result;
 }
 void container::replace(std::string& str, std::string from, std::string to)
 {
   std::string::size_type pos = str.find(from);
   if (pos != std::string::npos)
     str.replace(pos, from.length(), to);
 }
 // =================================================================
 // *********************************
 // * A collection of equal things. *
 // *********************************
 // In the context of this program, a collection of things is again
 // considered a single thing.
 // This is a concrete class.
 class equal_collection: public thing
 {
 public:
   // constructor
   equal_collection(int count, thing const& what);
   // get singular
   std::string singular() const;
   // get plural. This has to be implemented, even if it isn't used,
   // because the inherited version is pure virtual, and not
   // implementing this would make the class abstract.
   std::string plural() const;
   // this just returns whether thwere are still things left to take away.
   bool there_is_some_left();
   // this takes one thing away from the collection. Taking a thing
   // away from an empty collection is undefined behaviour (i.e. not
   // explicitly checked).
   void take_one_away();
 private:
   int count_of_things;
   thing const& type_of_thing;
 };
 // equal_collection constructor
 equal_collection::equal_collection(int count, thing const& what):
   count_of_things(count),
   type_of_thing(what)
 {
 }
 // get singular. The singular of the collection is just the number
 // followed by the thing, proper pluralized. The fact that it's
 // grammatically still a plural form doesn't matter for the problem
 // at hand.
 std::string equal_collection::singular() const
 {
   std::ostringstream oss;
   oss << count_of_things << " ";
   if (count_of_things == 1)
     oss << type_of_thing.singular();
   else
     oss << type_of_thing.plural();
   return oss.str();
 }
 // get plural. For collections, the plural is just "times " followed
 // by the singular. That is 3 collections of 4 bottles each give 3
 // times 4 bottles.
 std::string equal_collection::plural() const
 {
   return "times " + singular();
 }
 // tell if there are still things to take away. There are things to
 // take away if there are more than 0 things.
 bool equal_collection::there_is_some_left()
 {
   return count_of_things > 0;
 }
 // take one thing away from the collection. That is, just decrement
 // the count of things.
 void equal_collection::take_one_away()
 {
   --count_of_things;
 }
 // =================================================================
 // ************
 // * The beer *
 // ************
 class beer: public thing
 {
 public:
   std::string singular() const { return "beer"; }
   std::string plural() const { return "beers"; }
 };
 // =================================================================
 // **************
 // * The bottle *
 // **************
 class bottle: public thing
 {
 public:
   std::string singular() const { return "bottle"; }
   std::string plural() const { return "bottles"; }
 };
 // =================================================================
 // ************
 // * The wall *
 // ************
 class wall: public thing
 {
 public:
   std::string singular() const { return "wall"; }
   std::string plural() const { return "walls"; }
 };
 // =================================================================
 // this is the class for the song.
 class song
 {
 public:
   song(int bottle_count);
   void sing(std::ostream& where); // note: singing the song modifies it!
 private:
   beer beverage;
   bottle drink_source;
   container bottle_of_beer;
   equal_collection collection_of_bottles;
   wall bottle_storage;
   container wall_of_bottles;
 };
 song::song(int bottle_count):
   bottle_of_beer("%self% of %contained%", drink_source, beverage),
   collection_of_bottles(bottle_count, bottle_of_beer),
   wall_of_bottles("%contained% on the %self%",
                   bottle_storage, collection_of_bottles)
 {
 }
 void song::sing(std::ostream& where)
 {
   while (collection_of_bottles.there_is_some_left())
   {
     where << wall_of_bottles.singular() << ".\n"
           << collection_of_bottles.singular() << ".\n"
           << "Take one down, pass it around.\n";
     collection_of_bottles.take_one_away();
     where << wall_of_bottles.singular() << ".\n\n";
   }
 }

}

int main() {

 bottle_song::song song(100);
 song.sing(std::cout);

}</cpp>

A template metaprogramming solution

Of course, the output of the program always looks the same. One may therefore question why the program has to do all that tedious subtracting during runtime. Couldn't the compiler just generate the code to output the text, with ready-calculated constants? Indeed, it can, and the technique is called template metaprogramming. The following short code gives the text without containing a single variable, let alone a loop:

<cpp>#include <iostream>

  1. include <ostream>

template<int max, int min> struct bottle_countdown {

 static const int middle = (min + max)/2;
 static void print()
 {
   bottle_countdown<max, middle+1>::print();
   bottle_countdown<middle, min>::print();
 }

};

template<int value> struct bottle_countdown<value, value> {

 static void print()
 {
   std::cout << value << " bottles of beer on the wall\n"
             << value << " bottles of beer\n"
             << "Take one down, pass it around\n"
             << value-1 << " bottles of beer\n\n";
 }

};

int main() {

 bottle_countdown<100, 1>::print();

}</cpp>

A preprocessor solution

Of course, with the template metaprogramming solution, the program has still do the conversion of numbers to strings at runtime, and those function calls also cost unnecessary time. Couldn't we just compose the complete text at compile time, and just output it at run time? Well, with the preprocessor, that's indeed possible:

<cpp>#include <iostream>

  1. include <ostream>
  1. define BOTTLE(nstr) nstr " bottles of beer"
  1. define WALL(nstr) BOTTLE(nstr) " on the wall"
  1. define PART1(nstr) WALL(nstr) "\n" BOTTLE(nstr) \
                   "\nTake one down, pass it around\n"
  1. define PART2(nstr) WALL(nstr) "\n\n"
  1. define MIDDLE(nstr) PART2(nstr) PART1(nstr)
  1. define SONG PART1("100") CD2 PART2("0")
  1. define CD2 CD3("9") CD3("8") CD3("7") CD3("6") CD3("5") \
       CD3("4") CD3("3") CD3("2") CD3("1") CD4("")
  1. define CD3(pre) CD4(pre) MIDDLE(pre "0")
  1. define CD4(pre) MIDDLE(pre "9") MIDDLE(pre "8") MIDDLE(pre "7") \
MIDDLE(pre "6") MIDDLE(pre "5") MIDDLE(pre "4") MIDDLE(pre "3") \
MIDDLE(pre "2") MIDDLE(pre "1")

int main() {

 std::cout << SONG;

}</cpp>

An inspection of the generated executable proves that it indeed contains the complete text of the song in one block.

Common Lisp

<lisp>(defun bottles (x)

      (format t "~a bottles of beer on the wall~%" x)
      (format t "~a bottles of beer~%" x)
      (format t "Take one down, pass it around,~%")
      (format t "~a bottles of beer on the wall~%" (- x 1))
      (if (> (- x 1) 0)

(bottles (- x 1))))</lisp>

and then just call

<lisp>(bottles 99)</lisp>

D

Uses a non-commutative operator to construct a narrative expression of 99-bottles song. <d>module nbottles ; import std.string ; import std.stdio ;

alias Exception NoMoreBottlesLeft  ;

enum { // role

 None    = 0x0, // normal for OP and Term 
 Taker   = 0x1, // for OP that minus one bottlesLeft
 Viewer  = 0x2, // for Term display bottlesLeft
 NewLine = 0x4, // for Term that sending a newline to IO

} class XP {

 static string[] ones = ["","one","two","three","four",
                         "five","six","seven","eight","nine"] ;
 static string[] tens = ["", "ten", "twenty","thirty","fourty",
                         "fifty","sixty","seventy","eighty","ninty"] ;
 static string[] teens = ["","eleven","twelve","thirteen","fourteen",
                          "fifteen","sixteen","seventeen","eighteen","nineteen"] ;
 static private int bottlesLeft = 99 ;
 static bool opCall() {
   if (bottlesLeft == 0)
     throw new NoMoreBottlesLeft("") ;
   return true ;
 }
 static string Cap(string s) {
   return toupper(s[0..1]) ~ s[1..$] ;
 }
 static string num2word(int i) {
   if (i == 0)
     return "No more" ;
 //return std.string.toString(i) ;
   string[2] digits ;    
   int numTen = i / 10 ;   
   int numOne = i % 10 ;
   if(i == 10) 
     digits[1] = tens[1] ;      
   else if(numTen == 0)
     digits[1] = ones[numOne] ;
   else if(numTen == 1)
     digits[1] = teens[numOne] ;
   else {
     digits[0] = tens[numTen] ;
     digits[1] = ones[numOne] ;
   }     
   return Cap(strip(join(digits," "))) ;
 }
 static string getBottles() {
   string num = num2word(bottlesLeft) ;
   string pural = (bottlesLeft != 1) ? "s" : "";
   return num ~ " bottle" ~ pural ;
 }
 string words ;
 int role ;
 this (string w, int r) { words = w, role = r ; }
 string getWord() {
   string postfix = " ";
   string word ;
   if (words is null)
     return "" ;
   else
     word = words ;
   if (role & Viewer)
     word = getBottles ;
   if (role & NewLine)
     postfix = "\n" ;
   return word ~ postfix ;
 }

} alias XP A_drunker_sings_a_song ;

class Term : XP {

 this (string w = null, int r = None) { super(w, r) ; }

} class OP : XP {

 this (string w = null, int r = None) { super(w, r) ; }
 OP opDiv_r(Term t) {
   if(role & Taker)
     A_drunker_sings_a_song.bottlesLeft-- ;
   writef(t.getWord) ;
   writef(getWord) ;
   return this ;         
 }
 Term opDiv(Term t) {
   writef(t.getWord) ;
   return new Term ;
 }

}

void main() {

 Term N_bottles = new Term("", Viewer) ;
 OP of = new OP("of") ;
 Term beer = new Term("beer") ;
 OP on = new OP("on") ;
 Term the_wall = new Term("the wall", NewLine) ;
 Term beer_ = new Term("beer", NewLine) ;
 Term Take = new Term("Take") ;
 OP one = new OP("one", Taker) ;
 Term down = new Term("down,") ;
 Term pass = new Term("pass") ;
 OP it = new OP("it") ;
 Term around = new Term("around", NewLine) ;
 Term the_wall_ = new Term("the wall\n", NewLine) ;
 
 try{
   for(; A_drunker_sings_a_song();
 
     N_bottles/of/beer/on/the_wall,
     N_bottles/of/beer_ ,
     Take/one/down, pass/it/around,
     N_bottles/of/beer/on/the_wall_
   ) {}
 } catch (NoMoreBottlesLeft e) {
   writefln("Go buy more beer!") ;
 }
 

}</d>

Forth

:noname   dup . ." bottles" ;
:noname       ." 1 bottle"  ;
:noname ." no more bottles" ;
create bottles , , ,

: .bottles  dup 2 min cells bottles + @ execute ;
: .beer     .bottles ."  of beer" ;
: .wall     .beer ."  on the wall" ;
: .take     ." Take one down, pass it around" ;
: .verse    .wall cr .beer cr
         1- .take cr .wall cr ;
: verses    begin cr .verse ?dup 0= until ;

99 verses

Java

Console

<java>public class Beer{

  public static void main(String[] args){
     for (int x = 99; x > 0; --x) {
        System.out.println(x + " bottles of beer on the wall");
        System.out.println(x + " bottles of beer");
        System.out.println("Take one down, pass it around");
        System.out.println((x-1) + " bottles of beer on the wall");
        System.out.println();
     }
  }

}</java>

GUI

Library: Swing
Library: AWT

This version requires user interaction. The first two lines are shown in a text area on a window. The third line is shown on a button which you need to click to see the fourth line in a message box. The numbers update and the process repeats until "0 bottles of beer on the wall" is shown in a message box, when the program ends. <java>import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JTextArea; public class Beer extends JFrame implements ActionListener{ private int x; private JButton take; private JTextArea text; public static void main(String[] args){ new Beer();//build and show the GUI }

public Beer(){ x= 99; take= new JButton("Take one down, pass it around"); text= new JTextArea(4,30);//size the area to 4 lines, 30 chars each text.setText(x + " bottles of beer on the wall\n" + x + " bottles of beer"); take.addActionListener(this);//listen to the button setLayout(new BorderLayout());//handle placement of components add(text, BorderLayout.CENTER);//put the text area in the largest section add(take, BorderLayout.SOUTH);//put the button underneath it pack();//auto-size the window setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//exit on "X" (I hate System.exit...) setVisible(true);//show it }

public void actionPerformed(ActionEvent arg0){ if(arg0.getSource() == take){//if they clicked the button --x; JOptionPane.showMessageDialog(null, x + " bottles of beer on the wall");//show a popup message text.setText(x + " bottles of beer on the wall\n" + x + " bottles of beer");//change the text } if(x == 0){//if it's the end dispose();//end } } }</java>

Python

<python>a, b, c, s = " bottles of beer", " on the wall\n", "Take one down, pass it around\n", str for i in [s(x)+a+b+s(x)+a+"\n"+c+s(x-1)+a+b for x in xrange(99, 0, -1)]: print i</python>