99 bottles of beer: Difference between revisions
No edit summary |
(drank VB) |
||
Line 1,981: | Line 1,981: | ||
99 bottles |
99 bottles |
||
=={{header|Visual Basic}}== |
|||
<lang vb>Sub Main() |
|||
Const bottlesofbeer As String = " bottles of beer" |
|||
Const onthewall As String = " on the wall" |
|||
Const takeonedown As String = "Take one down, pass it around" |
|||
Const onebeer As String = "1 bottle of beer" |
|||
Dim bottles As Long |
|||
For bottles = 99 To 3 Step -1 |
|||
Debug.Print CStr(bottles) & bottlesofbeer & onthewall |
|||
Debug.Print CStr(bottles) & bottlesofbeer |
|||
Debug.Print takeonedown |
|||
Debug.Print CStr(bottles - 1) & bottlesofbeer & onthewall |
|||
Debug.Print |
|||
Next |
|||
Debug.Print "2" & bottlesofbeer & onthewall |
|||
Debug.Print "2" & bottlesofbeer |
|||
Debug.Print takeonedown |
|||
Debug.Print onebeer & onthewall |
|||
Debug.Print |
|||
Debug.Print onebeer & onthewall |
|||
Debug.Print onebeer |
|||
Debug.Print takeonedown |
|||
Debug.Print "No more" & bottlesofbeer & onthewall |
|||
Debug.Print |
|||
Debug.Print "No" & bottlesofbeer & onthewall |
|||
Debug.Print "No" & bottlesofbeer |
|||
Debug.Print "Go to the store, buy some more" |
|||
Debug.Print "99" & bottlesofbeer & onthewall |
|||
End Sub |
|||
</lang> |
|||
=={{header|Visual Basic .NET}}== |
=={{header|Visual Basic .NET}}== |
Revision as of 20:48, 6 August 2009
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
<lang 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;
</lang>
ALGOL 68
main:( FOR bottles FROM 99 TO 1 BY -1 DO printf(($z-d" bottles of beer on the wall"l$, bottles)); printf(($z-d" bottles of beer"l$, bottles)); printf(($"Take one down, pass it around"l$)); printf(($z-d" bottles of beer on the wall"ll$, bottles-1)) OD )
AmigaE
<lang amigae>PROC main()
DEF t: PTR TO CHAR, s: PTR TO CHAR, u: PTR TO CHAR, i, x t := 'Take one down, pass it around\n' s := '\d bottle\s of beer\s\n' u := ' on the wall' FOR i := 99 TO 0 STEP -1 ForAll({x}, [u, NIL], `WriteF(s, i, IF i <> 1 THEN 's' ELSE NIL, x)) IF i > 0 THEN WriteF(t) ENDFOR
ENDPROC</lang>
APL
bob ← { (⍕⍵), ' bottle', (1=⍵)↓'s of beer'} bobw ← {(bob ⍵) , ' on the wall'} beer ← { (bobw ⍵) , ', ', (bob ⍵) , '; take one down and pass it around, ', bobw ⍵-1} ↑beer¨ ⌽(1-⎕IO)+⍳99
AutoHotkey
Delayed Sing along <lang AutoHotkey>n=99 Gui, Font, s20 cMaroon, Comic Sans MS Gui, Add, Text, w500 vLyrics, %n% bottles of beer on the wall... Gui, Show Loop {
Sleep, 2000 GuiControl,,Lyrics,% n!=1 ? n " bottles of beer.":n " bottle of beer." Sleep, 2000 GuiControl,,Lyrics,% n ? "Take one down, pass it around...":"Go to the store, buy some more..." Sleep, 2000 n := n ? --n:99 GuiControl,,Lyrics,% n!=1 ? n " bottles of beer on the wall.":n " bottle of beer on the wall." Sleep, 2000 GuiControl,,Lyrics,% n!=1 ? n " bottles of beer on the wall...":n " bottle of beer on the wall..."
} GuiClose: ExitApp</lang>
Fast and Short <lang AutoHotkey>b=99 Loop, %b% { s := b " bottles of beer on the wall, " b "bottles of beer, Take one down, pass it around " b-1 " bottles of beer on the wall" b-- TrayTip,,%s% sleep, 40 }</lang>
AWK
{ i = 99 while (i > 0) {print i, " bottles of beer on the wall," print i, " bottles of beer." print "Take one down, pass it around," i-- print i, " bottles of beer on the wall\n"}}
BASIC
Sound
This version plays the tune 100 times while printing out the lyrics (not synchronized). <lang 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 </lang>
Text
<lang 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 </lang>
C
The simple solution
<lang c>
- include <stdio.h>
int main() {
int bottles = 99; do { printf("%d bottles of beer on the wall\n", bottles); printf("%d bottles of beer\n", bottles); printf("Take one down, pass it around\n"); printf("%d bottles of beer on the wall\n\n", --bottles); } while( bottles > 0 ); return 0;
} </lang>
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:
<lang c>
- include <stdio.h>
- define BOTTLE(nstr) nstr " bottles of beer"
- define WALL(nstr) BOTTLE(nstr) " on the wall"
- define PART1(nstr) WALL(nstr) "\n" BOTTLE(nstr) \
"\nTake one down, pass it around\n"
- define PART2(nstr) WALL(nstr) "\n\n"
- define MIDDLE(nstr) PART2(nstr) PART1(nstr)
- define SONG PART1("100") CD2 PART2("0")
- define CD2 CD3("9") CD3("8") CD3("7") CD3("6") CD3("5") \
CD3("4") CD3("3") CD3("2") CD3("1") CD4("")
- define CD3(pre) CD4(pre) MIDDLE(pre "0")
- 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() {
printf(SONG); return 0;
} </lang>
An inspection of the generated executable proves that it indeed contains the complete text of the song in one block.
C++
The simple solution
<lang cpp>
- include <iostream>
using namespace std;
int main() {
int bottles = 99; do { cout << bottles << " bottles of beer on the wall" << endl; cout << bottles << " bottles of beer" << endl; cout << "Take one down, pass it around" << endl; cout << --bottles << " bottles of beer on the wall\n" << endl; } while (bottles > 0);
} </lang>
An object-oriented solution
Another solution, which in addition correctly handles the grammar. This solution is object-oriented. It is completely overkill for this problem.
<lang cpp>
- include <iostream>
- include <string>
- 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); return 0;
} </lang>
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:
<lang cpp>
- include <iostream>
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(); return 0;
} </lang>
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:
<lang cpp>
- include <iostream>
- include <ostream>
- define BOTTLE(nstr) nstr " bottles of beer"
- define WALL(nstr) BOTTLE(nstr) " on the wall"
- define PART1(nstr) WALL(nstr) "\n" BOTTLE(nstr) \
"\nTake one down, pass it around\n"
- define PART2(nstr) WALL(nstr) "\n\n"
- define MIDDLE(nstr) PART2(nstr) PART1(nstr)
- define SONG PART1("100") CD2 PART2("0")
- define CD2 CD3("9") CD3("8") CD3("7") CD3("6") CD3("5") \
CD3("4") CD3("3") CD3("2") CD3("1") CD4("")
- define CD3(pre) CD4(pre) MIDDLE(pre "0")
- 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; return 0;
} </lang>
C#
<lang csharp>using System;
class Program {
static void Main(string[] args) { for (int i = 99; i > -1; i--) { if (i == 0) { Console.WriteLine("No more bottles of beer on the wall, no more bottles of beer."); Console.WriteLine("Go to the store and buy some more, 99 bottles of beer on the wall."); break; } if (i == 1) { Console.WriteLine("1 bottle of beer on the wall, 1 bottle of beer."); Console.WriteLine("Take one down and pass it around, no more bottles of beer on the wall."); Console.WriteLine(); } else { Console.WriteLine("{0} bottles of beer on the wall, {0} bottles of beer.", i); Console.WriteLine("Take one down and pass it around, {0} bottles of beer on the wall.", i - 1); Console.WriteLine(); } } }
}</lang>
Common Lisp
<lang lisp> (defun bottles (x)
(loop for bottles from x downto 1 do (format t "~a bottle~:*~p of beer on the wall
~:*~a bottle~:*~p of beer Take one down, pass it around ~a bottle~:*~p of beer on the wall~2%" bottles (1- bottles)))) </lang> and then just call <lang lisp> (bottles 99) </lang>
D
Uses a non-commutative operator to construct a narrative expression of 99-bottles song. <lang 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!") ; }
} </lang>
E
<lang e>def bottles(n) {
return switch (n) { match ==0 { "No bottles" } match ==1 { "1 bottle" } match _ { `$n bottles` } }
} for n in (1..99).descending() {
println(`${bottles(n)} of beer on the wall,
${bottles(n)} of beer. Take one down, pass it around, ${bottles(n.previous())} of beer on the wall. `) }</lang>
Erlang
<lang erlang>-module(beersong). -export([sing/0]). -define(TEMPLATE_0, "~s of beer on the wall, ~s of beer.~nGo to the store and buy some more, 99 bottles of beer on the wall.~n"). -define(TEMPLATE_N, "~s of beer on the wall, ~s of beer.~nTake one down and pass it around, ~s of beer on the wall.~n~n").
create_verse(0) -> {0, io_lib:format(?TEMPLATE_0, phrase(0))}; create_verse(Bottle) -> {Bottle, io_lib:format(?TEMPLATE_N, phrase(Bottle))}.
phrase(0) -> ["No more bottles", "no more bottles"]; phrase(1) -> ["1 bottle", "1 bottle", "no more bottles"]; phrase(2) -> ["2 bottles", "2 bottles", "1 bottle"]; phrase(Bottle) -> lists:duplicate(2, integer_to_list(Bottle) ++ " bottles") ++ [integer_to_list(Bottle-1) ++ " bottles"].
bottles() -> lists:reverse(lists:seq(0,99)).
sing() ->
lists:foreach(fun spawn_singer/1, bottles()), sing_verse(99).
spawn_singer(Bottle) ->
Pid = self(), spawn(fun() -> Pid ! create_verse(Bottle) end).
sing_verse(Bottle) ->
receive {_, Verse} when Bottle == 0 -> io:format(Verse); {N, Verse} when Bottle == N -> io:format(Verse), sing_verse(Bottle-1) after 3000 -> io:format("Verse not received - re-starting singer~n"), spawn_singer(Bottle), sing_verse(Bottle) end.</lang>
Factor
USING: io kernel make math math.parser math.ranges sequences ; : bottle ( -- quot ) [ [ [ [ # " bottles of beer on the wall,\n" % ] [ # " bottles of beer.\n" % ] bi ] keep "Take one down, pass it around,\n" % 1- # " bottles of beer on the wall\n" % ] " " make print ] ; inline : last-verse ( -- ) "Go to the store and buy some more," "no more bottles of beer on the wall!" [ print ] bi@ ; : bottles ( n -- ) 1 [a,b] bottle each last-verse ;
! Usage: 99 bottles
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
Fortran
<lang fortran>program bottlestest
implicit none
integer :: i character(len=*), parameter :: bwall = " on the wall", & bottles = "bottles of beer", & bottle = "bottle of beer", & take = "Take one down, pass it around", & form = "(I0, ' ', A)"
do i = 99,0,-1 if ( i /= 1 ) then write (*,form) i, bottles // bwall if ( i > 0 ) write (*,form) i, bottles else write (*,form) i, bottle // bwall write (*,form) i, bottle end if if ( i > 0 ) write (*,*) take end do
end program bottlestest</lang>
F#
#light let rec bottles n = let (before, after) = match n with | 1 -> ("bottle", "bottles") | 2 -> ("bottles", "bottle") | n -> ("bottles", "bottles") printfn "%d %s of beer on the wall" n before printfn "%d %s of beer" n before printfn "Take one down, pass it around" printfn "%d %s of beer on the wall\n" (n - 1) after if n > 1 then bottles (n - 1)
Groovy
Basic Solution
With a closure to handle special cardinalities of bottles. <lang groovy>def bottles = { "${it==0 ? 'No more' : it} bottle${it==1 ? : 's' }" }
99.downto(1) { i ->
print """
${bottles(i)} of beer on the wall ${bottles(i)} of beer Take one down, pass it around ${bottles(i-1)} of beer on the wall """ }</lang>
Bottomless Beer Solution
Using more closures to create a richer lyrical experience. <lang groovy> def bottles = { "${it==0 ? 'No more' : it} bottle${it==1 ? : 's' }" }
def initialState = {
"""${result(it)}
${resultShort(it)}""" }
def act = {
it > 0 ? "Take ${it==1 ? 'it' : 'one'} down, pass it around" : "Go to the store, buy some more"
}
def delta = { it > 0 ? -1 : 99 }
def resultShort = { "${bottles(it)} of beer" }
def result = { "${resultShort(it)} on the wall" }
// //// uncomment commented lines to create endless drunken binge //// // // while (true) { 99.downto(0) { i ->
print """
${initialState(i)} ${act(i)} ${result(i+delta(i))} """ } // Thread.sleep(1000) // }</lang>
gnuplot
<lang gnuplot>if (!exists("bottles")) bottles = 99 print sprintf("%i bottles of beer on the wall", bottles) print sprintf("%i bottles of beer", bottles) print "Take one down, pass it around" bottles = bottles - 1 print sprintf("%i bottles of beer on the wall", bottles) print "" if (bottles > 0) reread</lang>
Haskell
<lang haskell> import qualified Char
main = putStr $ concat
[(up $ bob n) ++ wall ++ ", " ++ (bob n) ++ ".\n" ++ (pass n) ++ (bob $ n - 1) ++ wall ++ ".\n\n" | n <- [99, 98 .. 0]] where bob n = (num n) ++ " bottle" ++ (s n) ++ " of beer" wall = " on the wall" pass 0 = "Go to the store and buy some more, " pass _ = "Take one down and pass it around, " up (x : xs) = Char.toUpper x : xs num (-1) = "99" num 0 = "no more" num n = (show n) s 1 = "" s _ = "s"
</lang>
Another version, that uses a Writer Monad to collect each part of the song. It also uses template haskell to generate the song at compile time.
<lang haskell> {-# LANGUAGE TemplateHaskell #-} -- build with "ghc --make beer.hs" module Main where import Language.Haskell.TH import Control.Monad.Writer
-- This is calculated at compile time, and is equivalent to -- songString = "99 bottles of beer on the wall\n99 bottles..." songString =
$(let sing = tell -- we can't sing very well...
someBottles 1 = "1 bottle of beer " someBottles n = show n ++ " bottles of beer "
bottlesOfBeer n = (someBottles n ++)
verse n = do sing $ n `bottlesOfBeer` "on the wall\n" sing $ n `bottlesOfBeer` "\n" sing $ "Take one down, pass it around\n" sing $ (n - 1) `bottlesOfBeer` "on the wall\n\n"
song = execWriter $ mapM_ verse [99,98..1]
in return $ LitE $ StringL $ song)
main = putStr songString
</lang>
haXe
<lang haXe> class RosettaDemo {
static public function main() { singBottlesOfBeer(100); }
static function singBottlesOfBeer(bottles : Int) { var plural : String = 's';
while (bottles >= 1) { neko.Lib.print(bottles + " bottle" + plural + " of beer on the wall,\n"); neko.Lib.print(bottles + " bottle" + plural + " of beer!\n"); neko.Lib.print("Take one down, pass it around,\n"); if (bottles - 1 == 1) { plural = ; }
if (bottles > 1) { neko.Lib.print(bottles-1 + " bottle" + plural + " of beer on the wall!\n\n"); } else { neko.Lib.print("No more bottles of beer on the wall!\n"); } bottles--; } }
} </lang>
Io
<lang io> bottles := method(i,
if(i==0, return "no more bottles of beer") if(i==1, return "1 bottle of beer") "" .. i .. " bottles of beer"
) for(i, 99, 1, -1,
write( bottles(i), " on the wall, ", bottles(i), ",\n", "take one down, pass it around,\n", bottles(i - 1), " on the wall.\n\n" )
) </lang>
J
As posted at the J wiki
bob =: ": , ' bottle' , (1 = ]) }. 's of beer'"_ bobw=: bob , ' on the wall'"_ beer=: bobw , ', ' , bob , '; take one down and pass it around, ' , bobw@<: beer"0 >:i.-99
Java
Console
MessageFormat's choice operator is used to properly format plurals. <lang java> import java.text.MessageFormat; public class Beer{
static String bottles(int n){ return MessageFormat.format("{0,choice,0#No more bottles|1#One bottle|2#{0} bottles} of beer", n); } public static void main(String[] args){ String byob = bottles(99); for (int x = 99; x > 0;) { System.out.println(byob + " on the wall"); System.out.println(byob); System.out.println("Take one down, pass it around"); byob = bottles(--x); System.out.println(byob + " on the wall\n"); } }
} </lang>
An object-oriented solution
Another solution, which in addition correctly handles the grammar. This solution is object-oriented. It is completely overkill for this problem.
<lang java> /*************************
* Interface for things. * *************************/
interface Thing {
String singular(); String plural();
}
/***************
* 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 implements Thing {
/** 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. */ private final String format; private final Thing self; private final Thing containedThing;
public Container(String fmt, Thing what, Thing contained) { format = fmt; self = what; containedThing = contained; }
public String singular() { return format.replace("%self%", self.singular()) .replace("%contained%", containedThing.singular()); }
public String plural() { return format.replace("%self%", self.plural()) .replace("%contained%", containedThing.singular()); }
}
/*********************************
* 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 EqualCollection implements Thing {
private int countOfThings; private final Thing typeOfThing;
public EqualCollection(int count, Thing what) { countOfThings = count; typeOfThing = 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. */ public String singular() { StringBuilder sb = new StringBuilder(); sb.append(countOfThings + " "); if (countOfThings == 1) sb.append(typeOfThing.singular()); else sb.append(typeOfThing.plural()); return sb.toString(); }
/** 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. * This has to be implemented, even if it isn't used, * because the it is specified by the interface, and this * class is not abstract. */ public String plural() { 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. */ public boolean thereIsSomeLeft() { return countOfThings > 0; }
/** this takes one thing away from the collection. Taking a thing * away from an empty collection is undefined behaviour (i.e. not * explicitly checked). */ public void takeOneAway() { --countOfThings; }
}
/************
* The beer * ************/
class Beer implements Thing {
public String singular() { return "beer"; } public String plural() { return "beers"; }
}
/**************
* The bottle * **************/
class Bottle implements Thing {
public String singular() { return "bottle"; } public String plural() { return "bottles"; }
}
/************
* The wall * ************/
class Wall implements Thing {
public String singular() { return "wall"; } public String plural() { return "walls"; }
}
/** this is the class for the song. */ public class Song {
private final Thing beverage = new Beer(); private final Thing drinkSource = new Bottle(); private final Thing bottleOfBeer = new Container("%self% of %contained%", drinkSource, beverage); private final EqualCollection collectionOfBottles; private final Thing bottleStorage = new Wall(); private final Thing wallOfBottles;
public Song(int bottleCount) { collectionOfBottles = new EqualCollection(bottleCount, bottleOfBeer); wallOfBottles = new Container("%contained% on the %self%", bottleStorage, collectionOfBottles); }
public void sing(java.io.PrintStream where) { while (collectionOfBottles.thereIsSomeLeft()) { where.println(wallOfBottles.singular() + "."); where.println(collectionOfBottles.singular() + "."); where.println("Take one down, pass it around."); collectionOfBottles.takeOneAway(); where.println(wallOfBottles.singular() + "."); where.println(); } }
public static void main(String[] args) { Song song = new Song(100); song.sing(System.out); }
} </lang>
GUI
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. <lang 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"); text.setEditable(false);//so they can't change the text after it's displayed 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 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 } }
} </lang>
JavaScript
<lang javascript> // Line breaks are in HTML var beer = 99; while ( beer > 0) {
document.write( beer + " bottles of beer on the wall
" ); document.write( beer + " bottles of beer
" ); document.write( "Take one down, pass it around
" ); document.write( ( beer - 1 ) + " bottles of beer on the wall
" ); beer--;
} </lang>
Lucid
// Run luval with -s inside the lucid shell script // The print out is a list of lines. So the output is not separated by new lines, rather // by '[' and ']' -- I cant figure out how to do string concatenation with numbers in lucid. // beer(N) ^ bottle(N) ^ wall ^ beer(N) ^ bottle(N) ^ pass ^ beer(N-1) ^ bottle(N-1) ^ wall // should have worked but doesn't [%beer(N),bottle(N),wall,beer(N),bottle(N),pass,beer(N-1),bottle(N-1),wall%] where N = 100 fby N - 1; wall = if N > 0 then ` On the wall ' else eod fi; pass = `Take one down and pass it around.'; beer(A) = if A > 0 then A else `No more' fi; bottle(A) = if A eq 1 then `bottle of beer' else `bottles of beer' fi; end
M4
<lang m4>define(`BOTTLES', `bottles of beer')dnl define(`BOTTLE', `bottle of beer')dnl define(`WALL', `on the wall')dnl define(`TAKE', `take one down, pass it around')dnl define(`NINETEEN', `$1 ifelse(`$1',`1',BOTTLE,BOTTLES) WALL $1 ifelse(`$1',`1',BOTTLE,BOTTLES) ifelse(`$1',`0',,`TAKE') ifelse(`$1',`0',,`NINETEEN(eval($1-1))')')dnl NINETEEN(99)</lang>
Mathematica
<lang Mathematica> texts = ToString[#] <> " bottles of beer on the wall\n" <> ToString[#] <>
" bottles of beer\nTake one down and pass it around\n" <> ToString[# - 1] <> " bottles of beer on the wall" & /@ Range[99, 1, -1];
AppendTo[texts, "No more bottles of beer on the wall, no more bottles of beer\nGo \ to the store and buy some more, 99 bottles of beer on the wall"]; texts = StringJoin@Riffle[texts, "\n\n"]; Print@StringReplace[texts, "\n1 bottles" -> "\n1 bottle"] </lang>
MAXScript
resetMaxFile #noPrompt viewport.setType #view_top max tool maximize viewport.SetRenderLevel #smoothhighlights delay = 1.6 a = text size:30 a.wirecolor = white theMod = extrude() addModifier a theMod for i in 99 to 1 by -1 do ( a.text = (i as string + " bottles of beer on the wall") redrawViews() sleep delay a.text = (i as string + " bottles of beer") redrawViews() sleep delay a.text = "Take one down, pass it around" redrawViews() sleep delay a.text = ((i-1) as string + " bottles of beer on the wall") redrawViews() sleep delay )
A one-line version
Since MAXscript is an expression based language (everything returns a value), it is relatively easy to write long expressions that are only one line long. the following single-line snippet (broken for clarity on the webpage) produces a grammatically correct printout of the song.
for i = 99 to 1 by -1 do (print (i as string + (if i == 1 then " bottle" else " bottles") + " of beer on the wall\n" + i as string +\ (if i == 1 then " bottle" else " bottles") + " of beer\nTake one down, pass it around\n" + (i - 1) as string + (if i - 1 == 1 then "\ bottle" else " bottles") + " of beer on the wall\n" + (if i - 1 == 0 then "\nno more beer" else "")))
Make
<lang make> PRED=`expr $* - 1`
1-bottles: 1-beer pass @echo "No more bottles of beer on the wall"
%-bottles: %-beer pass @echo "$(PRED) bottles of beer on the wall\n" @-make $(PRED)-bottles
1-beer: @echo "One bottle of beer on the wall, One bottle of beer"
%-beer: @echo "$* bottles of beer on the wall, $* bottles of beer"
pass: @echo "Take one down and pass it around," </lang>
Usage
make 99-bottles
Modula-3
<lang modula3>MODULE Bottles EXPORTS Main;
IMPORT IO, Fmt;
BEGIN
FOR i := 99 TO 1 BY -1 DO IO.Put(Fmt.Int(i) & " bottles of beer on the wall\n"); IO.Put(Fmt.Int(i) & " bottles of beer\n"); IO.Put("Take one down, pass it around\n"); IO.Put(Fmt.Int(i - 1) & " bottles of beer on the wall\n"); IO.Put("\n"); END;
END Bottles.</lang>
MPIF90
<lang fortran>program bottlesMPI
implicit none
integer :: ierr,rank,nproc character(len=*), parameter :: bwall = " on the wall", & bottles = "bottles of beer", & bottle = "bottle of beer", & take = "Take one down, pass it around", & form = "(I0, ' ', A)"
call mpi_init(ierr) call mpi_comm_size(MPI_COMM_WORLD,nproc, ierr) call mpi_comm_rank(MPI_COMM_WORLD,rank,ierr)
if ( rank /= 1 ) then write (*,form) rank, bottles // bwall if ( rank > 0 ) write (*,form) rank, bottles else write (*,form) rank, bottle // bwall write (*,form) rank, bottle end if if ( rank > 0 ) write (*,*) take
call mpi_finalize(ierr)
end program bottlesMPI</lang>
Usage
mpif90 filename.f90 mpiexec -np 99 a.out
Nial
line is fork [ 0=, 'No more bottles of beer' first, 1=, 'One bottle of beer' first, link [string,' bottles of beer' first] ] verse is link [ line, ' on the wall, ' first,line, '. Take it down and pass it around, ' first, line (-1+),'on the wall. ' first ]
bottles is iterate (write verse) reverse count
OCaml
<lang ocaml> for n = 99 downto 1 do
Printf.printf "%d bottles of beer on the wall\n" n; Printf.printf "%d bottles of beer\n" n; Printf.printf "Take one down, pass it around\n"; Printf.printf "%d bottles of beer on the wall\n\n" (pred n);
done </lang>
Octave
<lang octave>function bottles(n)
bottle = "bottle"; ofbeer = "of beer"; wall = "on the wall"; for i = n:-1:0 if ( i == 1 ) s = ""; else s = "s"; endif for j = 0:1 w = wall; if ( j == 1 )
w = "";
endif printf("%d %s%s %s %s\n",\
i, bottle, s, ofbeer, w);
endfor printf("Take one down, pass it around\n"); endfor
endfunction
bottles(99);</lang>
Pascal
<lang pascal> procedure BottlesOfBeer; var
i: Integer;
begin
for i := 99 downto 1 do begin if i = 1 then begin WriteLn('1 bottle of beer on the wall'); WriteLn('1 bottle of beer'); WriteLn('Take one down, pass it around'); WriteLn('No more bottles of beer on the wall'); Exit; end; WriteLn(Format('%d bottles of beer on the wall', [i])); WriteLn(Format('%d bottles of beer', [i])); WriteLn('Take one down, pass it around'); WriteLn(Format('%d bottles of beer on the wall', [Pred(i)])); WriteLn(); end;
end; </lang>
Perl
<lang perl>
- !/usr/bin/perl -w
my $plural = 's'; foreach (reverse 1 .. 99) {
print "$_ bottle$plural of beer on the wall,\n"; print "$_ bottle$plural of beer!\n"; print "Take one down, pass it around!\n"; if ($_ - 1 == 1) { $plural = ; } if ($_ > 1) { print +($_ - 1) . " bottle$plural of beer on the wall!\n\n"; } else { print "No more bottles of beer on the wall!\n"; }
} </lang>
PHP
<lang php> <?php $plural = 's'; foreach (range(99, 1) as $i) {
echo "$i bottle$plural of beer on the wall,\n"; echo "$i bottle$plural of beer!\n"; echo "Take one down, pass it around!\n"; if ($i - 1 == 1) $plural = ; if ($i > 1) echo ($i - 1) . " bottle$plural of beer on the wall!\n\n"; else echo "No more bottles of beer on the wall!\n";
} ?> </lang>
Plain TeX
<lang tex>\obeylines \newtoks\bottle \bottle={bottle} \newtoks\ofbeer \ofbeer={of beer} \newtoks\onthewall \onthewall={on the wall} \newtoks\passit \passit={Take one down, pass it around} \def\song#1{#1 \the\bottle\ifnum#1>1\relax s\fi% \ \the\ofbeer\ \the\onthewall
- 1 \the\bottle\ifnum#1>1\relax s\fi\ \the\ofbeer
\the\passit} \newcount\bottles \bottles99 \loop\song{\number\bottles} \advance\bottles-1\ifnum\bottles>1\repeat 0 \the\bottle s \the\ofbeer\ \the\onthewall \bye</lang>
Pop11
define bootles(n); while n > 0 do printf(n, '%p bottles of beer on the wall\n'); printf(n, '%p bottles of beer\n'); printf('Take one down, pass it around\n'); n - 1 -> n; printf(n, '%p bottles of beer on the wall\n'); endwhile; enddefine; bootles(99);
Python
<lang 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 </lang> Allowing for correct grammar <lang python> def d(n): return (str(n) if n>0 else 'No more')+' bottle'+('s' if n!=1 else )+' of beer' b,c = ' on the wall\n','Take one down, pass it around\n' for x in range(99,0,-1): print d(x)+b+d(x)+'\n'+c+d(x-1)+b </lang> And for a wordy version <lang python> l1=(,'-one','-two','-three','-four','-five','-six','-seven','-eight','-nine') m2=('thir','four','fif','six','seven','eigh','nine') l2= (,,'twenty')+tuple('%sty'%j.replace('u',) for j in m2) l3=('ten','eleven','twelve')+tuple('%steen'%j for j in m2) def v(n): t,o=divmod(n,10); return l2[t]+(l1 if t-1 else l3)[o][0 if t else 1:] def d(n): return (v(n).capitalize()if n>0 else 'No more')+' bottle'+('s' if n!=1 else )+' of beer' b,c = ' on the wall\n','Take one down, pass it around\n' for x in range(99,0,-1): print d(x)+b+d(x)+'\n'+c+d(x-1)+b </lang> Normal Code
<lang python> for i in range(99,0,-1): #or range(1,100)[::-1]
print "%d bottles of beer on the wall" % i print "%d bottles of beer" % i print "Take one down, pass it around" print "%d bottles of beer on the wall" % (i-1)
</lang>
R
<lang R>bottleofbeer <- function(n) {
v <- 1 for (b in n:0) { cat(b, " bottle", ifelse(b!=1, "s", ""), " of beer on the wall\n", b, " bottle", ifelse(b!=1, "s", ""), " of beer\n", "Take one down, pass it around\n", sep="") }
}
bottleofbeer(99)</lang>
Ruby
<lang ruby>plural = 's' 99.downto(1) do |i|
puts "#{i} bottle#{plural} of beer on the wall," puts "#{i} bottle#{plural} of beer" puts "Take one down, pass it around!" plural = if i - 1 == 1 if i > 1 puts "#{i-1} bottle#{plural} of beer on the wall!" puts else puts "No more bottles of beer on the wall!" end
end</lang>
Ruby has variable traces, so we can do <lang ruby>trace_var :$bottle_num do |val|
$bottles = %Q{#{val == 0 ? 'No more' : val.to_s} bottle#{val == 1 ? : 's'}}
end
($bottle_num = 99).times do
puts "#{$bottles} of beer on the wall" puts "#{$bottles} of beer" puts "Take one down, pass it around" $bottle_num -= 1 puts "#{$bottles} of beer on the wall" puts ""
end</lang>
Scheme
<lang scheme>(define (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))))</lang>
Slate
<lang slate> n@(Integer traits) bottleVerse [| nprinted |
nprinted: n printString ; ' bottle' ; (n > 1 ifTrue: ['s'] ifFalse: []) ; ' of beer'. inform: nprinted ; ' on the wall.'. inform: nprinted. inform: 'Take one down, pass it around.'. inform: nprinted ; ' on the wall.'.
].
x@(Integer traits) bottles [
x downTo: 0 do: #bottleVerse `er
].
99 bottles. </lang>
Smalltalk
A straightforward approach:
<lang smalltalk>Smalltalk at: #sr put: 0 ; at: #s put: 0 ! sr := Dictionary new. sr at: 0 put: ' bottle' ;
at: 1 put: ' bottles' ; at: 2 put: ' of beer' ; at: 3 put: ' on the wall' ; at: 4 put: 'Take one down, pass it around' !
99 to: 0 by: -1 do: [:v | v print.
( v == 1 ) ifTrue: [ s := 0. ]
ifFalse: [ s := 1. ]. Transcript show: (sr at:s) ; show: (sr at:2) ; show: (sr at:3) ; cr. v print. Transcript show: (sr at:s) ; show: (sr at:2) ; cr. (v ~~ 0) ifTrue: [ Transcript show: (sr at:4) ; cr. ].
].</lang>
SNUSP
/=!/===========!/==+++++++++# +9 | | /=!/=====@/==@@@+@+++++# +48 (itoa) | | | | /==!/==@@@@=++++# +32 (space) | | | | | \==@@++\!+++++++++++++\!+++++\ 9 9 '9 9' space 'b' 'o' 't' $@/>@/>@/>@/>@/>========@/>============@/>====@/>++++++++++ \n setup /====================================loop=====>\!=>\!<<<<<<<< / \@\@\>cr.@\< ?\<->+++++++++>->+++++++++\ | | ! | | \===-========>=>-==BCD==!\< @\< ?/< ?/# no more beer! /=|=====|================================/ | | \<++t.<<----a.>----k.<++++e.<_.>>++++o.-n.< e.<_.>-d.>+o.>+++w.<-n.<<_.\ | | / / | | \>---a.>n.<+++d.<_.>>++p.<---a.>>----s.s.<<<_.>>-------i.>+t.<<<_.\ | | / / | | \>a.>>--r.<++++++o.>+++u.<-n.<+++d.>>>cr.<-T<+O<--B<<<# | ! \@\<<<_.>>o.-n.<<_.>>>++t.<<+++h.---e.<_.>>>+++w.<<----a.>--l.l.>>CR.<---T<+++O<+B<<<# | \9.>9.>_.>B.>O.>T.t.<---l.<+++e.>>-s.<<<_.>>+++O.<+f.<_.>----b.+++e.E.>>-R.#
Standard ML
<lang ocaml>fun bottles 0 = ()
| bottles x = ( print (Int.toString x ^ " bottles of beer on the wall\n"); print (Int.toString x ^ " bottles of beer\n"); print "Take one down, pass it around\n"; print (Int.toString (x-1) ^ " bottles of beer on the wall\n"); bottles (x-1) )</lang>
Tcl
from http://99-bottles-of-beer.net/language-tcl-439.html <lang tcl>proc bottles {i} {
return "$i bottle[expr {$i!=1?{s}:{}}] of beer"
}
proc line123 {i} {
puts "[bottles $i] on the wall," puts "[bottles $i]," puts "take one down, pass it around,"
}
proc line4 {i} {
puts "[bottles $i] on the wall.\n"
}
for {set i 99} {$i>0} {} {
line123 $i incr i -1 line4 $i
}</lang>
Here's a version that uses Tcl's variable traces to set a global "bottle string" whenever the counter variable is set. <lang tcl>proc setBottles {varName args} {
upvar #0 $varName n set ::bottles [format "%d bottle%s" $n [expr {$n == 1 ? "" : "s"}]]
}
trace add variable i write setBottles
for {set i 99} {$i > 0} {} {
puts "$bottles of beer on the wall" puts "$bottles of beer" puts "take one down, pass it around" incr i -1 puts "$bottles of beer on the wall\n"
}</lang>
The Boozy Version
A particularly entertaining version is Don Libes’s coding from the mid-'90s in Expect, which "... SIMULATES a human typing the beer song."
This is a version of that code, adapted to use modern coding styles and not require any extensions.
<lang tcl># 99 bottles of beer on the wall, Expect-style
- Author: Don Libes <libes@nist.gov>
- Adapted by: Donal K. Fellows <donal.k.fellows@manchester.ac.uk>
- Unlike programs (http://www.ionet.net/~timtroyr/funhouse/beer.html)
- which merely print out the 99 verses, this one SIMULATES a human
- typing the beer song. Like a real human, typing mistakes and timing
- becomes more erratic with each beer - the final verse is barely
- recognizable and it is really like watching a typist hunt and peck
- while drunk.
- Finally, no humans actually sing all 99 verses - particularly when
- drunk. In reality, they occasionally lose their place (or just get
- bored) and skip verses, so this program does likewise.
proc bottles {i} {
return "$i bottle[expr {$i!=1?{s}:{}}] of beer"
} proc line123 {i} {
out $i "[bottles $i] on the wall,\n" out $i "[bottles $i],\n" out $i "take one down, pass it around,\n"
} proc line4 {i} {
out $i "[bottles $i] on the wall.\n\n"
} proc out {i s} {
boozyType $i [beerifyString $i $s]
}
- Factored the code to make drunken edits to the song
proc beerifyString {i s} {
foreach ch [split $s ""] {
# don't touch punctuation; just looks too strange if you do if {[regexp {[,. \n]} $ch]} { append d $ch continue }
# keep first couple of verses straight if {$i > 97} { append d $ch continue }
# +3 prevents it from degenerating too far # /2 makes it degenerate faster though if {int(rand() * ($i/2 + 3)) > 0} { append d $ch continue }
# do something strange switch [expr {int(rand()*3)}] { 0 { # substitute another letter if {[regexp {[aeiou]} $ch]} { # if vowel, substitute another append d [string index "aeiou" \ [expr {int(5 * rand())}]] } elseif {[regexp {[0-9]} $ch]} { # if number, substitute another append d [string index "123456789" \ [expr {int(9 * rand())}]] } else { # if consonant, substitute another append d [string index "bcdfghjklmnpqrstvwxyz" \ [expr {int(21 * rand())}]] } } 1 { # duplicate a letter append d $ch$ch } 2 { # drop a letter } }
} return $d
}
- Mainly an implementation of Expect's "human" mode
proc boozyType {i s} {
### Black magic with a Weibull distribution... set alphaStd [expr {0.4 - ($i/333.0)}] set alphaEOW [expr {0.6 - ($i/333.0)}] set c [expr {1/(log($i/2.0 + 1) + 0.1)}] set tMin 0.0 set tMax [expr {6.0 - $i/20.0}]
set inWord true set first true foreach ch [split $s {}] {
### use the end-of-word alpha at eow transitions if {$inWord || [string is punct $ch] || [string is space $ch]} { set alpha $alphaEOW } else { set alpha $alphaStd } set inWord [expr {!([string is punct $ch] || [string is space $ch])}]
### Work out how long to sleep set t [expr {$alpha * pow(-log(rand()), $c)}] if {$t < $tMin} { set t $tMin } if {$t > $tMax} { set t $tMax }
### Do the sleep, skipping only if it is the first character if {$first} { set first false } else { after [expr {int($t * 1000)}] } puts -nonewline $ch
}
} fconfigure stdout -buffering none
for {set i 99} {$i>0} {} {
line123 $i incr i -1 line4 $i
# get bored and skip ahead if {$i == 92} {
set i [expr {52+int(5*rand())}]
} if {$i == 51} {
set i [expr {12+int(5*rand())}]
} if {$i == 10} {
set i [expr {6+int(3*rand())}]
}
}</lang>
UnixPipes
- Unix Pipes, avoiding all the turing complete sub programs like sed, awk,dc etc.
<lang bash> mkdir 99 || exit 1 trap "rm -rf 99" 1 2 3 4 5 6 7 8
(cd 99
mkfifo p.b1 p.b2 p.verse1 p.wall p.take yes "on the wall" > p.wall & yes "Take one down and pass it around, " > p.take & (yes "bottles of beer" | nl -s\ | head -n 99 | tac | head -n 98 ; echo "One bottle of beer"; echo "No more bottles of beer") | tee p.b1 p.b2 | paste -d"\ " - p.wall p.b1 p.take | head -n 99 > p.verse1 & cat p.b2 | tail -99 | paste -d"\ " p.verse1 - p.wall | head -n 99
) rm -rf 99 </lang>
UNIX Shell
<lang bash>#! /bin/bash
for((i=99; i >= 0; i--)); do
if $i -gt 1 || $i -eq 0 ; then
s="s"
else
s=""
fi echo "$i bottle$s of beer on the wall" if $i -ne 0 ; then
echo "$i bottle$s of beer Take one down, pass it around"
fi
done</lang>
Ursala
<lang Ursala>
- import nat
- each function takes a natural number to a block of text
quantity = # forms the plural as needed
~&iNC+ --' of beer'+ ~&?(
1?=/'1 bottle'! --' bottles'+ ~&h+ %nP, 'no more bottles'!)
verse =
^(successor,~&); ("s","n"). -[
-[quantity "s"]- on the wall, -[quantity "s"]-, Take one down and pass it around, -[quantity "n"]- on the wall.]-
refrain "n" =
-[
No more bottles of beer on the wall, -[quantity 0]-. Go to the store and buy some more, -[quantity "n"]- on the wall.]-
whole_song "n" = ~&ittt2BSSL (verse*x iota "n")--<refrain "n">
- show+
main = whole_song 99</lang>
V
[bottles [newline '' puts]. [beer [0 =] ['No more bottles of beer' put] if [1 =] ['One bottle of beer' put] if [1 >] [dup put ' bottles of beer' put] if]. [0 =] [newline] [beer ' on the wall, ' put beer newline 'Take one down and pass it around, ' put pred beer ' on the wall' puts newline] tailrec].
99 bottles
Visual Basic
<lang vb>Sub Main()
Const bottlesofbeer As String = " bottles of beer" Const onthewall As String = " on the wall" Const takeonedown As String = "Take one down, pass it around" Const onebeer As String = "1 bottle of beer"
Dim bottles As Long
For bottles = 99 To 3 Step -1 Debug.Print CStr(bottles) & bottlesofbeer & onthewall Debug.Print CStr(bottles) & bottlesofbeer Debug.Print takeonedown Debug.Print CStr(bottles - 1) & bottlesofbeer & onthewall Debug.Print Next
Debug.Print "2" & bottlesofbeer & onthewall Debug.Print "2" & bottlesofbeer Debug.Print takeonedown Debug.Print onebeer & onthewall Debug.Print
Debug.Print onebeer & onthewall Debug.Print onebeer Debug.Print takeonedown Debug.Print "No more" & bottlesofbeer & onthewall Debug.Print
Debug.Print "No" & bottlesofbeer & onthewall Debug.Print "No" & bottlesofbeer Debug.Print "Go to the store, buy some more" Debug.Print "99" & bottlesofbeer & onthewall
End Sub </lang>
Visual Basic .NET
Platform: .NET <lang vbnet>Module Module1
Sub Main() Dim Bottles As Integer For Bottles = 99 To 0 Step -1 If Bottles = 0 Then Console.WriteLine("No more bottles of beer on the wall, no more bottles of beer.") Console.WriteLine("Go to the store and buy some more, 99 bottles of beer on the wall.") Console.ReadLine() ElseIf Bottles = 1 Then Console.WriteLine(Bottles & " bottle of beer on the wall, " & Bottles & " bottle of beer.") Console.WriteLine("Take one down and pass it around, no more bottles of beer on the wall.") Console.ReadLine() Else Console.WriteLine(Bottles & " bottles of beer on the wall, " & Bottles & " bottles of beer.") Console.WriteLine("Take one down and pass it around, " & (Bottles - 1) & " bottles of beer on the wall.") Console.ReadLine() End If Next End Sub
End Module</lang>
- Programming Tasks
- Puzzles
- Ada
- ALGOL 68
- AmigaE
- APL
- AutoHotkey
- AWK
- BASIC
- C
- C++
- C sharp
- Common Lisp
- D
- E
- Erlang
- Factor
- Forth
- Fortran
- F Sharp
- Groovy
- Gnuplot
- Haskell
- HaXe
- Io
- J
- Java
- Swing
- AWT
- JavaScript
- Lucid
- M4
- Mathematica
- MAXScript
- Make
- Modula-3
- MPIF90
- Nial
- OCaml
- Octave
- Pascal
- Perl
- PHP
- PlainTeX
- Pop11
- Python
- R
- Ruby
- Scheme
- Slate
- Smalltalk
- SNUSP
- Standard ML
- Tcl
- UnixPipes
- UNIX Shell
- Ursala
- V
- Visual Basic
- Visual Basic .NET