## Ninety-Nine Bottles Of Beer

### August 5, 2011

Somebody has to be the designated driver, so we’ll give the straight forward solution, but you should feel free to be as creative with your solution as you can. Even though it’s straight forward, the appalling badness of Scheme’s string notation is on glaring display:

```(define (beer n)   (define (upword str)     (string-append (string (char-upcase (string-ref str 0)))                    (substring str 1 (string-length str))))   (let ((n-words (upword (num->words n)))         (n1-words (upword (num->words (- n 1)))))     (if (< 1 n)         (begin           (display n-words)           (display " bottles of beer on the wall.")           (newline)           (display n-words)           (display " bottles of beer.")           (newline)           (display "Take one down and pass it around.")           (newline)           (display n1-words)           (display " bottles of beer on the wall.")           (newline)           (newline)           (beer (- n 1)))         (begin           (display "Only one bottle of beer on the wall.")           (newline)           (display "Only one bottle of beer.")           (newline)           (display "Take it down and pass it around.")           (newline)           (display "Now there's no more beer on the wall.")           (newline)))))```

To run the program, say `(beer 99)`.

We wrote the `num->words` function in a previous exercise. You can run the program at http://programmingpraxis.codepad.org/TMOKOo5n.

Pages: 1 2

### 13 Responses to “Ninety-Nine Bottles Of Beer”

1. me said

already amazingy done in every possibne way : http://99-bottles-of-beer.net/

2. Kanon said
```UNO - Universal Notation (in development)

#sing(x,y,z)
\$'{x} bottle{x|s} of beer on the wall, {x} bottle{x|s} of beer.
Take one down and pass it around, {z} bottle{y|s} of beer on the wall',x,y,z
?y=0 \$'No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.'

@99-1:i sing(i,i-1,i-1|'no more')
```

UNO is based in one simple principle: #=def, \$=print, ?=cond, @=loop is all you need to build any algorithm

3. Bogdan Popa said

Wrote this a while ago for Rosetta Code:

```#!/usr/bin/env python3
"""\
{0} {2} of beer on the wall
{0} {2} of beer
Take one down, pass it around
{1} {3} of beer on the wall
"""
print("\n".join(
__doc__.format(
i, i - 1,
"bottle" if i == 1 else "bottles",
"bottle" if i - 1 == 1 else "bottles"
) for i in range(99, 0, -1)
), end=""
```
4. ```print '\n'.join('{0} bottle{2} of beer on the wall, {0} bottle{2} of beer!\nTake one down, pass it around,\n{0} bottle{3} of beer on the wall!\n'.format(i, i - 1, i > 1 and 's' or '', i > 2 and 's' or '') for i in range(100, 0, -1))
```
5. lukaszk said

ok, sorry :)

```print '\n'.join('{0} bottle{2} of beer on the wall, {0} bottle{2} of beer!\nTake one down, pass it around,\n{1} bottle{3} of beer on the wall!\n'.format(i, i - 1, i > 1 and 's' or '', i > 2 and 's' or '') for i in xrange(99, 0, -1))
```
6. First time poster. But I’ll give it a shot.

using System;

class Program
{
static void Main(string[] args)
{
for (int number = 99; number > 0; number–)
{
int nextNumber = number – 1;
Console.WriteLine("{0} {1} of beer on the wall, {0} {1} of beer…", number, number > 1 ? "bottles":"bottle" );
Console.WriteLine("Take one down, pass it around {0} {1} of beer on the wall.", nextNumber, nextNumber != 1 ? "bottles" : "bottle");
Console.WriteLine();
}//end for
}
}

7. Try that again.

```using System;

class Program
{
static void Main(string[] args)
{
for (int number = 99; number > 0; number--)
{
int nextNumber = number - 1;
Console.WriteLine("{0} {1} of beer on the wall, {0} {1} of beer...", number, number > 1 ? "bottles":"bottle"  );
Console.WriteLine("Take one down, pass it around {0} {1} of beer on the wall.", nextNumber, nextNumber != 1 ? "bottles" : "bottle");
Console.WriteLine();
}//end for
}
}
```
8. My implementation, which uses C++ template metaprogramming with the Boost MPL library, generates the text of the song at compile time. .gist table { margin-bottom: 0; } This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters Show hidden characters #include <boost/mpl/assert.hpp> #include <boost/mpl/at.hpp> #include <boost/mpl/back_inserter.hpp> #include <boost/mpl/copy.hpp> #include <boost/mpl/divides.hpp> #include <boost/mpl/empty_sequence.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/equal_to.hpp> #include <boost/mpl/fold.hpp> #include <boost/mpl/for_each.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/joint_view.hpp> #include <boost/mpl/less.hpp> #include <boost/mpl/minus.hpp> #include <boost/mpl/modulus.hpp> #include <boost/mpl/push_back.hpp> #include <boost/mpl/range_c.hpp> #include <boost/mpl/string.hpp> #include <boost/mpl/transform.hpp> #include <boost/mpl/vector.hpp> #include <iostream> using namespace boost::mpl; template <typename n> struct NumberInEnglish { // Can't handle >= 100 BOOST_MPL_ASSERT(( less<n, int_<100> > )); typedef int_<10> ten; typedef int_<20> twenty; typedef char_<'–'> dash; typedef vector< string<>, // use Ones vector string<>, // use Teens vector string<'twen','ty'>, string<'thir','ty'>, string<'four','ty'>, string<'fift','y'>, string<'sixt','y'>, string<'seve','nty'>, string<'eigh','ty'>, string<'nine','ty'> > Tens; typedef vector< string<'no ','more'>, string<'one'>, string<'two'>, string<'thre','e'>, string<'four'>, string<'five'>, string<'six'>, string<'seve','n'>, string<'eigh','t'>, string<'nine'> > Ones; typedef vector< string<'ten'>, string<'elev','en'>, string<'twel','ve'>, string<'thir','teen'>, string<'four','teen'>, string<'fift','een'>, string<'sixt','een'>, string<'seve','ntee','n'>, string<'eigh','teen'>, string<'nine','teen'> > Teens; typedef if_< modulus<n, ten>, typename copy< joint_view< typename push_back<typename at<Tens, divides<n, ten> >::type, dash>::type, typename at<Ones, modulus<n, ten> >::type>, back_inserter<string<> > >::type, typename at<Tens, divides<n, ten> >::type > DoubleDigit; typedef typename if_< less<n, ten>, typename at<Ones, n>::type, typename if_< less<n, twenty>, typename at<Teens, minus<n, ten> >::type, typename DoubleDigit::type >::type >::type type; }; BOOST_MPL_ASSERT(( equal< NumberInEnglish<int_<4> >::type, string<'four'> > )); BOOST_MPL_ASSERT(( equal< NumberInEnglish<int_<14> >::type, string<'four','teen'> > )); BOOST_MPL_ASSERT(( equal< NumberInEnglish<int_<20> >::type, string<'twen','ty'> > )); BOOST_MPL_ASSERT(( equal< NumberInEnglish<int_<44> >::type, string<'four','ty-f','our'> > )); template <typename n> struct CountBottles { typedef string<'bott','le'> Bottle; typedef typename copy< joint_view< typename push_back< typename NumberInEnglish<n>::type, char_<' '> >::type, typename if_< equal_to<n, int_<1> >, Bottle, push_back<Bottle, char_<'s'> >::type >::type >, back_inserter<string<> > >::type type; }; BOOST_MPL_ASSERT(( equal< CountBottles<int_<0> >::type, string<'no m','ore ','bott','les'> > )); BOOST_MPL_ASSERT(( equal< CountBottles<int_<1> >::type, string<'one ','bott','le'> > )); BOOST_MPL_ASSERT(( equal< CountBottles<int_<14> >::type, string<'four','teen',' bot','tles'> > )); template <typename n> struct Verse { typedef string<'n'> NL; typedef string<',n'> CommaNL; typedef string<' of ','beer'> OfBeer; typedef string<' on ','the ','wall'> OnTheWall; typedef string<'take',' one',' dow','n, p','ass ','it a','roun','d,n'> TakeOneDownPassItAround; typedef typename transform< vector< typename CountBottles<n>::type, OfBeer, OnTheWall, CommaNL, typename CountBottles<n>::type, OfBeer, CommaNL, TakeOneDownPassItAround, typename CountBottles<typename prior<n>::type>::type, OfBeer, NL, NL >, c_str<_1> >::type strings; }; struct PrintValue { PrintValue(std::ostream& os) : os_(os) {} std::ostream& os_; template <typename T> void operator() (T t) { os_ << T::value; } }; template <typename n> std::ostream& operator<< (std::ostream& os, Verse<n> verse) { boost::mpl::for_each<typename Verse<n>::strings>(PrintValue(os)); }; struct PrintTo { PrintTo(std::ostream& os) : os_(os) {} std::ostream& os_; template <typename T> void operator() (T t) { os_ << t; } }; int main() { boost::mpl::for_each< range_c<int, 1, 100>, lambda< Verse<minus<int_<100>, _1> > >::type>( PrintTo(std::cout)); return 0; } view raw 99bob.cpp hosted with ❤ by GitHub It also generates english words instead of digits (i.e. “forty-four” instead of “44”). Not sure if that was part of the brief or not – wasn’t too hard to implement anyway.
9. Some timing… I recently wrote two versions of the “song”

http://www.emmanueloga.com/2011/07/29/drinking-contest.html

Greetings.

10. I once SSH’d into my roommate’s mac and ran this little bash script while I was at work and he was home alone.

for ((i=99; i>0 ; i–));
do
let “j = i – 1”;
say \$i bottles of beer on the wall;
say \$i bottles of beer;
say take one down ;
say pass it around;
say \$j bottles of beer on the wall;
done

Then I denied all knowledge of it, and told him the computer must have just been really bored.

11. Alex said

def song(num):
if num == 0:
print “Song is over”
elif num == 1:
print str(num) + ” bottle of beer on the wall”
else:
print str(num) + ” bottles of beer on the wall”
song(num-1)

12. Nothing particularly clever, but FWIW… In PLT Racket.

```#lang scheme
(require srfi/1) ; for iota

;;; Converts 1 to 99 into words
;;; There's a PLaneT package for this: (require (planet neil/numspell:1:2))
;;; But I whipped this up before I went to find it
;;; Turns out that Neil used the same two lists that I did
(define (number->words n)
(let ((uniques '("zero" "one" "two" "three" "four" "five" "six" "seven"
"eight" "nine" "ten" "eleven" "twelve" "thirteen"
"fourteen" "fifteen" "sixteen" "seventeen" "eighteen"
"nineteen"))
(tens '("twenty" "thirty" "fourty" "fifty" "sixty" "seventy" "eighty"
"ninety")))
(cond ((< n 20)
(list-ref uniques n))
((< n 100)
(string-append
(list-ref tens (- (quotient n 10) 2))
(let ((r (remainder n 10)))
(if (= r 0)
""
(string-append "-" (list-ref uniques r))))))
(else #f))))

;;; There's certainly a better way...didn't think too long about it
;;; Unfortunately string-titlecase doesn't do exactly what I want
(define (capitalize word)
(let-values (((head tail) (car+cdr (string->list word))))
tail))))

;;; Print the lyrics for "Ninety-nine bottles of beer"
;;; The value of fall (#t or #f) will determine the variant
(define (sing-it fall)
(for-each
(lambda (n)
(let ((n-bottles-of-beer
(string-append
(capitalize (number->words n))
" "
(if (= n 1)
"bottle"
"bottles")
" of beer")))
(unless (= n 99)
(displayln (string-append n-bottles-of-beer " on the wall!"))
(newline))
(displayln (string-append n-bottles-of-beer " on the wall!"))
(displayln (string-append n-bottles-of-beer "!"))
(if fall
(displayln "If one of those bottles should happen to fall,")
(displayln "Take one down; pass it around!"))))
(iota 99 99 -1))
(displayln "No more bottles of beer on the wall!"))

(sing-it #t)
```