99 Bottles of Beer

From Rosetta Code
Jump to: navigation, search
Task
99 Bottles of Beer
You are encouraged to solve this task according to the task description, using any language you may know.
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/


Contents

[edit] 0815

ATTENTION: Since 0815 output is in Hexadecimals only, the bottles count is obviously in Hexadecimals too. So if you see something like: "1E Bottles of beer..." don’t panic, everything is OK.

 
<:63:x<:20:=<:62:>=>=><:6F:x<:74:=<:6C:>=>>=><:65:x<:73:=<:20:>=>=><:6F:x<:66:=<:20:>=>=>
<:62:x<:65:=<:72:>=>>=><:20:x<:6F:=<:6E:>=>=><:20:x<:74:=<:68:>=>=><:65:x<:20:=<:77:>=>=>
<:61:x<:6C:=>=>><:54:x<:61:=<:6B:>=>=><:65:x<:20:=<:6F:>=>=><:6E:x<:65:=<:20:>=>=><:64:x
<:6F:=<:77:>=>=><:6E:x<:20:=<:61:>=>=><:6E:x<:64:=<:20:>=>=><:70:x<:61:=<:73:>=>=>><:20:x
<:69:=<:74:>=>=><:20:x<:61:=<:72:>=>=><:6F:x<:75:=<:6E:>=>=><:64:~>}:_start:{~%><:1c:~
}:_99:~{~$>=<:01:x-^:_99:<:0D:~$@:20:{~%><:10:~}:_98:~{~$>=<:01:x-^:_98:<:0D:~$@:c:<:20:~
}:_97:~{~$>=<:01:x-^:_97:<:0D:~${x<:01:x->&==<:01:-#:_322:{~%><:1c:~}:_96:~{~$>=<:01:x-
^:_96:<:d:~$$@:20:{~>&^:_start:}:_90:?<:4E:x<:6F:=<:20:>=>=><:6D:x<:6F:=<:72:>=>=><:65:x
<:20:=<:62:>=>=><:6F:x<:74:=<:6C:>=>>=><:65:x<:73:=<:20:>=>=><:6F:x<:66:=<:20:>=>=><:62:x
<:65:=<:72:>=>>=><:20:x<:6F:=<:6E:>=>=><:20:x<:74:=<:68:>=>=><:65:x<:20:=<:77:>=>=><:61:x
<:6C:=>=>><:02:~}:_70:><:23:~}:_80:~{~$>=<:01:x-^:_80:{~<:01:=-#:_60:<:0D:~$$=^:_70:}:_60:
<:0D:~$<:17:~}:_81:~{~$=<:01:x-^:_81:<:0D:~$?<:47:x<:6F:=<:20:>=>=><:74:x<:6F:=<:20:>=>=>
<:74:x<:68:=<:65:>=>=><:20:x<:73:=<:74:>=>=><:6F:x<:72:=<:65:>=>=><:20:x<:61:=<:6E:>=>=>
<:64:x<:20:=<:62:>=>=><:75:x<:79:=<:20:>=>=><:73:x<:6F:=<:6D:>=>=><:65:x<:20:=<:6D:>=>=>
<:6F:x<:72:=<:65:>=>=><:21:~}:_18:~{~$=<:01:x-^:_18:<:0D:~$<:63:x<:20:=<:62:>=>=><:6F:x
<:74:=<:6C:>=>>=><:65:x<:73:=<:20:>=>=><:6F:x<:66:=<:20:>=>=><:62:x<:65:=<:72:>=>>=><:20:
x<:6F:=<:6E:>=>=><:20:x<:74:=<:68:>=>=><:65:x<:20:=<:77:>=>=><:61:x<:6C:=>=>>{~%<:1c:~
}:_21:~{~$=<:01:x-^:_21:<:0D:~$^:end:}:_322:?<:01:x<:20:=<:62:>=>=><:6F:x<:74:=<:6C:>=>>=
><:65:x<:20:=<:6F:>=>=><:66:x<:20:=>=><:62:x<:65:=<:72:>=>>=><:20:x<:6F:=<:6E:>=>=><:20:x
<:74:=<:68:>=>=><:65:x<:20:=<:77:>=>=><:61:x<:6C:=>=>><:54:x<:61:=<:6B:>=>=><:65:x<:20:=
<:6F:>=>=><:6E:x<:65:=<:20:>=>=><:64:x<:6F:=<:77:>=>=><:6E:x<:20:=<:61:>=>=><:6E:x<:64:=
<:20:>=>=><:70:x<:61:=<:73:>=>=>><:20:x<:69:=<:74:>=>=><:20:x<:61:=<:72:>=>=><:6F:x<:75:=
<:6E:>=>=><:64:~>{~%><:1b:~}:_299:~{~$>=<:01:x-^:_299:<:0D:~$$@:20:{~%><:1b:~}:_298:~{~$>
=<:01:x-^:_298:<:0D:~$@:20:{~%<:f:~}:_297:~{~$>=<:01:x-^:_297:<:0D:~$@:c:<:20:~}:_296:~{~
$>=<:01:x-^:_296:<:0D:~${x<:01:x->&==<:01:-^:_90:
 

[edit] 6502 Assembly

IMPORTANT NOTE: This assembly language solution is targeted at the Apple 1. The Apple 1 was an innovative device for its time, but it's quite primitive by modern standards, and it had NO support for lower-case letters. Therefore, the UPPER-CASE output of this example accurately represents the only reasonable one for this device, and cannot be "fixed" due to non-compliance, only deleted.

   .CR 6502
.TF AP1BEER.O,AP1
.LF AP1BEER.LST
.OR $0BEE
;-------------------------------------;
; BEER SONG IN 6502 ASSEMBLY LANGUAGE ;
; BY BARRYM 2010-05-30  ;
; THANKS TO SBPROJECTS.COM FOR LOTS  ;
; OF VALUABLE INFORMATION AND A  ;
; VERY NICE ASSEMBLER!  ;
;-------------------------------------;
; THE TARGET MACHINE FOR THIS PROGRAM ;
; IS THE APPLE 1, BUT IT WOULD BE  ;
; EASY TO MAKE IT RUN ON OTHER 65XX ;
; MACHINES BY CHANGING THE NEXT TWO ;
; EQUATES. SOME MACHINE-TESTED  ;
; EXAMPLES:  ;
; APPLE II, +, E, C: $FDED, $80  ;
; COMMODORE 64: $FFD2, $00  ;
;-------------------------------------;
ECHO = $FFEF  ;EMIT A REG AS ASCII
ORMASK = $80  ;($00 FOR + ASCII)
;
MAXBEER = 99  ;INITIAL BEER COUNT
;-------------------------------------;
; X REG. IS THE BOTTLE COUNTER.  ;
; Y REG. IS THE STRING INDEX POINTER, ;
; AND THE TENS DIGIT IN THE BINARY- ;
; TO-ASCII CONVERSION ROUTINE.  ;
; A REG. HANDLES EVERYTHING ELSE WITH ;
; A LITTLE HELP FROM THE STACK.  ;
; ZERO PAGE ISN'T DIRECTLY DISTURBED. ;
;-------------------------------------;
; EMIT COMPLETE CORRECT SONG ADJUSTED ;
; FOR UPPER-CASE 40-COLUMN DISPLAY. ;
;-------------------------------------;
LDX #MAXBEER  ;X=MAXBEER
BNE PRSONG  ;SING THE SONG & RTS
;-------------------------------------;
; EMIT WHOLE SONG UP TO LAST SENTENCE.;
;-------------------------------------;
BEERME:
LDY #TAKE1-TXT  ;? "TAKE ... AROUND,"
JSR PRBOB  ;? X;" BOT ... WALL."
PRSONG: ;  ;?
LDY #CR-TXT  ;? X;" BOT ... WALL,"
JSR PRBOB  ;? X;" BOT ... BEER."
DEX  ;X=X-1
BPL BEERME  ;IF X>=0 THEN BEERME
;-------------------------------------;
; EMIT LAST SENTENCE AND FALL THROUGH.;
;-------------------------------------;
LDX #MAXBEER X=MAXBEER:
;  ? "GO TO ... MORE,"
;-------------------------------------;
; PRINT A PROPERLY PUNCTUATED "BOTTLE ;
; OF BEER" SENTENCE.  ;
;-------------------------------------;
PRBOB:
TYA
PHA  ;SAVE THE PRE$ PTR
JSR PUTS  ;? PRE$;
TXA  ;IF X=0 THEN
BEQ PRBOTT  ;  ? "NO MORE";
LDY #"0"-1  ;ELSE
SEC  ;(
DIV10:
SBC #10  ; Y=INT(X/10)
INY
BCS DIV10
ADC #10+'0'
CPY #"0"
BEQ ONEDIG
PHA  ; IF Y>0 THEN
TYA  ? Y;
JSR PUTCH
PLA  ;  ? X MOD 10;
ONEDIG:
LDY #BOTTL-TXT  ;)
PRBOTT:
JSR PUTCH  ;? " BOTTLE";
CPX #1
BNE PLURAL
INY  ;IF X<>1 THEN ? "S";
PLURAL:
JSR PUTS  ;? " OF BEER";
PLA  ;RECALL THE PRE$ PTR
CMP #COMCR-TXT
BEQ PRDOT
PHA  ;IF APPROPRIATE THEN
JSR PUTS  ;  ? " ON THE WALL";
PLA
LDY #COMCR-TXT  ;IF APPROPRIATE THEN
CMP #CR-TXT  ;  ? ",":
BEQ PRBOB  ;  ? X;" ... BEER";
PRDOT:
LDY #DOTCR-TXT  ;? "."
;-------------------------------------;
; EMIT A HI-BIT-SET TERMINATED STRING ;
; @ OFFSET Y AND EXIT WITH Y @ THE  ;
; BEGINNING OF THE NEXT STRING.  ;
;-------------------------------------;
PUTS:
LDA TXT,Y  ;GRAB A STRING CHAR
INY  ;ADVANCE STRING PTR
PUTCH:
PHA
ORA #ORMASK
AND #ORMASK+127 ;FORMAT CHAR FOR ECHO
JSR ECHO  ;SHOOT IT TO CONSOLE
PLA
BPL PUTS  ;LOOP IF APPROPRIATE
RTS
;-------------------------------------;
; OPTIMIZED SONG LYRIC STRINGS.  ;
;-------------------------------------;
TXT:
TAKE1:
.AS "TAKE ONE DOWN AND"
.AS " PASS IT AROUND"
COMCR:
.AS ","
CR:
.AT #13
.AS "NO MORE"
BOTTL:
.AT " BOTTLE"
.AT "S OF BEER"
.AT " ON THE WALL"
DOTCR:
.AT ".",#13
.AS "GO TO THE STORE AND"
.AT " BUY SOME MORE,",#13
.EN
;-------------------------------------;
; APPLE 1 MONITOR HEX DUMP FOLLOWS.  ;
; ENTER AS SHOWN INTO THE MONITOR,  ;
; AND LET THE BEER FLOW!!  ;
;-------------------------------------;
0BEE
:A2 63 D0 05 A0 00 20 01 0C A0 21 20 01
:0C CA 10 F3 A2 63 98 48 20 3C 0C 8A F0
:16 A0 AF 38 E9 0A C8 B0 FB 69 3A C0 B0
:F0 06 48 98 20 40 0C 68 A0 29 20 40 0C
:E0 01 D0 01 C8 20 3C 0C 68 C9 20 F0 0B
:48 20 3C 0C 68 A0 20 C9 21 F0 C7 A0 45
:B9 4C 0C C8 48 09 80 29 FF 20 EF FF 68
:10 F1 60 54 41 4B 45 20 4F 4E 45 20 44
:4F 57 4E 20 41 4E 44 20 50 41 53 53 20
:49 54 20 41 52 4F 55 4E 44 2C 8D 4E 4F
:20 4D 4F 52 45 20 42 4F 54 54 4C C5 53
:20 4F 46 20 42 45 45 D2 20 4F 4E 20 54
:48 45 20 57 41 4C CC 2E 8D 47 4F 20 54
:4F 20 54 48 45 20 53 54 4F 52 45 20 41
:4E 44 20 42 55 59 20 53 4F 4D 45 20 4D
:4F 52 45 2C 8D
BEER

[edit] 6800 Assembly

        .cr  6800
.tf beer6800.obj,AP1
.lf beer6800
;=====================================================;
; Beer Song for the Motorola 6800 microprocessor  ;
; by barrym 2011-04-19  ;
;-----------------------------------------------------;
; Prints the correct, complete song lyrics to a full  ;
; ascii terminal (console) connected to a 1970s  ;
; vintage SWTPC 6800 system, which is the target  ;
; device for this assembly.  ;
; Many thanks to:  ;
; swtpc.com for hosting Michael Holley's documents! ;
; sbprojects.com for a very nice assembler!  ;
; swtpcemu.com for a very capable emulator!  ;
; The 6800 microprocessor is the slightly older, less ;
; popular, and more expensive step-brother of the  ;
; 6502. Numerous similarities exist between the  ;
; assembly languages of the two, but the 6800 has  ;
; its own distinct flavor, which is (judging by how ;
; compact the code ended up) well suited to this  ;
; type of small program. I am especially impressed ;
; with the two-byte 'bsr' instruction, and I make  ;
; extensive use of it here.  ;
; Effort was made to keep the code footprint as small ;
; as possible by re-using substrings and code in a  ;
; hacker-like style that makes the program flow a  ;
; bit strange to the human eye (the 6800 gobbles it ;
; up without complaint). The final tally: 97 bytes ;
; of instructions, 108 bytes of text, and about 11  ;
; bytes of stack. This includes integer-to-ascii  ;
; conversion, blank line between verses, removal of ;
; "s" from "1 bottles", substitution of "no more"  ;
; for "0", and proper capitalization of "No more".  ;
; reg b is the beer counter  ;
; reg x is the string pointer  ;
; reg a handles everything else (with a little help  ;
; from the system stack)  ;
;-----------------------------------------------------;
outeee = $e1d1  ;ROM: console putchar routine
stbeer = 99  ;Must be in the range [0..99]
.or $0f00
;=====================================================;
; Initialize, sing the song, and exit  ;
;-----------------------------------------------------;
main ldab #stbeer  ;Beer count = stbeer
bsr prsong  ;Sing the entire song
swi  ;Return to the monitor.
;=====================================================;
; Emit the entire song up to the last sentence  ;
;-----------------------------------------------------;
beerme bsr prbob2  ;Emit second sentence of verse
prsong ldx #nline  ;Blank line between verses
ldaa #'N'  ;First sentence type = 'N'
bsr prbob  ;Emit 1st sentence of verse
decb  ;Beer count -= 1
bpl beerme  ;If beer count >= 0 then beerme
;=====================================================;
; Set up the last sentence and fall through to prbob2 ;
;-----------------------------------------------------;
ldab #stbeer  ;Beer count = stbeer
ldx #store  ;x$ = "Go to the store ..."
;=====================================================;
; Emit a properly punctuated bottle-of-beer sentence, ;
; using beer counter in reg b, pre-string pointer  ;
; in reg x, and the sentence type in reg a ('N' =  ;
; sentence 1, 'o' = sentence 1.5, 'n' = sentence 2) ;
;-----------------------------------------------------;
prbob2 ldaa #'n'  ;Second sentence type = 'n'
prbob psha  ;Stack sentence type for later
bsr puts  ;Emit pre-string
pula  ;Check sentence type and use
psha  ; it to prepare the upper- or
anda #'n'  ; lower-case of "no more"
ldx #omore  ;x$ = "o more bottle"
tstb  ;If beer count = 0 then
beq prbott  ; skip over the i-to-a
ldx #bottl  ;x$ = " bottle"
;=====================================================;
; I-to-A (inline): convert int in b to ascii and emit ;
; with leading zero suppression (0 <= # <= 99)!  ;
;-----------------------------------------------------;
pshb  ;Stack beer count
ldaa #-1  ; (divten trashes it)
divten subb #10  ;b = ones digit - 10
inca  ;a = tens digit
bcc divten  ;If a = 0 then
beq onedig  ; suppress leading zero
adda #"0"  ;else translate tens digit to
bsr putch  ; shifted ascii and emit
onedig addb #'0'+10  ;Translate ones digit to ascii
tba  ; and leave it in a for putch
pulb  ;Restore beer count
;-----------------------------------------------------;
prbott bsr putch  ;Emit a;x$;
cmpb #1  ;If beer count = 1
bne plural  ;then
inx  ; skip over the "s"
plural bsr puts  ;Emit " ... beer";
pula  ;Restore sentence type
cmpa #'o'  ;If type <> 'o'
beq putdot  ;then
psha  ; emit " on the wall";
bsr puts  ; if type = 'N' then loop
pula  ; back to finish the
adda #33  ; first sentence with
bpl prbob  ; type = 'o', x$ = ", "
putdot ldx #dotnl  ;x$ = ".\n"
;=====================================================;
; Emit string @ x and leave x @ start of next string  ;
;-----------------------------------------------------;
puts ldaa 0,x  ;a = raw character removed
inx  ; from the beginning of x$
;=====================================================;
; Emit a as ascii and loop into x$ if hi-bit is clear ;
;-----------------------------------------------------;
putch psha  ;Stack raw char
anda #$7f  ;Mask off the hi-bit
jsr outeee  ;Emit a as 7-bit ascii
pula  ;Restore raw char
tsta  ;If hi-bit is clear then
bpl puts  ; loop back into x$
rts  ;All 8 'bsr's use this 'rts'!
;=====================================================;
; Optimized song lyric strings, carefully arranged to ;
; allow the prbob subroutine to take full advantage ;
; of the x register side-effects of puts  ;
;-----------------------------------------------------;
omore .as "o more"
bottl .at " bottle"
.at "s of beer"
.at " on the wall"
.at ", "
dotnl .as "."
nline .at #13,#10
.at "Take one down and pass it around, "
store .at "Go to the store and buy some more, "
.en
;=====================================================;
; The following is a hex dump of the object file,  ;
; suitable for copying and pasting into the 6800  ;
; emulator available at swtpcemu.com!  ;
;-----------------------------------------------------;
e0F00 C6 63 8D 03 3F 8D 0F CE 0F 86 86 4E 8D 0A 5A 2A
e0F10 F4 C6 63 CE 0F AA 86 6E 36 8D 38 32 36 84 6E CE
e0F20 0F 61 5D 27 15 CE 0F 67 37 86 FF C0 0A 4C 24 FB
e0F30 27 04 8B B0 8D 20 17 8B 3A 33 8D 1A C1 01 26 01
e0F40 08 8D 10 32 81 6F 27 08 36 8D 08 32 8B 21 2A C8
e0F50 CE 0F 85 A6 00 08 36 84 7F BD E1 D1 32 4D 2A F3
e0F60 39 6F 20 6D 6F 72 65 20 62 6F 74 74 6C E5 73 20
e0F70 6F 66 20 62 65 65 F2 20 6F 6E 20 74 68 65 20 77
e0F80 61 6C EC 2C A0 2E 0D 8A 54 61 6B 65 20 6F 6E 65
e0F90 20 64 6F 77 6E 20 61 6E 64 20 70 61 73 73 20 69
e0FA0 74 20 61 72 6F 75 6E 64 2C A0 47 6F 20 74 6F 20
e0FB0 74 68 65 20 73 74 6F 72 65 20 61 6E 64 20 62 75
e0FC0 79 20 73 6F 6D 65 20 6D 6F 72 65 2C A0
j0F00

[edit] ABAP

REPORT z99bottles.
 
DATA lv_no_bottles(2) TYPE n VALUE 99.
 
DO lv_no_bottles TIMES.
WRITE lv_no_bottles NO-ZERO.
WRITE ' bottles of beer on the wall'.
NEW-LINE.
WRITE lv_no_bottles NO-ZERO.
WRITE ' bottles of beer'.
NEW-LINE.
WRITE 'Take one down, pass it around'.
NEW-LINE.
SUBTRACT 1 FROM lv_no_bottles.
WRITE lv_no_bottles NO-ZERO.
WRITE ' bottles of beer on the wall'.
WRITE /.
ENDDO.

[edit] ACL2

(defun bottles-of-beer (n)
(if (zp n)
nil
(prog2$ (cw (concatenate 'string
"~%"
"~N0 bottle~#1~[~/s~] of beer on the wall,~%"
"~n0 bottle~#1~[~/s~] of beer.~%"
"Take one down, pass it around,~%"
"~n2 bottle~#3~[~/s~] of beer on the wall.~%")
n
(if (= n 1) 0 1)
(1- n)
(if (= n 2) 0 1))
(bottles-of-beer (- n 1)))))

[edit] ActionScript

for(var numBottles:uint = 99; numBottles > 0; numBottles--)
{
trace(numBottles, " bottles of beer on the wall");
trace(numBottles, " bottles of beer");
trace("Take one down, pass it around");
trace(numBottles - 1, " bottles of beer on the wall\n");
}

[edit] Ada

[edit] Simple version

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;

[edit] Concurrent version

with 1 task to print out the information and 99 tasks to specify the number of bottles

with Ada.Text_Io; use Ada.Text_Io;
 
procedure Tasking_99_Bottles is
subtype Num_Bottles is Natural range 1..99;
task Print is
entry Set (Num_Bottles);
end Print;
task body Print is
Num : Natural;
begin
for I in reverse Num_Bottles'range loop
select
accept
Set(I) do -- Rendezvous with Counter task I
Num := I;
end Set;
Put_Line(Integer'Image(Num) & " bottles of beer on the wall");
Put_Line(Integer'Image(Num) & " bottles of beer");
Put_Line("Take one down, pass it around");
Put_Line(Integer'Image(Num - 1) & " bottles of beer on the wall");
New_Line;
or terminate; -- end when all Counter tasks have completed
end select;
end loop;
end Print;
task type Counter(I : Num_Bottles);
task body Counter is
begin
Print.Set(I);
end Counter;
type Task_Access is access Counter;
 
Task_List : array(Num_Bottles) of Task_Access;
 
begin
for I in Task_List'range loop -- Create 99 Counter tasks
Task_List(I) := new Counter(I);
end loop;
end Tasking_99_Bottles;

[edit] Aime

integer
main(void)
{
cardinal bottles;
 
bottles = 99;
 
do {
o_cardinal(bottles);
o_text(" bottles of beer on the wall\n");
o_cardinal(bottles);
o_text(" bottles of beer\n");
o_text("Take one down, pass it around\n");
bottles -= 1;
o_cardinal(bottles);
o_text(" bottles of beer on the wall\n\n");
} while (bottles);
 
return 0;
}

[edit] ALGOL 68

Works with: ALGOL 68 version Standard - no extensions to language used
Works with: ALGOL 68G version Any - tested with release mk15-0.8b.fc9.i386
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
)

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

[edit] Apache Ant

Implementation in Apache Ant, due to the limitations of Ant, this requires ant-contrib for arithmetic operations and a dummy target to keep Ant from detecting the loop.

<?xml version="1.0"?>
<project name="n bottles" default="99_bottles">
 
<!-- ant-contrib.sourceforge.net for arithmetic and if -->
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
 
<!-- start count of bottles, you can set this with
e.g. ant -f 99.xml -Dcount=10 -->
<property name="count" value="99"/>
 
<target name="99_bottles">
<antcall target="bottle">
<param name="number" value="${count}"/>
</antcall>
</target>
 
<target name="bottle">
<echo message="${number} bottles of beer on the wall"/>
<echo message="${number} bottles of beer"/>
<echo message="Take one down, pass it around"/>
 
<math result="result" operand1="${number}" operation="-" operand2="1" datatype="int"/>
 
<echo message="${result} bottles of beer on the wall"/>
 
<if>
<not><equals arg1="${result}" arg2="0" /></not>
<then>
<antcall target="bottleiterate">
<param name="number" value="${result}"/>
</antcall>
</then>
</if>
</target>
 
<target name="bottleiterate">
<antcall target="bottle">
<param name="number" value="${number}"/>
</antcall>
</target>
 
</project>

[edit] APL

Works with: Dyalog APL
Translation of: J
     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

[edit] App Inventor

[edit] Using a 'for each <number>' block (simplest)

Note that the output label text is not displayed until the entire lyrics text has been built and there is some delay between button press and display. <CLICK HERE TO VIEW THE BLOCKS AND OUTPUT>

[edit] Using a Clock Timer block (preferrred)

Output can be sent directly to a label with this preferred method as there is no noticeable delay between button press and output. <CLICK HERE TO VIEW THE BLOCKS AND OUTPUT>

[edit] AppleScript

repeat with beerCount from 99 to 1 by -1
set bottles to "bottles"
if beerCount < 99 then
if beerCount = 1 then
set bottles to "bottle"
end
log "" & beerCount & " " & bottles & " of beer on the wall"
log ""
end
log "" & beerCount & " " & bottles & " of beer on the wall"
log "" & beerCount & " " & bottles & " of beer"
log "Take one down, pass it around"
end
log "No more bottles of beer on the wall!"

[edit] Arbre

 
bottle(x):
template: '
$x bottles of beer on the wall.
$x bottles of beer.
Take one down and pass it around,
$y bottles of beer on the wall.
'
 
if x==0
template~{x: 'No more', y: 'No more'}
else
if x==1
template~{x: x, y: 'No more'}
else
template~{x: x, y: x-1}
 
bottles(n):
for x in [n..0]
bottle(x)
 
99bottles():
bottles(99) -> io
 
 


[edit] Argile

use std
 
let X be an int
for each X from 99 down to 1
prints X bottles of beer on the wall
prints X bottles of beer
prints "Take one down, pass it" around
if X == 1
echo No more "beer." Call da "amber lamps"
break
X--
prints X bottles of beer on the wall "\n"
X++
.:around :. -> text {X>59 ? "around", "to me"}
.:bottles:. -> text {X> 5 ? "bottles", (X>1 ? "buttles", "wall")}
.:of beer:. -> text {X>11 ? "of beer", "ov beeer"}
.:on the wall:. -> text {
X>17 ? "on the wall", (X>1 ? "on the bwall", "in the buttle")
}

[edit] ATS

//
#include
"share/atspre_staload.hats"
//
(* ****** ****** *)
 
fun bottles
(n0: int): void = let
//
fun loop (n: int): void =
(
if n > 0 then
(
if n0 > n then println! ();
println! (n, " bottles of beer on the wall");
println! (n, " bottles of beer");
println! ("Take one down, pass it around");
println! (n-1, " bottles of beer on the wall");
loop (n - 1)
) (* end of [if] *)
)
//
in
loop (n0)
end // end of [bottles]
 
(* ****** ****** *)
 
implement main0 () = bottles (99)

[edit] AutoHotkey

; RC: 99 bottles of beer
b = 99
Loop, %b% {
s .= b . " bottles of beer on the wall,`n"
. b . " bottles of beer.`nTake one down, pass it around,`n"
. b-1 . " bottles of beer on the wall.`n`n"
b--
}
Gui, Add, Edit, w200 h200, %s%
Gui, Show, , 99 bottles of beer
Return ; end of auto-execute section
 
GuiClose:
ExitApp
Return

Delayed Sing along

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

Fast and Short

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
}

With a GUI and slight grammatical variation:

N=o more
Z=99
L:=Z M:=(B:=" bottle")"s"
Loop 99
V.=L (W:=(O:=" of beer")" on the wall")",`n"L O ",`nTake one down and pass it around,`n"(L:=(--Z ? Z:"N"N)(Z=1 ? B:M))W ".`n`n"
Gui,Add,Edit,w600 h250,% V L W ", n"N M O ".`nGo to the store and buy some more, 99"M W "."
Gui,Show
Return
GuiClose:
ExitApp

[edit] AutoIt

 
 
 
local $bottleNo=99
local $lyrics=" "
 
While $bottleNo<>0
If $bottleNo=1 Then
$lyrics&=$bottleNo & " bottles of beer on the wall" & @CRLF
$lyrics&=$bottleNo & " bottles of beer" & @CRLF
$lyrics&="Take one down, pass it around" & @CRLF
Else
$lyrics&=$bottleNo & " bottles of beer on the wall" & @CRLF
$lyrics&=$bottleNo & " bottles of beer" & @CRLF
$lyrics&="Take one down, pass it around" & @CRLF
EndIf
If $bottleNo=1 Then
$lyrics&=$bottleNo-1 & " bottle of beer" & @CRLF
Else
$lyrics&=$bottleNo-1 & " bottles of beer" & @CRLF
EndIf
$bottleNo-=1
WEnd
MsgBox(1,"99",$lyrics)
 

Easier to read output to Console

 
$bottles = 99
$lyrics1 = " bottles of beer on the wall. "
$lyrics2 = " bottles of beer. Take one down and pass it around. "
 
For $i = $bottles To 1 Step -1
If $i = 1 Then
$lyrics1 = " bottle of beer on the wall. "
$lyrics2 = " bottle of beer. Take one down and pass it around. "
$lyrics3 = " Go to the store and get some more! No bottles of beer on the wall!"
ConsoleWrite($bottles & $lyrics1 & $bottles & $lyrics2 & $lyrics3 & @CRLF)
Else
ConsoleWrite($bottles & $lyrics1 & $bottles & $lyrics2 & $bottles - 1 & $lyrics1 & @CRLF)
$bottles -= 1
EndIf
Next
 

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

[edit] Babel

main: { 99 bottles }
 
bottles!:
{ x set
{ bw
bx cr <<
"Take one down, pass it around\n" <<
1 x -=
bw "\n" << }
x times }
 
b  : " bottles of beer"
bx!: { x %d << b }
w  : " on the wall"
bw!: { bx w . cr << }
 
x: [0]

[edit] BASIC

[edit]
Works with: QuickBASIC version 4.5

[edit] Sound

This version plays the tune 100 times while printing out the lyrics (not synchronized).

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

[edit] Text

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

[edit] Applesoft BASIC

 
10 HOME
20 FOR B=99 TO 1 STEP -1
30 PRINT B;" BOTTLE OF BEER ON THE WALL"
40 PRINT B;" BOTTLE OF BEER ON THE WALL"
50 PRINT "TAKE ONE DOWN, PASS IT AROUND"
60 PRINT B-1;" BOTTLE OF BEER ON THE WALL"
70 NEXT B
 

[edit] BASIC256

#length of querter and eight note in ms
n4 = 1000 * 60 / 80 / 4
n8 = n4 / 2
 
#frequency of musical notes in hz
e = 330
ef = 311
b = 247
bf = 233
f = 349
c = 262
d = 294
ds = 311
a = 220
 
dim notes(1)
dim lengs(1)
 
# redim is automatic when using a {} list to assign an array
notes = {ef, ef, ef, bf, bf, bf, ef, ef, ef, ef, f , f , f , c , c , c , f , d , d , d , d , d , d , d , bf, bf, bf, c , c , ef, ef, ef, ef, ef}
lengs = {n8, n8, n8, n8, n8, n8, n8, n8, n8, n4, n8, n8, n8, n8, n8, n8, n4, n4, n8, n8, n8, n8, n8, n4, n8, n8, n8, n8, n8, n8, n8, n8, n8, n4 }
 
for x = 99 to 1 step -1
for t = 0 to notes[?]-1
if t = 0 then print x + " bottles of beer on the wall"
if t = 11 then print x + " bottles of beer"
if t = 18 then print "Take one down, pass it around"
if t = 25 then print(x-1) + " bottles of beer on the wall"
sound notes[t], lengs[t]
pause .002
next t
print
next x
 

[edit] BBC BASIC

 
N_Bottles = 99
 
beer$ = " of beer"
wall$ = " on the wall"
unit$ = "99 bottles"
 
WHILE N_Bottles >= 0
 
IF N_Bottles=0 THEN
PRINT '"No more bottles" beer$ wall$ ", " unit$ beer$ "."
PRINT "Go to the store and buy some more, ";
ELSE
PRINT 'unit$ beer$ wall$ ", " unit$ beer$ "."
PRINT "Take one down and pass it around, ";
ENDIF
 
N_Bottles -= 1
 
CASE N_Bottles OF
WHEN 0:
unit$ = "no more bottles"
WHEN 1:
unit$ = "1 bottle"
OTHERWISE:
unit$ = STR$((N_Bottles + 100) MOD 100) + " bottles"
ENDCASE
 
PRINT unit$ beer$ wall$ "."
 
ENDWHILE
 
END
 

[edit] Creative Basic

[edit] window version

DEF Win:WINDOW
DEF Close:CHAR
DEF ScreenSizeX,ScreenSizeY:INT
 
DECLARE VSpace(Number:UINT)
DECLARE CLR()
 
DEF TheLine$[4],Number$,Erase:STRING
DEF TheLine,TextHeight,TextWidth:INT
DEF TextX,TextY:UINT
 
TheLine$[0]="bottles"
TheLine$[1]="of beer on the wall."
TheLine$[2]="of beer."
TheLine$[3]="Take one down, pass it around."
 
BottlesOfBeer=99
TheLine=1
 
GETSCREENSIZE(ScreenSizeX,ScreenSizeY)
 
WINDOW Win,0,0,ScreenSizeX,ScreenSizeY,@MINBOX|@MAXBOX|@SIZE,0,"99 Bottles Of Beer",MainHandler
 
GETTEXTSIZE(Win,TheLine$[3],TextWidth,TextHeight)
 
Erase$=STRING$(TextWidth," ")
 
PRINT Win,"Let's sing a song."
 
VSpace(2)
 
'1.2 seconds.
STARTTIMER Win,1200
 
GOSUB Sing
 
WAITUNTIL Close=1
 
CLOSEWINDOW Win
 
END
 
SUB MainHandler
 
SELECT @CLASS
 
CASE @IDCLOSEWINDOW
 
Close=1
 
CASE @IDTIMER
 
GOSUB Sing
 
ENDSELECT
 
RETURN
 
SUB Sing
 
DEF Sing:INT
 
Sing=TheLine
 
MOVE Win,TextX,TextY
 
Number$=STR$(BottlesOfBeer)
 
IF BottlesOfBeer=0
 
Number$="No more"
TheLine$[0]="bottles"
TheLine$[3]="Go to the store and buy some more."
 
ENDIF
 
IF BottlesOfBeer=1
 
TheLine$[0]="bottle"
TheLine$[3]="Take it down, pass it around."
 
ENDIF
 
IF TheLine=4 THEN Sing=1
 
IF (TheLine=1)|(TheLine=2)|(TheLine=4)
 
IF BottlesOfBeer>-1 THEN PRINT Win,Number$+" "+TheLine$[0]+" "+TheLine$[Sing] ELSE GOSUB TheEnd
 
ELSE
 
PRINT Win,TheLine$[3]
 
BottlesOfBeer=BottlesOfBeer-1
 
ENDIF
 
TheLine=TheLine+1
 
VSpace(1)
 
IF TheLine>4
 
TheLine=1
 
VSpace(1)
 
ENDIF
 
RETURN
 
SUB TheEnd
 
PRINT Win,"What's the problem, offishur?"
 
STOPTIMER Win
 
VSpace(2)
 
MOVE Win,TextX,TextY:PRINT Win,"That's all."
 
RETURN
 
SUB VSpace(Number:UINT)
 
TextY=TextY+(TextHeight*Number)
 
IF TextY+(TextHeight*8)>ScreenSizeY THEN CLR()
 
RETURN
 
SUB CLR()
 
FOR X=0 TO ScreenSizeY
 
MOVE Win,0,X:PRINT Win,Erase$
 
TextY=8
 
NEXT X
 
RETURN
 

[edit] console only version

Rather quickly written and dirty.

REM Using the ESC key to exit will not work in console programs under Windows 95/98 or ME.
 
DECLARE SingWallLn()
DECLARE Delay1()
DECLARE Delay2()
'To use ESC Key to exit.
DECLARE Quit()
DECLARE TheEnd()
 
DEF Bottles:UINT
DEF Number$,Again$:STRING
 
OPENCONSOLE
 
PRINT"I'm going to sing a song.":PRINT
 
Delay1()
 
LABEL StartSong
 
Bottles=99
 
DO
Quit()
 
SingWallLn():Delay1()
 
PRINT LTRIM$(STR$(Bottles))+Number$+" of beer.":Delay1()
 
IF Bottles>0 THEN PRINT"Take one down, pass it around." ELSE PRINT"Take it down, pass it around.":Delay1()
 
Bottles=Bottles-1
 
SingWallLn()
 
Delay2()
 
PRINT:PRINT
 
UNTIL Bottles=0
 
Delay2()
 
ClS
 
LABEL Question
 
INPUT"Sing it again (y or n)?",Again$
 
SELECT Again$
 
CASE("y")
CASE("Y")
 
CLS
 
GOTO StartSong
 
CASE "n"
CASE "N"
 
CLS
 
PRINT"Fine, be that way.":Delay2()
 
TheEnd()
 
ENDSELECT
 
PRINT"Sorry, I didn't understand.":PRINT
 
GOTO Question
 
'Keep from running into subroutines.
END
 
SUB SingWallLn()
 
IF Bottles=1 THEN Number$=" bottle" ELSE Number$=" bottles"
 
PRINT LTRIM$(STR$(Bottles))+Number$+" of beer on the wall."
 
RETURN
 
SUB Delay1()
 
FOR X=1 TO 7000:NEXT X
 
RETURN
 
SUB Delay2()
 
FOR X=1 TO 1750000:NEXT X
 
RETURN
 
SUB Quit()
 
'Close program by pressing the ESC key.
'Will not work in console under Windows 95/98 or ME.
IF GETKEYSTATE(0x1B) THEN TheEnd()
 
RETURN
 
SUB TheEnd()
 
CLOSECONSOLE
 
END
 
RETURN
 

[edit] FBSL

This is a OO version, using FBSL v3.5 Beta

#AppType Console
 
Class Wall
bottles
 
SUB Initialize(%n = 99)
bottles = n
END SUB
 
Method Denom()
IF bottles+1 > 1 THEN
RETURN "one"
ELSEIF bottles+1 = 1 THEN
RETURN "it"
END IF
END Method
 
Method StockUp( %n = 99 )
bottles = n
END Method
 
Method TakeOneDown()
bottles = bottles - 1
END Method
 
Method Pluraliser()
IF bottles > 1 THEN
RETURN "s"
ELSE
RETURN ""
END IF
END method
 
Method Sing()
PRINT bottles, " bottle", Pluraliser(), " of beer on the wall"
PRINT bottles, " bottle", Pluraliser(), " of beer"
TakeOneDown()
PRINT "take ", Denom(), " down and pass it round"
IF bottles > 0 THEN
PRINT bottles, " bottle", Pluraliser(), " of beer on the wall"
PRINT
ELSE
PRINT "no more bottles of beer on the wall"
PRINT
PRINT "no more bottles of beer on the wall"
PRINT "no more bottles of beer on the wall"
PRINT "go to the store and buy some more"
StockUp(99)
PRINT bottles, " bottle", Pluraliser(), " of beer on the wall"
PRINT
END IF
RETURN bottles
END Method
 
END Class
 
DIM BeerSong AS new Wall(99)
 
WHILE BeerSong.Sing() <> 99
END WHILE
 

[edit] Integer BASIC

IMPORTANT NOTE: Integer BASIC was written (and hand-assembled by Woz himself) for the Apple 1 and original Apple 2. The Apple 1 has NO support for lower-case letters, and it was an expensive (and later) option on the Apple 2. The UPPER-CASE output of this example accurately represents the only reasonable solution for those target devices, and therefore cannot be "fixed" for mixed case, only deleted.

E000G (APPLE II)
E000R (APPLE I)
10 REM -------------------------
11 REM BEERSONG IN APPLE INTEGER
12 REM BASIC BY BARRYM 2011-8-21
13 REM THANKS : APPLEWIN1.17.2.0
14 REM THANKS ALSO : POM1 0.7B
15 REM -------------------------
16 REM PRINTS THE COMPLETE UPPER
17 REM CASE LYRICS ON AN APPLE I
18 REM OR AN 'ORIGINAL' APPLE II
19 REM WITH WOZ'S INTEGER BASIC.
20 REM -------------------------
21 REM THIS BASIC HAS AN UNUSUAL
22 REM 'THEN', WHICH EXECUTES OR
23 REM SKIPS ONE (AND ONLY ONE!)
24 REM STATEMENT. THIS CONFUSED
25 REM US KIDS REGULARLY WHEN WE
26 REM TRIED TRANSLATING INTEGER
27 REM BASIC GAMES TO APPLE$OFT!
30 REM -------------------------
40 FOR B=99 TO 98 STEP 0: PRINT : FOR W=0 TO 2: IF W<2 THEN 70
50 IF B THEN PRINT "TAKE ONE DOWN AND PASS IT AROUND";:B=B-1
60 IF B+1 THEN 70:B=99: PRINT "GO TO THE STORE AND BUY SOME MORE";
70 IF W THEN PRINT ",": IF B THEN PRINT B;: IF B=0 THEN PRINT "NO MORE";
80 PRINT " BOTTLE";: IF B#1 THEN PRINT "S";: PRINT " OF BEER";
90 IF W#1 THEN PRINT " ON THE WALL";: IF W THEN PRINT ".": NEXT W,B: END
RUN

[edit] Liberty BASIC

For bottles = 99 To 1 Step -1
song$ = song$ + str$(bottles) + " bottle"
If (bottles > 1) Then song$ = song$ + "s"
song$ = song$ + " of beer on the wall, " + str$(bottles) + " bottle"
If (bottles > 1) Then song$ = song$ + "s"
song$ = song$ + " of beer," + chr$(13) + chr$(10) + "Take one down, pass it around, " + str$(bottles - 1) + " bottle"
If (bottles > 2) Or (bottles = 1) Then song$ = song$ + "s"
song$ = song$ + " of beer on the wall." + chr$(13) + chr$(10)
Next bottles
song$ = song$ + "No more bottles of beer on the wall, no more bottles of beer." _
+ chr$(13) + chr$(10) + "Go to the store and buy some more, 99 bottles of beer on the wall."
 
Print song$

[edit] OxygenBasic

int    x=99
string cr,tab,pr,bottles,bottlem,remain
cr=chr(13) chr(10)
tab=chr(9)
pr="99 BOTTLES" cr cr
bottles=" bottles "
bottlem=" bottles "
'
for x=99 to 1 step -1
  if x=1
    bottles=" bottle "
    bottlem=" bottles "
    remain="No"
  elseif x=2
    bottlem=" bottle "
    remain=x-1
  else
    remain=x-1
  end if
  pr+=
  x bottles      "of beer on the wall" cr + 
  x bottles      "of beer" cr +
                 "Take one down, pass it around" cr +
  remain bottlem "of beer on the wall" cr +
  cr
next
'
putfile "t.txt",pr 

[edit] PureBasic

[edit] Normal version

If OpenConsole()
Define Bottles=99
While Bottles
PrintN(Str(Bottles)+" bottles of beer on the wall")
PrintN(Str(Bottles)+" bottles of beer")
PrintN("Take one down, pass it around")
Bottles-1
PrintN(Str(Bottles)+" bottles of beer on the wall"+#CRLF$)
Wend
 
PrintN(#CRLF$+#CRLF$+"Press ENTER to exit"):Input()
CloseConsole()
EndIf

[edit] An object-oriented solution

Prototype Wall_Action(*Self, Number.i)
 
Structure WallClass
Inventory.i
AddBottle.Wall_Action
DrinkAndSing.Wall_Action
EndStructure
 
Procedure.s _B(n, Short=#False)
Select n
Case 0 : result$="No more bottles "
Case 1 : result$=Str(n)+" bottle of beer"
Default: result$=Str(n)+" bottles of beer"
EndSelect
If Not Short: result$+" on the wall": EndIf
ProcedureReturn result$+#CRLF$
EndProcedure
 
Procedure PrintBottles(*Self.WallClass, n)
Bottles$=" bottles of beer "
Bottle$ =" bottle of beer "
txt$ = _B(*Self\Inventory)
txt$ + _B(*Self\Inventory, #True)
txt$ + "Take one down, pass it around"+#CRLF$
*Self\AddBottle(*Self, -1)
txt$ + _B(*self\Inventory)
PrintN(txt$)
ProcedureReturn *Self\Inventory
EndProcedure
 
Procedure AddBottle(*Self.WallClass, n)
i=*Self\Inventory+n
If i>=0
*Self\Inventory=i
EndIf
EndProcedure
 
Procedure InitClass()
*class.WallClass=AllocateMemory(SizeOf(WallClass))
If *class
InitializeStructure(*class, WallClass)
With *class
\AddBottle =@AddBottle()
\DrinkAndSing =@PrintBottles()
EndWith
EndIf
ProcedureReturn *class
EndProcedure
 
If OpenConsole()
*MyWall.WallClass=InitClass()
If *MyWall
*MyWall\AddBottle(*MyWall, 99)
While *MyWall\DrinkAndSing(*MyWall, #True): Wend
;
PrintN(#CRLF$+#CRLF$+"Press ENTER to exit"):Input()
CloseConsole()
EndIf
EndIf

[edit] REALbasic

Place the following in the "open" event of a console application.

dim bottles as Integer = 99
While bottles > 0
Print(str(bottles) + " bottles of beer on the wall")
Print(str(bottles) + " bottles of beer")
Print("Take one down, pass it around")
bottles = bottles - 1
Print(str(bottles) + " bottles of beer on the wall")
Wend

[edit] Run BASIC

b$ = " bottles"
for bottles = 99 To 1 Step -1
If (bottles = 1) then b$ = " bottle"
print bottles;b$;" of beer on the wall, "
print bottles ;b$;" of beer"
print "Take one down, pass it around, "
if bottles = 1 then
print "No bottles of beer on the wall"
else
print bottles - 1;b$;" of beer on the wall.";chr$(10)
end if
next bottles

[edit] TI-83 BASIC

PROGRAM:BEER
:For(I,99,1,-1)
:Disp I
:Disp "BOTTLES OF BEER"
:Disp "ON THE WALL,"
:Disp I
:Pause "BOTTLES OF BEER,"
:Disp "TAKE ONE DOWN,"
:Disp "PASS IT AROUND,"
:Disp I-1
:Disp "BOTTLES OF BEER"
:Disp "ON THE WALL."
:End
 

[edit] TI-89 BASIC

Prgm
Local i,plural,clockWas,t,k,wait
"s" → plural
0 → k
isClkOn() → clockWas
 
Define wait() = Prgm
EndPrgm
 
ClockOn
 
For i,99,0,–1
Disp ""
Disp string(i) & " bottle" & plural & " of beer on the"
Disp "wall, " & string(i) & " bottle" & plural & " of beer."
 
getTime()[3]→t
While getTime()[3] = t and k = 0 : getKey() → k : EndWhile
If k ≠ 0 Then : Exit : EndIf
 
Disp "Take one down, pass it"
Disp "around."
 
getTime()[3]→t
While getTime()[3] = t and k = 0 : getKey() → k : EndWhile
If k ≠ 0 Then : Exit : EndIf
 
If i - 1 = 1 Then
"" → plural
EndIf
If i > 1 Then
Disp string(i-1) & " bottle" & plural & " of beer on the"
Disp "wall."
Else
Disp "No more bottles of beer on"
Disp "the wall."
EndIf
 
getTime()[3]→t
While abs(getTime()[3] - t)<2 and k = 0 : getKey() → k : EndWhile
If k ≠ 0 Then : Exit : EndIf
 
EndFor
If not clockWas Then
ClockOff
ENdIf
EndPrgm

[edit] Visual Basic

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

[edit] Visual Basic .NET

Platform: .NET

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

[edit] Batch File

@echo off
setlocal
:main
for /L %%i in (99,-1,1) do (
call :verse %%i
)
echo no bottles of beer on the wall
echo no bottles of beer
echo go to the store and buy some more
echo 99 bottles of beer on the wall
echo.
set /p q="Keep drinking? "
if %q% == y goto main
if %q% == Y goto main
goto :eof
 
:verse
call :plural %1 res
echo %res% of beer on the wall
echo %res% of beer
call :oneit %1 res
echo take %res% down and pass it round
set /a c=%1-1
call :plural %c% res
echo %res% of beer on the wall
echo.
goto :eof
 
:plural
if %1 gtr 1 goto :gtr
if %1 equ 1 goto :equ
set %2=no bottles
goto :eof
:gtr
set %2=%1 bottles
goto :eof
:equ
set %2=1 bottle
goto :eof
 
:oneit
if %1 equ 1 (
set %2=it
) else (
set %2=one
)
goto :eof

[edit] Battlestar

 
const bottle = " bottle"
const plural = "s"
const ofbeer = " of beer"
const wall = " on the wall"
const sep = ", "
const takedown = "Take one down and pass it around, "
const u_no = "No"
const l_no = "no"
const more = " more bottles of beer"
const store = "Go to the store and buy some more, "
const dotnl = ".\n"
const nl = "\n"
 
// Write two digits, uses the value in a
fun writenum
b = a
loop
break (a < 10)
a /= 10
// modulo is in the d register after idiv
b = d
a += 48 // ASCII value for '0'
write(chr(a))
break
end
a = b
a += 48 // ASCII value for '0'
write(chr(a))
end
 
fun main
loop 99
// Save loop counter for later, twice
c -> stack
c -> stack
 
// Print the loop counter (passed in the a register)
a = c
writenum()
 
// N, "bottles of beer on the wall, "
write(bottle)
write(plural)
write(ofbeer)
write(wall)
write(sep)
 
// Retrieve and print the number
stack -> a
writenum()
 
// N, "bottles of beer."
write(bottle)
write(plural)
write(ofbeer)
write(dotnl)
 
// "Take one down and pass it around,"
write(takedown)
 
// N-1, "bottles of beer on the wall."
stack -> a
a--
// Store N-1, used just a few lines down
a -> stack
writenum()
write(bottle)
// Retrieve N-1
stack -> a
// Write an "s" if the count is not 1
a != 1
write(plural)
end
// Write the rest
write(ofbeer)
write(wall)
write(dotnl)
 
// Blank line
write(nl)
 
// Skip to the top of the loop while the counter is >= 2
continue (c >= 2)
 
// At the last two
 
// "1 bottle of beer on the wall,"
a = 1
writenum()
write(bottle)
write(ofbeer)
write(wall)
write(sep)
 
// "1 bottle of beer."
a = 1
writenum()
write(bottle)
write(ofbeer)
write(dotnl)
 
// "Take one down and pass it around,"
write(takedown)
 
// "no more bottles of beer on the wall."
write(l_no)
write(more)
write(wall)
write(dotnl)
 
// Blank line
write(nl)
 
// "No more bottles of beer on the wall,"
write(u_no)
write(more)
write(wall)
write(sep)
 
// "no more bottles of beer."
write(l_no)
write(more)
write(dotnl)
 
// "Go to the store and buy some more,"
write(store)
 
// "99 bottles of beer on the wall."
a = 99
writenum()
write(bottle)
write(plural)
write(ofbeer)
write(wall)
write(dotnl)
end
end
 
// vim: set syntax=c ts=4 sw=4 et:
 

[edit] Befunge

This outputs a single CR (ASCII code 13) between verses; this needs changing for systems other than DOS, Windows, and Mac OS.

<v  <.g10" bottles of beer on the wall"+*4310     <
c>:,|
<v <.g10" bottles of beer"+*4310
>:,|
<v <"take one down, pass it around"+*4310
>:,|
>01g1-:01p v
v <.g10" bottles of beer on the wall"+*4310<
>:,|
>134*+0` |
@

[edit] Bracmat

Copy the code to a file called BottlesOfBeer.bra. Start Bracmat and after the {?} prompt write get$"BottlesOfBeer.bra" <Enter>. Then, after the next prompt, write !r <Enter>. Notice that the lyrics has two more lines at the end:

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.

Code to save to BottlesOfBeer.bra:

{BottlesOfBeer.bra
 
See http://99-bottles-of-beer.net/}
 
X=
new
= n upper nbottles lyrics
. 99:?n
& ( upper
= .@(!arg:%@?a ?z)&str$(upp$!a !z)
)
& ( nbottles
=
. str
$ ( (  !arg:>0
&  !arg
" bottle"
(!arg:1&|s)
| "no more bottles"
)
" of beer"
)
)
& ( lyrics
= (upper$(nbottles$!n:?x) " on the wall, " !x ".\n")
(  !n+-1:?n:~<0
& "Take one down and pass it around, "
nbottles$!n
" on the wall.
 
"
 !lyrics
| "Go to the store and buy some more, "
nbottles$99
" on the wall.
"
)
)
& put$(str$!lyrics);
 
r=
get'"BottlesOfBeer.bra"
& rmv$(str$(BottlesOfBeer ".bak"))
& ren$("BottlesOfBeer.bra".str$(BottlesOfBeer ".bak"))
& put
$ ( "{BottlesOfBeer.bra
 
See http://99-bottles-of-beer.net/}
 
"
, "BottlesOfBeer.bra"
, NEW
)
& lst'(X,"BottlesOfBeer.bra",APP)
& put'(\n,"BottlesOfBeer.bra",APP)
& lst'(r,"BottlesOfBeer.bra",APP)
& put$(str$("\nnew'" X ";\n"),"BottlesOfBeer.bra",APP);
 
new'X;
 

[edit] Brainf***

>+++++++++[<+++++++++++>-]<[>[-]>[-]<<[>+>+<<-]>>[<<+>>-]>>>
[-]<<<+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>>+<
-]<<-<-]+++++++++>[<->-]>>+>[<[-]<<+>>>-]>[-]+<<[>+>-<<-]<<<
[>>+>+<<<-]>>>[<<<+>>>-]>[<+>-]<<-[>[-]<[-]]>>+<[>[-]<-]<+++
+++++[<++++++<++++++>>-]>>>[>+>+<<-]>>[<<+>>-]<[<<<<<.>>>>>-
]<<<<<<.>>[-]>[-]++++[<++++++++>-]<.>++++[<++++++++>-]<++.>+
++++[<+++++++++>-]<.><+++++..--------.-------.>>[>>+>+<<<-]>
>>[<<<+>>>-]<[<<<<++++++++++++++.>>>>-]<<<<[-]>++++[<+++++++
+>-]<.>+++++++++[<+++++++++>-]<--.---------.>+++++++[<------
---->-]<.>++++++[<+++++++++++>-]<.+++..+++++++++++++.>++++++
++[<---------->-]<--.>+++++++++[<+++++++++>-]<--.-.>++++++++
[<---------->-]<++.>++++++++[<++++++++++>-]<++++.-----------
-.---.>+++++++[<---------->-]<+.>++++++++[<+++++++++++>-]<-.
>++[<----------->-]<.+++++++++++..>+++++++++[<---------->-]<
-----.---.>>>[>+>+<<-]>>[<<+>>-]<[<<<<<.>>>>>-]<<<<<<.>>>+++
+[<++++++>-]<--.>++++[<++++++++>-]<++.>+++++[<+++++++++>-]<.
><+++++..--------.-------.>>[>>+>+<<<-]>>>[<<<+>>>-]<[<<<<++
++++++++++++.>>>>-]<<<<[-]>++++[<++++++++>-]<.>+++++++++[<++
+++++++>-]<--.---------.>+++++++[<---------->-]<.>++++++[<++
+++++++++>-]<.+++..+++++++++++++.>++++++++++[<---------->-]<
-.---.>+++++++[<++++++++++>-]<++++.+++++++++++++.++++++++++.
------.>+++++++[<---------->-]<+.>++++++++[<++++++++++>-]<-.
-.---------.>+++++++[<---------->-]<+.>+++++++[<++++++++++>-
]<--.+++++++++++.++++++++.---------.>++++++++[<---------->-]
<++.>+++++[<+++++++++++++>-]<.+++++++++++++.----------.>++++
+++[<---------->-]<++.>++++++++[<++++++++++>-]<.>+++[<----->
-]<.>+++[<++++++>-]<..>+++++++++[<--------->-]<--.>+++++++[<
++++++++++>-]<+++.+++++++++++.>++++++++[<----------->-]<++++
.>+++++[<+++++++++++++>-]<.>+++[<++++++>-]<-.---.++++++.----
---.----------.>++++++++[<----------->-]<+.---.[-]<<<->[-]>[
-]<<[>+>+<<-]>>[<<+>>-]>>>[-]<<<+++++++++<[>>>+<<[>+>[-]<<-]
>[<+>-]>[<<++++++++++>>>+<-]<<-<-]+++++++++>[<->-]>>+>[<[-]<
<+>>>-]>[-]+<<[>+>-<<-]<<<[>>+>+<<<-]>>>[<<<+>>>-]<>>[<+>-]<
<-[>[-]<[-]]>>+<[>[-]<-]<++++++++[<++++++<++++++>>-]>>>[>+>+
<<-]>>[<<+>>-]<[<<<<<.>>>>>-]<<<<<<.>>[-]>[-]++++[<++++++++>
-]<.>++++[<++++++++>-]<++.>+++++[<+++++++++>-]<.><+++++..---
-----.-------.>>[>>+>+<<<-]>>>[<<<+>>>-]<[<<<<++++++++++++++
.>>>>-]<<<<[-]>++++[<++++++++>-]<.>+++++++++[<+++++++++>-]<-
-.---------.>+++++++[<---------->-]<.>++++++[<+++++++++++>-]
<.+++..+++++++++++++.>++++++++[<---------->-]<--.>+++++++++[
<+++++++++>-]<--.-.>++++++++[<---------->-]<++.>++++++++[<++
++++++++>-]<++++.------------.---.>+++++++[<---------->-]<+.
>++++++++[<+++++++++++>-]<-.>++[<----------->-]<.+++++++++++
..>+++++++++[<---------->-]<-----.---.+++.---.[-]<<<]

[edit] Brat

99.to 2 { n |
p "#{n} bottles of beer on the wall, #{n} bottles of beer!"
p "Take one down, pass it around, #{n - 1} bottle#{true? n > 2 's' ''} of beer on the wall."
}
 
p "One bottle of beer on the wall, one bottle of beer!"
p "Take one down, pass it around, no more bottles of beer on the wall."

[edit] C

Translation of: C++

[edit] The simple solution

#include <stdlib.h>
#include <stdio.h>
 
int main(void)
{
unsigned int bottles = 99;
do
{
printf("%u bottles of beer on the wall\n", bottles);
printf("%u bottles of beer\n", bottles);
printf("Take one down, pass it around\n");
printf("%u bottles of beer on the wall\n\n", --bottles);
} while(bottles > 0);
return EXIT_SUCCESS;
}

[edit] A recursive solution

#include <stdio.h>
 
int main(int argc, char *argv[])
{
if(argc == 99)
return 99;
if(argv[0] != NULL){
argv[0] = NULL;
argc = 0;
}
argc = main(argc + 1, argv);
printf("%d bottle%c of beer on the wall\n", argc, argc == 1?'\0': 's');
printf("%d bottle%c of beer\n", argc, argc == 1?'\0': 's');
printf("Take one down, pass it around\n");
printf("%d bottle%c of beer on the wall\n\n", argc - 1, (argc - 1) == 1?'\0': 's');
return argc - 1;
}

[edit] Code golf

#include <stdio.h>
main(){_=100;while(--_)printf("%i bottle%s of beer in the wall,\n%i bottle%"
"s of beer.\nTake one down, pass it round,\n%s%s\n\n",_,_-1?"s":"",_,_-1?"s"
:"",_-1?(char[]){(_-1)/10?(_-1)/10+48:(_-1)%10+48,(_-1)/10?(_-1)%10+48:2+30,
(_-1)/10?32:0,0}:"",_-1?"bottles of beer in the wall":"No more beers");}

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

#include <stdlib.h>
#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(void)
{
(void) printf(SONG);
return EXIT_SUCCESS;
}

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

[edit] The bottled version

WYSIWYG (with correct plurals and can buy some more):
      int b =99,u =1;
#include<stdio.h>
char *d[16],y[]
= "#:ottle/ of"
":eer_ a_Go<o5"
"st>y\x20some6"
"_Take8;down4p"
"a=1rou7_17 _<"
"h;_ m?_nd_ on"
"_085wal" "l_ "
"b_e _ t_ss it"
"_?4bu_ore_9, "
"\060.""@, 9$";
# define x c ^=
#include <string.h>
#define or(t,z) else\
if(c==t && !(c = 0) &&\
(c =! z)); int p(char *t)

{ char *s = t; int c; for (
d[c = 0] = y; !t && (d[c +1
]= strchr(s = d[c], '_'));*
(d[++c]++) = 0); for(t = s?
s:t;(c= *s++); c && putchar
(c)) { if (!((( x 48)& ~0xf
) && ( x 48)) ) p(d[c]), c=
0 ; or('$', p(b - 99?".\n":
"." ) && p(b - 99? t : ""))
or ('\x40', c && p( d[!!b--
+ 2])) or('/', c && p( b^1?
"s": "")) or ('\043', b++ ?
p("So6" + --b):!printf("%d"
, b ? --b : (b += 99))) or(
'S',!(++u % 3) * 32+ 78) or
('.', puts("."))}return c;}
int main() {return p(0);}

[edit] C++

[edit] The simple solution

Works with: g++ version 4.8.1
#include <iostream>
using std::cout;
 
int main()
{
for(int bottles(99); bottles > 0; bottles -= 1){
cout << bottles << " bottles of beer on the wall\n"
<< bottles << " bottles of beer\n"
<< "Take one down, pass it around\n"
<< bottles - 1 << " bottles of beer on the wall\n\n";
}
}

[edit] An object-oriented solution

See: 99 Bottles of Beer/C++/Object Oriented

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

#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;
}

[edit] A Recursive solution

#include <iostream>
using namespace std;
void rec(int bottles)
{
if ( bottles!=0)
{
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;
rec(bottles);
}
}
 
int main()
{
rec(99);
system("pause");
return 0;
}
 

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

#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;
}

[edit] Bottled Version

                          //>,_
//Beer Song>,_
#include <iostream>
using namespace std;
int main(){ for( int
b=-1; b<99; cout <<
'\n') for ( int w=0;
w<3; cout << ".\n"){
if (w==2) cout << ((
b--) ?"Take one dow"
"n and pass it arou"
"nd":"Go to the sto"
"re and buy some mo"
"re"); if (b<0) b=99
; do{ if (w) cout <<
", "; if (b) cout <<
b; else cout << (
(w) ? 'n' : 'N') <<
"o more"; cout <<
" bottle" ; if
(b!=1) cout <<
's' ; cout <<
" of beer";
if (w!=1)
cout <<
" on th"
"e wall"
;} while
(!w++);}
return
0
;
}
//
// by barrym 2011-05-01
// no bottles were harmed in the
// making of this program!!!

[edit] C#

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();
}
}
}
}

[edit] Another Implementation using Linq

Works with: C# version 3+
using System;
using System.Linq;
 
class Program
{
static void Main()
{
var query = from total in Enumerable.Range(0,100).Reverse()
select (total > 0)
? string.Format("{0} bottles of beer on the wall\n{0} bottles of beer\nTake one down, pass it around", total)
: string.Format("{0} bottles left", total);
 
foreach (var item in query)
{
Console.WriteLine(item);
}
}
}

[edit] Flexible Version

 
class Program
{
const string Vessel = "bottle";
const string Beverage = "beer";
const string Location = "on the wall";
 
private static string DefaultAction(ref int bottles)
{
bottles--;
return "take one down, pass it around,";
}
 
private static string FallbackAction(ref int bottles)
{
bottles += 99;
return "go to the store, buy some more,";
}
 
private static string Act(ref int bottles)
{
return bottles > 0 ? DefaultAction(ref bottles) : FallbackAction(ref bottles);
}
 
static void Main()
{
Func<int, string> plural = b => b == 1 ? "" : "s";
Func<int, string> describeCount = b => b == 0 ? "no more" : b.ToString();
Func<int, string> describeBottles = b => string.Format("{0} {1}{2} of {3}", describeCount(b), Vessel, plural(b), Beverage);
Action<string> write = s => Console.WriteLine(CultureInfo.CurrentCulture.TextInfo.ToTitleCase(s));
int bottles = 99;
while (true)
{
write(string.Format("{0} {1}, {0},", describeBottles(bottles), Location));
write(Act(ref bottles));
write(string.Format("{0} {1}.", describeBottles(bottles), Location));
write(string.Empty);
}
}
}
 

[edit] Using Formatting

Works with: C# version 3+
 
class songs
{
static void Main(string[] args)
{
beer(5);
}
 
private static void beer(int bottles)
{
for (int i = bottles; i > 0; i--)
{
if (i > 1)
{
Console.Write("{0}\n{1}\n{2}\n{3}\n\n",
i + " bottles of beer on the wall",
i + " bottles of beer",
"Take one down, pass it around",
(i - 1) + " bottles of beer on the wall");
}
else
Console.Write("{0}\n{1}\n{2}\n{3}\n\n",
i + " bottle of beer on the wall",
i + " bottle of beer",
"Take one down, pass it around",
(i - 1) + " bottles of beer on the wall....");
}
}
}

OUTPUT: 5 bottles of beer on the wall 5 bottles of beer Take one down, pass it around 4 bottles of beer on the wall

4 bottles of beer on the wall 4 bottles of beer Take one down, pass it around 3 bottles of beer on the wall

3 bottles of beer on the wall 3 bottles of beer Take one down, pass it around 2 bottles of beer on the wall

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

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


[edit] Using iterator blocks

Works with: C# version 3+
using System;
using System.Linq;
 
class Program
{
static void Main()
{
BeerBottles().Take(99).ToList().ForEach(Console.WriteLine);
}
 
static IEnumerable<String> BeerBottles()
{
int i = 100;
String f = "{0}, {1}. Take one down, pass it around, {2}";
Func<int, bool, String> booze = (c , b) =>
String.Format("{0} bottle{1} of beer{2}", c > 0 ? c.ToString() : "no more", (c == 1 ? "" : "s"), b ? " on the wall" : "");
 
while (--i >= 1)
yield return String.Format(f, booze(i, true), booze(i, false), booze(i - 1, true));
}
}

[edit] A Fun One

 
string[] bottles = { "80 Shilling",
"Abita Amber",
"Adams Broadside Ale",
"Altenmünster Premium",
"August Schell's SnowStorm",
"Bah Humbug! Christmas Ale",
"Beck's Oktoberfest",
"Belhaven Wee Heavy",
"Bison Chocolate Stout",
"Blue Star Wheat Beer",
"Bridgeport Black Strap Stout",
"Brother Thelonius Belgian-Style Abbey Ale",
"Capital Blonde Doppelbock",
"Carta Blanca",
"Celis Raspberry Wheat",
"Christian Moerlein Select Lager",
"Corona",
"Czechvar",
"Delirium Tremens",
"Diamond Bear Southern Blonde",
"Don De Dieu",
"Eastside Dark",
"Eliot Ness",
"Flying Dog K-9 Cruiser Altitude Ale",
"Fuller's London Porter",
"Gaffel Kölsch",
"Golden Horseshoe",
"Guinness Pub Draught",
"Hacker-Pschorr Weisse",
"Hereford & Hops Black Spring Double Stout",
"Highland Oatmeal Porter",
"Ipswich Ale",
"Iron City",
"Jack Daniel's Amber Lager",
"Jamaica Sunset India Pale Ale",
"Killian's Red",
"König Ludwig Weiss",
"Kronenbourg 1664",
"Lagunitas Hairy Eyball Ale",
"Left Hand Juju Ginger",
"Locktender Lager",
"Magic Hat Blind Faith",
"Missing Elf Double Bock",
"Muskoka Cream Ale ",
"New Glarus Cherry Stout",
"Nostradamus Bruin",
"Old Devil",
"Ommegang Three Philosophers",
"Paulaner Hefe-Weizen Dunkel",
"Perla Chmielowa Pils",
"Pete's Wicked Springfest",
"Point White Biere",
"Prostel Alkoholfrei",
"Quilmes",
"Rahr's Red",
"Rebel Garnet",
"Rickard's Red",
"Rio Grande Elfego Bock",
"Rogue Brutal Bitter",
"Roswell Alien Amber Ale",
"Russian River Pliny The Elder",
"Samuel Adams Blackberry Witbier",
"Samuel Smith's Taddy Porter",
"Schlafly Pilsner",
"Sea Dog Wild Blueberry Wheat Ale",
"Sharp's",
"Shiner 99",
"Sierra Dorada",
"Skullsplitter Orkney Ale",
"Snake Chaser Irish Style Stout",
"St. Arnold Bock",
"St. Peter's Cream Stout",
"Stag",
"Stella Artois",
"Stone Russian Imperial Stout",
"Sweetwater Happy Ending Imperial Stout",
"Taiwan Gold Medal",
"Terrapin Big Hoppy Monster",
"Thomas Hooker American Pale Ale",
"Tie Die Red Ale",
"Toohey's Premium",
"Tsingtao",
"Ugly Pug Black Lager",
"Unibroue Qatre-Centieme",
"Victoria Bitter",
"Voll-Damm Doble Malta",
"Wailing Wench Ale",
"Warsteiner Dunkel",
"Wellhead Crude Oil Stout",
"Weyerbacher Blithering Idiot Barley-Wine Style Ale",
"Wild Boar Amber",
"Würzburger Oktoberfest",
"Xingu Black Beer",
"Yanjing",
"Younger's Tartan Special",
"Yuengling Black & Tan",
"Zagorka Special",
"Zig Zag River Lager",
"Zywiec" };
 
 
int bottlesLeft = 99;
const int FIRST_LINE_SINGULAR = 98;
const int FINAL_LINE_SINGULAR = 97;
string firstLine = "";
string finalLine = "";
 
 
for (int i = 0; i < 99; i++)
{
firstLine = bottlesLeft.ToString() + " bottle";
if (i != FIRST_LINE_SINGULAR)
firstLine += "s";
firstLine += " of beer on the wall, " + bottlesLeft.ToString() + " bottle";
if (i != FIRST_LINE_SINGULAR)
firstLine += "s";
firstLine += " of beer";
 
Console.WriteLine(firstLine);
Console.WriteLine("Take the " + bottles[i] + " down, pass it around,");
bottlesLeft--;
 
finalLine = bottlesLeft.ToString() + " bottle";
if (i != FINAL_LINE_SINGULAR)
finalLine += "s";
finalLine += " of beer on the wall!";
 
Console.WriteLine(finalLine);
Console.WriteLine();
Console.ReadLine();
}
 

[edit] Using recursion

 
public static void BottlesSong(int numberOfBottles)
{
if (numberOfBottles > 0)
{
Console.WriteLine("{0} bottles of beer on the wall", numberOfBottles);
Console.WriteLine("{0} bottles of beer ", numberOfBottles);
Console.WriteLine("Take one down, pass it around");
Console.WriteLine("{0} bottles of beer ", numberOfBottles - 1);
Console.WriteLine();
BottlesSong(--numberOfBottles);
}
}
 

[edit] Clay

/* A few options here: I could give n type Int; or specify that n is of any
numeric type; but here I just let it go -- that way it'll work with anything
that compares with 1 and that printTo knows how to convert to a string. And
all checked at compile time, remember. */
getRound(n) {
var s = String();
var bottle = if (n == 1) " bottle " else " bottles ";
 
printTo(s,
n, bottle, "of beer on the wall\n",
n, bottle, "of beer\n",
"take one down, pass it around\n",
n, bottle, "of beer on the wall!\n");
 
return s;
}
 
main() {
println(join("\n", mapped(getRound, reversed(range(100)))));
}
 

[edit] Chapel

copied from http://99-bottles-of-beer.net/language-chapel-1215.html, with minor modifications for chapel 1.7

Works with: Chapel version 1.7.0
 
/***********************************************************************
* Chapel implementation of "99 bottles of beer"
*
* by Brad Chamberlain and Steve Deitz
* 07/13/2006 in Knoxville airport while waiting for flight home from
* HPLS workshop
* compiles and runs with chpl compiler version 1.7.0
* for more information, contact: [email protected]
*
*
* Notes:
* o as in all good parallel computations, boundary conditions
* constitute the vast bulk of complexity in this code (invite Brad to
* tell you about his zany boundary condition simplification scheme)
* o uses type inference for variables, arguments
* o relies on integer->string coercions
* o uses named argument passing (for documentation purposes only)
***********************************************************************/
 
// allow executable command-line specification of number of bottles
// (e.g., ./a.out -snumBottles=999999)
config const numBottles = 99;
const numVerses = numBottles+1;
 
// a domain to describe the space of lyrics
var LyricsSpace: domain(1) = {1..numVerses};
 
// array of lyrics
var Lyrics: [LyricsSpace] string;
 
// parallel computation of lyrics array
[verse in LyricsSpace] Lyrics(verse) = computeLyric(verse);
 
// as in any good parallel language, I/O to stdout is serialized.
// (Note that I/O to a file could be parallelized using a parallel
// prefix computation on the verse strings' lengths with file seeking)
writeln(Lyrics);
 
 
// HELPER FUNCTIONS:
 
proc computeLyric(verseNum) {
var bottleNum = numBottles - (verseNum - 1);
var nextBottle = (bottleNum + numVerses - 1)%numVerses;
return "\n" // disguise space used to separate elements in array I/O
+ describeBottles(bottleNum, startOfVerse=true) + " on the wall, "
+ describeBottles(bottleNum) + ".\n"
+ computeAction(bottleNum)
+ describeBottles(nextBottle) + " on the wall.\n";
}
 
 
proc describeBottles(bottleNum, startOfVerse:bool = false) {
// NOTE: bool should not be necessary here (^^^^); working around bug
var bottleDescription = if (bottleNum) then bottleNum:string
else (if startOfVerse then "N"
else "n")
+ "o more";
return bottleDescription
+ " bottle" + (if (bottleNum == 1) then "" else "s")
+ " of beer";
}
 
 
proc computeAction(bottleNum) {
return if (bottleNum == 0) then "Go to the store and buy some more, "
else "Take one down and pass it around, ";
}
 

[edit] Chef

99 Bottles Of Beer.
 
Ingredients.
99 bottles
 
Method.
Loop the bottles.
Put bottles into 1st mixing bowl.
Serve with bottles of beer on the wall.
Clean 1st mixing bowl.
Put bottles into 1st mixing bowl.
Serve with bottles of beer.
Clean 1st mixing bowl.
Serve with Take one down and pass it around.
Clean 1st mixing bowl.
Loop the bottles until looped.
Serve with No more bottles of beer.
Clean 1st mixing bowl.
Pour contents of the 3rd mixing bowl into the 1st baking dish.
 
Serves 1.
 
bottles of beer on the wall.
 
Prints out "n" bottles of beer on the wall.
 
Ingredients.
108 g lime
97 cups asparagus
119 pinches watercress
32 tablespoons pickles
101 pinches eggplant
104 g huckleberry
116 teaspoons turnip
110 tablespoons nannyberry
111 tablespoons onion
114 tablespoons raspberry
98 g broccoli
102 g feijoa
115 teaspoons squach
10 ml new line
 
Method.
Put new line into 1st mixing bowl.
Put lime into 2nd mixing bowl.
Put lime into 2nd mixing bowl.
Put asparagus into 2nd mixing bowl.
Put watercress into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put eggplant into 2nd mixing bowl.
Put huckleberry into 2nd mixing bowl.
Put turnip into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put nannyberry into 2nd mixing bowl.
Put onion into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put raspberry into 2nd mixing bowl.
Put eggplant into 2nd mixing bowl.
Put eggplant into 2nd mixing bowl.
Put broccoli into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put feijoa into 2nd mixing bowl.
Put onion into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put squach into 2nd mixing bowl.
Put eggplant into 2nd mixing bowl.
Put lime into 2nd mixing bowl.
Put turnip into 2nd mixing bowl.
Put turnip into 2nd mixing bowl.
Put onion into 2nd mixing bowl.
Put broccoli into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Liquify contents of the 2nd mixing bowl.
Pour contents of the 2nd mixing bowl into the baking dish.
Pour contents of the mixing bowl into the baking dish.
Refrigerate for 1 hour.
 
bottles of beer.
 
Prints out "n" bottles of beer.
 
Ingredients.
114 tablespoons raspberry
101 pinches eggplant
98 teaspoons broccoli
32 pinches pickles
102 tablespoons feijoa
111 teaspoons onion
115 cups squach
108 cups lime
116 teaspoons turnip
10 ml new line
 
Method.
Put new line into 1st mixing bowl.
Put raspberry into 2nd mixing bowl.
Put eggplant into 2nd mixing bowl.
Put eggplant into 2nd mixing bowl.
Put broccoli into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put feijoa into 2nd mixing bowl.
Put onion into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put squach into 2nd mixing bowl.
Put eggplant into 2nd mixing bowl.
Put lime into 2nd mixing bowl.
Put turnip into 2nd mixing bowl.
Put turnip into 2nd mixing bowl.
Put onion into 2nd mixing bowl.
Put broccoli into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Liquify contents of the 2nd mixing bowl.
Pour contents of the 2nd mixing bowl into the baking dish.
Pour contents of the mixing bowl into the baking dish.
Refrigerate for 1 hour.
 
Take one down and pass it around.
 
Prints out "Take one down and pass it around".
 
Ingredients.
100 cups dandelion
110 g nannyberry
117 pinches cucumber
111 pinches onion
114 pinches raspberry
97 g asparagus
32 tablespoons pickles
116 pinches turnip
105 g chestnut
115 g squach
112 g pumpkin
119 cups watercress
101 g eggplant
107 g kale
84 cups tomatoe
10 ml new line
 
Method.
Put new line into 3rd mixing bowl.
Put dandelion into 2nd mixing bowl.
Put nannyberry into 2nd mixing bowl.
Put cucumber into 2nd mixing bowl.
Put onion into 2nd mixing bowl.
Put raspberry into 2nd mixing bowl.
Put asparagus into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put turnip into 2nd mixing bowl.
Put chestnut into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put squach into 2nd mixing bowl.
Put squach into 2nd mixing bowl.
Put asparagus into 2nd mixing bowl.
Put pumpkin into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put dandelion into 2nd mixing bowl.
Put nannyberry into 2nd mixing bowl.
Put asparagus into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put nannyberry into 2nd mixing bowl.
Put watercress into 2nd mixing bowl.
Put onion into 2nd mixing bowl.
Put dandelion into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put eggplant into 2nd mixing bowl.
Put nannyberry into 2nd mixing bowl.
Put onion into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put eggplant into 2nd mixing bowl.
Put kale into 2nd mixing bowl.
Put asparagus into 2nd mixing bowl.
Put tomatoe into 2nd mixing bowl.
Liquify contents of the 2nd mixing bowl.
Pour contents of the 2nd mixing bowl into the baking dish.
Pour contents of the 3rd mixing bowl into the baking dish.
Refrigerate for 1 hour.
 
No more bottles of beer.
 
Prints out "No more bottles of beer".
 
Ingredients.
114 pinches raspberry
101 teaspoons eggplant
98 cups broccoli
32 tablespoons pickles
102 pinches feijoa
111 cups onion
115 tablespoons squach
108 tablespoons lime
116 pinches turnip
109 cups mushrooms
78 g nectarine
10 ml new line
 
Method.
Put new line into 3rd mixing bowl.
Put new line into 2nd mixing bowl.
Put raspberry into 2nd mixing bowl.
Put eggplant into 2nd mixing bowl.
Put eggplant into 2nd mixing bowl.
Put broccoli into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put feijoa into 2nd mixing bowl.
Put onion into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put squach into 2nd mixing bowl.
Put eggplant into 2nd mixing bowl.
Put lime into 2nd mixing bowl.
Put turnip into 2nd mixing bowl.
Put turnip into 2nd mixing bowl.
Put onion into 2nd mixing bowl.
Put broccoli into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put eggplant into 2nd mixing bowl.
Put raspberry into 2nd mixing bowl.
Put onion into 2nd mixing bowl.
Put mushrooms into 2nd mixing bowl.
Put pickles into 2nd mixing bowl.
Put onion into 2nd mixing bowl.
Put nectarine into 2nd mixing bowl.
Liquify contents of the 2nd mixing bowl.
Pour contents of the 2nd mixing bowl into the baking dish.
Pour contents of the 3rd mixing bowl into the baking dish.
Refrigerate for 1 hour.

[edit] CLIPS

(deffacts beer-bottles
(bottles 99))
 
(deffunction bottle-count
(?count)
(switch ?count
(case 0 then "No more bottles of beer")
(case 1 then "1 more bottle of beer")
(default (str-cat ?count " bottles of beer"))))
 
(defrule stanza
 ?bottles <- (bottles ?count)
=>
(retract ?bottles)
(printout t (bottle-count ?count) " on the wall," crlf)
(printout t (bottle-count ?count) "." crlf)
(printout t "Take one down, pass it around," crlf)
(printout t (bottle-count (- ?count 1)) " on the wall." crlf crlf)
(if (> ?count 1) then (assert (bottles (- ?count 1)))))

[edit] Clojure

(defn sing
[start]
(doseq [n (range start 0 -1)]
(printf "%d bottles of beer on the wall,
%d bottles of beer,
Take one down, pass it around,
%d bottles of beer on the wall.\n\n"

n
n
(dec n))))
 
(sing 99)

Or, using cl-format:

Translation of: Common Lisp
(clojure.pprint/cl-format 
true
"~{~[~^~]~:*~D bottle~:P of beer on the wall~%~:*~D bottle~:P of beer
Take one down, pass it around,~%~D bottle~:P~:* of beer on the wall.~2%~}"

(range 99 0 -1))

[edit] COBOL

Works with: OpenCOBOL version 1.1

Free form version.

identification division.
program-id. ninety-nine.
environment division.
data division.
working-storage section.
01 counter pic 99.
88 no-bottles-left value 0.
88 one-bottle-left value 1.
 
01 parts-of-counter redefines counter.
05 tens pic 9.
05 digits pic 9.
 
01 after-ten-words.
05 filler pic x(7) value spaces.
05 filler pic x(7) value "Twenty".
05 filler pic x(7) value "Thirty".
05 filler pic x(7) value "Forty".
05 filler pic x(7) value "Fifty".
05 filler pic x(7) value "Sixty".
05 filler pic x(7) value "Seventy".
05 filler pic x(7) value "Eighty".
05 filler pic x(7) value "Ninety".
05 filler pic x(7) value spaces.
 
01 after-ten-array redefines after-ten-words.
05 atens occurs 10 times pic x(7).
 
01 digit-words.
05 filler pic x(9) value "One".
05 filler pic x(9) value "Two".
05 filler pic x(9) value "Three".
05 filler pic x(9) value "Four".
05 filler pic x(9) value "Five".
05 filler pic x(9) value "Six".
05 filler pic x(9) value "Seven".
05 filler pic x(9) value "Eight".
05 filler pic x(9) value "Nine".
05 filler pic x(9) value "Ten".
05 filler pic x(9) value "Eleven".
05 filler pic x(9) value "Twelve".
05 filler pic x(9) value "Thirteen".
05 filler pic x(9) value "Fourteen".
05 filler pic x(9) value "Fifteen".
05 filler pic x(9) value "Sixteen".
05 filler pic x(9) value "Seventeen".
05 filler pic x(9) value "Eighteen".
05 filler pic x(9) value "Nineteen".
05 filler pic x(9) value spaces.
 
01 digit-array redefines digit-words.
05 adigits occurs 20 times pic x(9).
 
01 number-name pic x(15).
 
procedure division.
100-main section.
100-setup.
perform varying counter from 99 by -1 until no-bottles-left
perform 100-show-number
display " of beer on the wall"
perform 100-show-number
display " of beer"
display "Take " with no advancing
if one-bottle-left
display "it " with no advancing
else
display "one " with no advancing
end-if
display "down and pass it round"
subtract 1 from counter giving counter
perform 100-show-number
display " of beer on the wall"
add 1 to counter giving counter
display space
end-perform.
display "No more bottles of beer on the wall"
display "No more bottles of beer"
display "Go to the store and buy some more"
display "Ninety Nine bottles of beer on the wall"
stop run.
 
100-show-number.
if no-bottles-left
display "No more" with no advancing
else
if counter < 20
display function trim( adigits( counter ) ) with no advancing
else
if counter < 100
move spaces to number-name
string atens( tens ) delimited by space, space delimited by size, adigits( digits ) delimited by space into number-name
display function trim( number-name) with no advancing
end-if
end-if
end-if.
if one-bottle-left
display " bottle" with no advancing
else
display " bottles" with no advancing
end-if.
 
100-end.
end-program.

Another free-form version, without using DISPLAY NO ADVANCING.

identification division.
program-id. ninety-nine.
environment division.
data division.
working-storage section.
01 counter pic 99.
88 no-bottles-left value 0.
88 one-bottle-left value 1.
 
01 parts-of-counter redefines counter.
05 tens pic 9.
05 digits pic 9.
 
01 after-ten-words.
05 filler pic x(7) value spaces.
05 filler pic x(7) value "Twenty".
05 filler pic x(7) value "Thirty".
05 filler pic x(7) value "Forty".
05 filler pic x(7) value "Fifty".
05 filler pic x(7) value "Sixty".
05 filler pic x(7) value "Seventy".
05 filler pic x(7) value "Eighty".
05 filler pic x(7) value "Ninety".
05 filler pic x(7) value spaces.
 
01 after-ten-array redefines after-ten-words.
05 atens occurs 10 times pic x(7).
 
01 digit-words.
05 filler pic x(9) value "One".
05 filler pic x(9) value "Two".
05 filler pic x(9) value "Three".
05 filler pic x(9) value "Four".
05 filler pic x(9) value "Five".
05 filler pic x(9) value "Six".
05 filler pic x(9) value "Seven".
05 filler pic x(9) value "Eight".
05 filler pic x(9) value "Nine".
05 filler pic x(9) value "Ten".
05 filler pic x(9) value "Eleven".
05 filler pic x(9) value "Twelve".
05 filler pic x(9) value "Thirteen".
05 filler pic x(9) value "Fourteen".
05 filler pic x(9) value "Fifteen".
05 filler pic x(9) value "Sixteen".
05 filler pic x(9) value "Seventeen".
05 filler pic x(9) value "Eighteen".
05 filler pic x(9) value "Nineteen".
05 filler pic x(9) value spaces.
 
01 digit-array redefines digit-words.
05 adigits occurs 20 times pic x(9).
 
01 number-name pic x(15).
 
01 stringified pic x(30).
01 outline pic x(50).
01 other-numbers.
03 n pic 999.
03 r pic 999.
 
procedure division.
100-main section.
100-setup.
perform varying counter from 99 by -1 until no-bottles-left
move spaces to outline
perform 100-show-number
string stringified delimited by "|", space, "of beer on the wall" into outline end-string
display outline end-display
move spaces to outline
string stringified delimited by "|", space, "of beer" into outline end-string
display outline end-display
move spaces to outline
move "Take" to outline
if one-bottle-left
string outline delimited by space, space, "it" delimited by size, space, "|" into outline end-string
else
string outline delimited by space, space, "one" delimited by size, space, "|" into outline end-string
end-if
string outline delimited by "|", "down and pass it round" delimited by size into outline end-string
display outline end-display
move spaces to outline
subtract 1 from counter giving counter end-subtract
perform 100-show-number
string stringified delimited by "|", space, "of beer on the wall" into outline end-string
display outline end-display
add 1 to counter giving counter end-add
display space end-display
end-perform.
display "No more bottles of beer on the wall"
display "No more bottles of beer"
display "Go to the store and buy some more"
display "Ninety-Nine bottles of beer on the wall"
stop run.
 
100-show-number.
if no-bottles-left
move "No more|" to stringified
else
if counter < 20
string function trim( adigits( counter ) ), "|" into stringified
else
if counter < 100
move spaces to number-name
string atens( tens ) delimited by space, space delimited by size, adigits( digits ) delimited by space into number-name end-string
move function trim( number-name) to stringified
divide counter by 10 giving n remainder r end-divide
if r not = zero
inspect stringified replacing first space by "-"
end-if
inspect stringified replacing first space by "|"
end-if
end-if
end-if.
if one-bottle-left
string stringified delimited by "|", space, "bottle|" delimited by size into stringified end-string
else
string stringified delimited by "|", space, "bottles|" delimited by size into stringified end-string
end-if.
 
100-end.
end-program.

A more concise version that adheres to the minimum guidelines. Leading zeros are not suppressed. (OpenCOBOL - 1.1.0)

program-id. ninety-nine.
data division.
working-storage section.
01 cnt pic 99.
 
procedure division.
 
perform varying cnt from 99 by -1 until cnt < 1
display cnt " bottles of beer on the wall"
display cnt " bottles of beer"
display "Take one down, pass it around"
subtract 1 from cnt
display cnt " bottles of beer on the wall"
add 1 to cnt
display space
end-perform.

[edit] CoffeeScript

 
bottlesOfBeer = (n) ->
"#{n} bottle#{if n is 1 then '' else 's'} of beer"
 
console.log """
#{bottlesOfBeer n} on the wall
#{bottlesOfBeer n}
Take one down, pass it around
#{bottlesOfBeer n - 1} on the wall
\n"""
for n in [99..1]
 

With completely different approach...

for j in [99..1]
x=''
x += [j,j-1,'\nTake one down, pass it around\n'," bottles of beer",' on the wall\n'][i] for i in [0,3,4,0,3,2,1,3,4]
console.log x.replace /(1.+)s/g, '$1'
 

or as a one liner...

console.log( if (j+2)%4 then (x=Math.round j/4)+" bottle#{if x-1 then 's' else ''} of beer#{if (j+1)%4 then ' on the wall' else ''}" else "Take one down, pass it around" ) for j in [396..1]

or another completely different one liner

((console.log if i is 2 then "Take one down, pass it around" else "#{b-!(i-1%4)} bottle#{if 4*b+i<10 and b-i then '' else 's'} of beer#{if i%3 then ' on the wall' else ''}") for i in [4..1]) for b in [99..1]

[edit] ColdFusion

[edit] Classic tag based CFML

<cfoutput>
<cfloop index="x" from="99" to="0" step="-1">
<cfset plur = iif(x is 1,"",DE("s"))>
#x# bottle#plur# of beer on the wall<br>
#x# bottle#plur# of beer<br>
Take one down, pass it around<br>
#iif(x is 1,DE("No more"),"x-1")# bottle#iif(x is 2,"",DE("s"))# of beer on the wall<br><br>
</cfloop>
</cfoutput>

or if you prefer: (identical output, grammatically correct to the last stanza)

[edit] CFScript

<cfscript>
for (x=99; x gte 1; x--) {
plur = iif(x==1,'',DE('s'));
WriteOutput("#x# bottle#plur# of beer on the wall<br>#x# bottle#plur# of beer<br>Take one down, pass it around<br>#iif(x is 1,DE('No more'),'x-1')# bottle#iif(x is 2,'',DE('s'))# of beer on the wall<br><br>");
}
</cfscript>

[edit] Common Lisp

[edit] Sensible solution

(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))))

and then just call

(bottles 99)

[edit] Ridiculous

(format t "~{~[~^~]~:*~D bottle~:P of beer on the wall~%~:*~D bottle~:P of beer~%Take one down, pass it around~%~D bottle~:P~:* of beer on the wall~2%~}"
(loop :for n :from 99 :downto 0 :collect n))

The FORMAT function is probably the most baroque (i.e. featureful almost to a fault) function in Common Lisp. To really drive this point home, try replacing each instance of ~D with ~R, and then with ~@R. Yes, this is all standard and dependable (dys?)functionality.

Explanation of the format string for the uninitiated:

  • ~{fmt~} expects the next argument to be a list (which is of the integers from 99 down to 0), and executes the format string fmt on each element. It is essentially a map or foreach.
  • ~[...~] is a case/switch. It executes the nth clause, where n is taken from the next argument. Since there is only one clause here, it will be executed only when the argument is 0.
  • ~^ will terminate formatting.
  • ~:* will back-up to the most-recently used argument.
  • ~D prints the next argument as a decimal number.
  • ~:P is for English plurals: it prints s if the last argument wasn't 1; it prints nothing otherwise. There's also ~@P for y/ies, in case you were worried about that.

Note, by the way, how the emoticons :*~D and :P have shown up in the format string. FORMAT is so powerful, it's even self-aware about how silly it is.

[edit] Component Pascal

BlackBox Component Builder

 
MODULE BottlesOfBeer;
IMPORT StdLog;
CONST bottles = 99;
 
PROCEDURE Part(i: INTEGER);
BEGIN
StdLog.Int(i);StdLog.String(" bottles of beer on the wall");StdLog.Ln;
StdLog.Int(i);StdLog.String(" bottles of beer");StdLog.Ln;
StdLog.String("Take one down, pass it around");StdLog.Ln;
StdLog.Int(i - 1);StdLog.String(" bottles of beer on the wall.");StdLog.Ln;
StdLog.Ln
END Part;
 
PROCEDURE Sing*;
VAR
i: INTEGER;
BEGIN
FOR i := bottles TO 1 BY -1 DO
Part(i)
END
END Sing;
END BottlesOfBeer.
 

Execute: ^Q BottlesOfBeer.Sing
Output:

 99 bottles of beer on the wall
 99 bottles of beer
Take one down, pass it around
 98 bottles of beer on the wall.

 98 bottles of beer on the wall
 98 bottles of beer
Take one down, pass it around
 97 bottles of beer on the wall.

 97 bottles of beer on the wall
 97 bottles of beer
Take one down, pass it around
 96 bottles of beer on the wall.

...


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

[edit] D

[edit] Simple Solution

Works with: D version 2

Based on Steward Gordon's code at: 99-bottles-of-beer.net.

import std.stdio;
 
void main() {
int bottles = 99;
 
while (bottles > 1) {
writeln(bottles, " bottles of beer on the wall,");
writeln(bottles, " bottles of beer.");
writeln("Take one down, pass it around,");
if (--bottles > 1) {
writeln(bottles, " bottles of beer on the wall.\n");
}
}
writeln("1 bottle of beer on the wall.\n");
 
writeln("No more bottles of beer on the wall,");
writeln("no more bottles of beer.");
writeln("Go to the store and buy some more,");
writeln("99 bottles of beer on the wall.");
}

[edit] CTFE Solution

CTFE (Compile-Time Function Execution) is a feature of D that allows for pure functions of arbitrary complexity to be completely evaluated at compile time when every parameter is known. Note that this is distinct from the template meta-programming tricks used by some other languages, and this bottles() function could just as easily be executed during run-time. The compiled result of this program simply prints the pre-generated lyrics to the song, using a standard compiler pragma directive.

import std.stdio, std.conv;
 
string bottles(in size_t num) pure {
static string bottlesRecurse(in size_t num) pure {
return num.text ~ " bottles of beer on the wall,\n"
~ num.text ~ " bottles of beer!\n"
~ "Take one down, pass it around,\n"
~ (num - 1).text ~ " bottle" ~ ((num - 1 == 1) ? "" : "s")
~ " of beer on the wall.\n\n"
~ ((num > 2)
? bottlesRecurse(num - 1)
: "1 bottle of beer on the wall,\n"
~ "1 bottle of beer!\n"
~ "Take one down, pass it around,\n"
~ "No bottles of beer on the wall!\n\n");
}
 
return bottlesRecurse(num)
~ "Go to the store and buy some more...\n"
~ num.text ~ " bottles of beer on the wall!";
}
 
pragma(msg, 99.bottles);
void main() {}

[edit] Dart

main() {
for(int x=99;x>0;x--) {
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("");
}
}

[edit] Delphi

See Pascal
Or
program Hundred_Bottles; 
 
{$APPTYPE CONSOLE}
 
uses SysUtils;
 
const C_1_Down = 'Take one down, pass it around' ;
 
Var i : Integer ;
 
// As requested, some fun : examples of Delphi basic techniques. Just to make it a bit complex
 
procedure WriteABottle( BottleNr : Integer ) ;
begin
Writeln(BottleNr, ' bottles of beer on the wall' ) ;
end ;
 
begin
for i := 99 Downto 1 do begin
WriteABottle(i);
Writeln( Format('%d bottles of beer' , [i] ) ) ;
Writeln( C_1_Down ) ;
WriteABottle(i-1);
Writeln ;
End ;
 
end.

[edit] Déjà Vu

plural i:
if = 1 i "" "s"
 
bottles i:
local :s plural i
!print( to-str i " bottle"s" of beer on the wall, " to-str i " bottle"s" of beer," )
!print\ "You take one down, pass it around, "
set :i -- i
if i:
set :s plural i
!print( to-str i " bottle"s" of beer on the wall." )
bottles i
else:
!print "no more bottles of beer on the wall, no more bottles of beer."
!print "Go to the store and buy some more, 99 bottles of beer on the wall."
 
bottles 99

[edit] Dylan

Module: bottles
define method bottles (n :: <integer>)
for (n from 99 to 1 by -1)
format-out("%d bottles of beer on the wall,\n"
"%d bottles of beer\n"
"Take one down, pass it around\n"
"%d bottles of beer on the wall\n",
n, n, n - 1);
end
end method

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

[edit] ECL

 
Layout := RECORD
UNSIGNED1 RecID1;
UNSIGNED1 RecID2;
STRING30 txt;
END;
Beers := DATASET(99,TRANSFORM(Layout,
SELF.RecID1 := COUNTER,SELF.RecID2 := 0,SELF.txt := ''));
 
Layout XF(Layout L,INTEGER C) := TRANSFORM
IsOneNext := L.RecID1-1 = 1;
IsOne := L.RecID1 = 1;
SELF.txt := CHOOSE(C,
(STRING)(L.RecID1-1) + ' bottle'+IF(IsOneNext,'','s')+' of beer on the wall',
'Take one down, pass it around',
(STRING)(L.RecID1) + ' bottle'+IF(IsOne,'','s')+' of beer',
(STRING)(L.RecID1) + ' bottle'+IF(IsOne,'','s')+' of beer on the wall','');
SELF.RecID2 := C;
SELF := L;
END;
 
Rev := NORMALIZE(Beers,5,XF(LEFT,COUNTER));
OUTPUT(SORT(Rev,-Recid1,-RecID2),{txt},ALL);
 

[edit] EGL

program TestProgram type BasicProgram {}
 
function main()
for (count int from 99 to 1 decrement by 1)
SysLib.writeStdout( bottleStr( count ) :: " of beer on the wall." );
SysLib.writeStdout( bottleStr( count ) :: " of beer." );
SysLib.writeStdout( "Take one down, pass it around." );
SysLib.writeStdout( bottleStr( count - 1) :: " of beer on the wall.\n");
end
end
 
private function bottleStr( count int in) returns( string )
case ( count )
when ( 1 )
return( "1 bottle" );
when ( 0 )
return( "No more bottles" );
otherwise
return( count :: " bottles" );
end
end
end

[edit] Eiffel

 
class
APPLICATION
 
create
make
 
feature {NONE} -- Initialization
 
make
local
bottles: INTEGER
do
from
bottles := 99
invariant
bottles <= 99 and bottles >= 1
until
bottles = 1
loop
print (bottles)
print (" bottles of beer on the wall,%N")
print (bottles)
print (" bottles of beer.%N")
print ("Take one down, pass it around,%N")
bottles := bottles - 1
if bottles > 1 then
print (bottles)
print (" bottles of beer on the wall.%N%N")
end
variant
bottles
end
print ("1 bottle of beer on the wall.%N%N");
print ("No more bottles of beer on the wall,%N");
print ("no more bottles of beer.%N");
print ("Go to the store and buy some more,%N");
print ("99 bottles of beer on the wall.%N");
end
 
end
 

[edit] Ela

open list
 
beer 1 = "1 bottle of beer on the wall\n1 bottle of beer\nTake one down, pass it around"
beer 0 = "better go to the store and buy some more."
beer v = show v ++ " bottles of beer on the wall\n"
++ show v
++" bottles of beer\nTake one down, pass it around\n"
 
map beer [99,98..0]

[edit] Elixir

defmodule Bottles do
def run do
Enum.each 99..1, fn idx ->
IO.puts "#{idx} bottle#{plural(idx)} of beer on the wall"
IO.puts "#{idx} bottle#{plural(idx)} of beer"
IO.puts "Take one down, pass it around"
IO.puts "#{idx - 1} bottle#{plural(idx-1)} of beer on the wall"
IO.puts ""
end
end
 
def plural(1), do: ""
def plural(num), do: "s"
end
 
Bottles.run

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

[edit] Euphoria

Works with: Euphoria version 4.0.0

This is based on the Batch File example.

 
include std/console.e
include std/search.e
 
function one_or_it( atom n )
if n = 1 then
return "it"
else
return "one"
end if
end function
 
function numberable( atom n )
if n = 0 then
return "no"
else
return sprintf( "%d", n )
end if
end function
 
function plural( atom n )
if n != 1 then
return "s"
else
return ""
end if
end function
 
atom stillDrinking = 1
 
sequence yn
sequence plurality
sequence numerality
 
while stillDrinking do
for bottle = 99 to 1 by -1 do
plurality = plural( bottle )
numerality = numberable( bottle )
printf( 1, "%s bottle%s of beer on the wall\n%s bottle%s of beer\n",
{ numerality, plurality, numerality, plurality } )
printf( 1, "Take %s down and pass it round\n", { one_or_it( bottle ) } )
printf( 1, "%s bottle%s of beer on the wall\n\n",
{ numberable( bottle - 1 ), plural( bottle - 1 ) } )
end for
puts( 1, "No more bottles of beer on the wall\nNo more bottles of beer\n" )
puts( 1, "Go to the store and buy some more\n99 bottles of beer on the wall\n" )
puts( 1, "\nKeep drinking? " )
yn = gets(0)
stillDrinking = find_any( "yY", yn )
puts( 1, "\n" )
end while

[edit] Extended BrainF***

more info about EBF

 
;; Macroes
; create 100
{init
 :tmp
$tmp 10+(-^where 10+)
 !tmp
}
 
; macro that prints 99-2
{print_num
 :what:div:1s:10s
 %where(-$what+$div+)
$div(-^where+)
 %div 10+
$what &divmod
$div(-)
$10s(|"0"(-))
$1s|"0"(-)
$what(-)
 !10s!1s!div!what
}
 
; macro that prints the text between the numbers
{do_iteration
 :iter:zero:tmp
(-$iter+$zero+)
$zero(-^+)+
switch $iter-
(
$tmp|" of beer on the wall"(-)
$iter-
(-$zero-|"."(-)10+..(-))
$zero(-|", "(-))
)
$zero(-
|" of beer."(-)10+.(-)
$zero+
$not_first((-)$zero-
|"Go to the store and buy some more, 99 bottles of beer on the wall."(-)10+.(-))
$zero(-|"Take one down and pass it around, "(-))
)
 !tmp!zero!iter
}
 
; divmod performs divide and modulus at the same time
{divmod[->-[>+>>]>[+[-<+>]>+>>]<<<<<]*-3}
 
;; global variables
:not_first
:round
:number
:copy
:flag
 
;; main program starts here
$number &init
while $number
(
$round++
$not_first(-$round+)
while $round
(
$number(-$copy+$flag+)
$flag(-$number+)+
switch $copy
-(-
(+
$copy &print_num
$flag-
$copy(-)
|" bottles"(-)
) $flag (-
|"1 bottle"(-)
)) $flag (-
|"No more bottles"(-)
$not_first+
)
 
$round &do_iteration
$round-
)
$not_first+
$number-
)
 
 


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

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

[edit] Falcon

for i in [99:1]
> i, " bottles of beer on the wall"
> i, " bottles of beer"
> "Take one down, pass it around"
> i-1, " bottles of beer on the wall\n"
end

A more robust version to handle plural/not plural conditions

for i in [99:1]
plural = (i != 1) ? 's' : ""
> @ "$i bottle$plural of beer on the wall"
> @ "$i bottle$plural of beer"
> "Take one down, pass it around"
> i-1, @ " bottle$plural of beer on the wall\n"
end

[edit] FALSE

[$." bottle"$1-["s"]?" of beer"]b:
99
[$][b;!" on the wall
"b;!"
Take one down and pass it around
"1-b;!" on the wall
"]#%

[edit] ferite

copied from 99-bottles-of-beer.net.

uses "console";
 
number bottles = 99;
boolean looping = true;
object counter = closure {
if (--bottles > 0) {
return true;
} else {
return false;
}
};
 
while (looping) {
Console.println("${bottles} bottles of beer on the wall,");
Console.println("${bottles} bottles of beer,");
Console.println("Take one down, pass it around,");
 
looping = counter.invoke();
 
Console.println("${bottles} bottles of beer on the wall.");

[edit] Fexl

 
\suffix=(\n eq n 1 "" "s")
\sing_count=(\n put n put " " put "bottle" put (suffix n) put " of beer")
\sing_line1=(\n sing_count n put " on the wall" nl)
\sing_line2=(\n sing_count n nl)
\sing=
(@\loop\n
le n 0 ();
sing_line1 n
sing_line2 n
say "Take one down, pass it around"
\n=(- n 1)
sing_line1 n
nl
loop n
)
sing 3
 

The output is:

Output:
3 bottles of beer on the wall
3 bottles of beer
Take one down, pass it around
2 bottles of beer on the wall

2 bottles of beer on the wall
2 bottles of beer
Take one down, pass it around
1 bottle of beer on the wall

1 bottle of beer on the wall
1 bottle of beer
Take one down, pass it around
0 bottles of beer on the wall

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

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

[edit] MPI version

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

Usage:

mpif90 filename.f90
mpiexec -np 99 a.out

[edit] Frege

Translation of: Haskell
Works with: Frege version 3.20.113
module Beer where
 
beer 1 = "1 bottle of beer on the wall\n1 bottle of beer\nTake one down, pass it around"
beer 0 = "better go to the store and buy some more."
beer v = show v ++ " bottles of beer on the wall\n"
++ show v
++" bottles of beer\nTake one down, pass it around\n"
++ head (lines $ beer $ v-1) ++ "\n"
 
main _ = mapM_ (printStrLn . beer) (reverse (0..99))

[edit] friendly interactive shell

set i 99
# Assign s to variable $s
set s s
while test $i != 'No more'
echo $i bottle$s of beer on the wall,
echo $i bottle$s of beer.
echo Take one down, pass it around,
set i (math $i - 1)
if test $i -eq 1
set s ""
else if test $i -eq 0
set i 'No more'
end
echo $i bottle$s of beer on the wall.
if test $i != 'No more'
echo
end
end

[edit] Frink

Frink tracks units of measure through all calculations. It has a large library of built-in units of measure, including volume. The following program prints out the remaining volume of beer (assuming we start with 99 bottles of beer, each containing 12 fluid ounces) in different random units of volume, never repeating a unit.

 
units = array[units[volume]]
showApproximations[false]
 
for n = 99 to 0 step -1
{
unit = units.removeRandom[]
str = getBottleString[n, unit]
 
println["$str of beer on the wall, $str."]
 
if (n == 0)
println["Go to the store and buy some more, 99 bottles of beer on the wall."]
else
println["Take one down and pass it around, " + getBottleString[n-1, unit] + " on the wall.\n"]
}
 
getBottleString[n, unit] := format[n*12 floz, unit, 6] + "s"
 

Sample randomized output:

0.019386 facecords of beer on the wall, 0.019386 facecords.
Take one down and pass it around, 0.019190 facecords on the wall.

36.750000 quarts of beer on the wall, 36.750000 quarts.
Take one down and pass it around, 36.375000 quarts on the wall.

581539.650545 brminims of beer on the wall, 581539.650545 brminims.
Take one down and pass it around, 575544.396416 brminims on the wall.

10.377148 scotsoatlippys of beer on the wall, 10.377148 scotsoatlippys.
Take one down and pass it around, 10.269053 scotsoatlippys on the wall.

7.416004 cangallons of beer on the wall, 7.416004 cangallons.
Take one down and pass it around, 7.337941 cangallons on the wall.

3335.894135 dessertspoons of beer on the wall, 3335.894135 dessertspoons.
Take one down and pass it around, 3300.405899 dessertspoons on the wall.

0.233105 barrelbulks of beer on the wall, 0.233105 barrelbulks.
Take one down and pass it around, 0.230599 barrelbulks on the wall.

21.766118 magnums of beer on the wall, 21.766118 magnums.
Take one down and pass it around, 21.529530 magnums on the wall.

1092.000000 fluidounces of beer on the wall, 1092.000000 fluidounces.
Take one down and pass it around, 1080.000000 fluidounces on the wall.
...
12.000000 ponys of beer on the wall, 12.000000 ponys.
Take one down and pass it around, 0.000000 ponys on the wall.

0.000000 brfluidounces of beer on the wall, 0.000000 brfluidounces.
Go to the store and buy some more, 99 bottles of beer on the wall.

[edit] FunL

val
numbers = {1:'one', 2:'two', 3:'three', 4:'four', 5:'five', 6:'six', 7:'seven',
8:'eight', 9:'nine', 10:'ten', 11:'eleven', 12:'twelve'}
alt = {3:'thir', 5:'fif'}
 
def
suffix( a, b ) = (if a.endsWith( 't' ) then a.substring( 0, a.length()-1 ) else a) + b
 
number( n@(13 | 15) ) = suffix( alt(n%10), 'teen' )
number( 20 ) = 'twenty'
number( n@(30 | 50) ) = suffix( alt(n\10), 'ty' )
number( n )
| n <= 12 = numbers(n)
| n <= 19 = suffix( numbers(n%10), 'teen' )
| 10|n = suffix( numbers(n\10), 'ty' )
| otherwise = number( n\10*10 ) + '-' + number( n%10 )
 
cap( s ) = s.substring( 0, 1 ).toUpperCase() + s.substring( 1, s.length() )
 
bottles( 0 ) = 'no more bottles'
bottles( 1 ) = 'one bottle'
bottles( n ) = number( n ) + ' bottles'
 
verse( 0 ) = ('No more bottles of beer on the wall, no more bottles of beer.\n'
+ 'Go to the store and buy some more, ninety-nine bottles of beer on the wall.')
verse( n ) = (cap( bottles(n) ) + ' of beer on the wall, ' + bottles( n ) + ' of beer.\n'
+ 'Take one down and pass it around, ' + bottles( n-1 )
+ ' of beer on the wall.\n')
 
for i <- 99..0 by -1 do println( verse(i) )

[edit] GAP

Bottles := function(n)
local line, i, j, u;
line := function(n)
s := String(n);
if n < 2 then
return Concatenation(String(n), " bottle of beer");
else
return Concatenation(String(n), " bottles of beer");
fi;
end;
for i in [1 .. n] do
j := n - i + 1;
u := line(j);
Display(Concatenation(u, " on the wall"));
Display(u);
Display("Take one down, pass it around");
Display(Concatenation(line(j - 1), " on the wall"));
if i <> n then
Display("");
fi;
od;
end;

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

[edit] Go

[edit] No sense of humor

package main
 
import "fmt"
 
func main() {
cardinality := func (i int) string {
if i!=1 {
return "s"
}
return ""
}
for i := 99; i > 0; i-- {
fmt.Printf("%d bottle%s of beer on the wall\n", i, cardinality(i))
fmt.Printf("%d bottle%s of beer\n", i, cardinality(i))
fmt.Printf("Take one down, pass it around\n")
fmt.Printf("%d bottle%s of beer on the wall\n", i-1, cardinality(i-1))
}
}

[edit] Typoglycemic

With code from RC tasks Number names, Knuth shuffle.

package main
 
import (
"fmt"
"math/rand"
"strings"
"time"
)
 
func main() {
rand.Seed(time.Now().UnixNano())
for i := 99; i > 0; i-- {
fmt.Printf("%s %s %s\n",
slur(numberName(i), i),
pluralizeFirst(slur("bottle of", i), i),
slur("beer on the wall", i))
fmt.Printf("%s %s %s\n",
slur(numberName(i), i),
pluralizeFirst(slur("bottle of", i), i),
slur("beer", i))
fmt.Printf("%s %s %s\n",
slur("take one", i),
slur("down", i),
slur("pass it around", i))
fmt.Printf("%s %s %s\n",
slur(numberName(i-1), i),
pluralizeFirst(slur("bottle of", i), i-1),
slur("beer on the wall", i))
}
}
 
// adapted from Number names task
func numberName(n int) string {
switch {
case n < 0:
case n < 20:
return small[n]
case n < 100:
t := tens[n/10]
s := n % 10
if s > 0 {
t += " " + small[s]
}
return t
}
return ""
}
 
var small = []string{"no", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen",
"fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"}
var tens = []string{"ones", "ten", "twenty", "thirty", "forty",
"fifty", "sixty", "seventy", "eighty", "ninety"}
 
// pluralize first word of s by adding an s, but only if n is not 1.
func pluralizeFirst(s string, n int) string {
if n == 1 {
return s
}
w := strings.Fields(s)
w[0] += "s"
return strings.Join(w, " ")
}
 
// p is string to slur, d is drunkenness, from 0 to 99
func slur(p string, d int) string {
// shuffle only interior letters
a := []byte(p[1 : len(p)-1])
// adapted from Knuth shuffle task.
// shuffle letters with probability d/100.
for i := len(a) - 1; i >= 1; i-- {
if rand.Intn(100) >= d {
j := rand.Intn(i + 1)
a[i], a[j] = a[j], a[i]
}
}
// condense spaces
w := strings.Fields(p[:1] + string(a) + p[len(p)-1:])
return strings.Join(w, " ")
}
Output:

Things start out pretty well...

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
ninety eight bottles of beer on the wall
ninety eight bottles of beer
take one down pass it around
ninety seven bottles of beer on the wall
ninety seven boetlts of beer on the wall
ninety seven bottles of beer
take one down pass it around
ninety six botelts of beer on the wall

Soon,

eighty four bottles of bere wn the oall
ehigty four bottles of beer
tkae one down pnssti arouad
eihhty tgree bttoles of beer en tho wall
eighty three blottes of beet on rhe wall
eighty three bottles of beer
taen oke down pass it around
eiwyth tgo bttoles of beew on lhr eatl

It ends very well, if you're drinking along.

two btloots ef bre enehta wo ll
two bs tleootf beer
tnoeka e dwon pts ou nsaaird
one bolote tf betwr le ao enhl
one beoo ttlf blwtenr ehoa el
one bltooe tf beer
tne okae down pasaostiu rnd
no bletts oof beloethw r ea nl

[edit] Go!

Copied from The 99 Bottles of Beer web site with a minor bug fix.

-- 
-- 99 Bottles of Beer in Go!
-- John Knottenbelt
--
-- Go! is a multi-paradigm programming language that is oriented
-- to the needs of programming secure, production quality, agent
-- based applications.
--
-- http://www.doc.ic.ac.uk/~klc/dalt03.html
--
 
main .. {
include "sys:go/io.gof".
include "sys:go/stdlib.gof".
 
main() ->
drink(99);
stdout.outLine("Time to buy some more beer...").
 
drink(0) -> {}.
drink(i) -> stdout.outLine(
bottles(i) <> " on the wall,\n" <>
bottles(i) <> ".\n" <>
"take one down, pass it around,\n" <>
bottles(i-1) <> " on the wall.\n");
drink(i-1).
 
bottles(0) => "no bottles of beer".
bottles(1) => "1 bottle of beer".
bottles(i) => i^0 <> " bottles of beer".
}

[edit] Gosu

 
for (i in 99..0) {
 
print("${i} bottles of beer on the wall")
 
if (i > 0) {
print("${i} bottles of beer")
print("Take one down, pass it around")
}
print("");
 
}
 

[edit] Golfscript

[296,{3/)}%-1%["No more"]+[" bottles":b]294*[b-1<]2*+[b]+[" of beer on the wall\n".8<"\nTake one down, pass it around\n"+1$n+]99*]zip

[edit] Groovy

[edit] Basic Solution

With a closure to handle special cardinalities of bottles.

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
"""

}

[edit] Single Print Version

Uses a single print algorithm for all four lines. Handles cardinality on bottles, uses 'No more' instead of 0.

298.downto(2) {
def (m,d) = [it%3,(int)it/3]
print "${m==1?'\n':''}${d?:'No more'} bottle${d!=1?'s':''} of beer" +
"${m?' on the wall':'\nTake one down, pass it around'}\n"
}

[edit] Bottomless Beer Solution

Using more closures to create a richer lyrical experience.

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)
// }

[edit] GUISS

We will just use the calculator and keep taking one off. We do not get the full text here, but the number of the calculator shows how many bottles we still have left to drink:

Start,Programs,Accessories,Calculator,Button:9,Button:9,
Button:[hyphen],Button:1,Button:[equals],Button:[hyphen],Button:1,Button:[equals],
Button:[hyphen],Button:1,Button:[equals],Button:[hyphen],Button:1,Button:[equals],
Button:[hyphen],Button:1,Button:[equals],Button:[hyphen],Button:1,Button:[equals],
Button:[hyphen],Button:1,Button:[equals],Button:[hyphen],Button:1,Button:[equals]
 

We haven't drank all of the bottles at this point, but we can keep going, if we want.

[edit] Haskell

A relatively concise solution:

main = mapM_ (putStrLn . beer) [99, 98 .. 0]
beer 1 = "1 bottle of beer on the wall\n1 bottle of beer\nTake one down, pass it around"
beer 0 = "better go to the store and buy some more."
beer v = show v ++ " bottles of beer on the wall\n"
++ show v
++" bottles of beer\nTake one down, pass it around\n"
++ head (lines $ beer $ v-1) ++ "\n"

As a list comprehension:

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"

Another version, which uses a Writer monad to collect each part of the song. It also uses Template Haskell to generate the song at compile time.

{-# 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

[edit] Haxe

[edit] Simple solution

class RosettaDemo
{
static public function main()
{
singBottlesOfBeer(100);
}
 
static function singBottlesOfBeer(bottles : Int)
{
var plural : String = 's';
 
while (bottles >= 1)
{
Sys.println(bottles + " bottle" + plural + " of beer on the wall,");
Sys.println(bottles + " bottle" + plural + " of beer!");
Sys.println("Take one down, pass it around,");
if (bottles - 1 == 1)
{
plural = '';
}
 
if (bottles > 1)
{
Sys.println(bottles-1 + " bottle" + plural + " of beer on the wall!\n");
}
else
{
Sys.println("No more bottles of beer on the wall!");
}
bottles--;
}
}
}

[edit] Macro solution

All those counters, loops and conditinal blocks are pretty expensive in runtime compared to single print of fully inlined text of the song. Let's generate that print with macro.

class Bottles {
 
static public function main () : Void {
singBottlesOfBeer(100);
}
 
 
macro static public function singBottlesOfBeer (bottles:Int) {
var lines = [];
var s : String = 's';
 
var song : String = '';
while( bottles >= 1 ){
song += '$bottles bottle$s of beer on the wall,\n';
song += '$bottles bottle$s of beer!\n';
song += 'Take one down, pass it around,\n';
 
bottles --;
 
if( bottles > 1 ){
song += '$bottles bottles of beer on the wall!\n\n';
}else if( bottles == 1 ){
s = '';
song += '$bottles bottle of beer on the wall!\n\n';
}else{
song += 'No more bottles of beer on the wall!\n';
}
}
 
return macro Sys.print($v{song});
}
 
}

[edit] HicEst

DO x = 99, 1, -1
WRITE() x , "bottles of beer on the wall"
BEEP("T16 be be be bH bH bH be be be 2be ")
 
WRITE() x , "bottles of beer"
BEEP("2p f f f c c c 2f ")
 
WRITE() "take one down, pass it around"
BEEP("2p 2d d d 2p d d d 2d ")
 
WRITE() x , "bottles of beer on the wall"
BEEP("2p #A #A #A c c d #d #d #d 2#d 2p")
ENDDO

[edit] HQ9+

9

[edit] Icon and Unicon

The default is 99 bottles, but you can change this on the command line for really long trips...

procedure main(args)
numBeers := integer(args[1]) | 99
drinkUp(numBeers)
end
 
procedure drinkUp(beerMax)
static beerMap
initial {
beerMap := table(" bottles")
beerMap[1] := " bottle"
}
 
every beerCount := beerMax to 1 by -1 do {
writes( beerCount,beerMap[beerCount]," of beer on the wall, ")
write( beerCount,beerMap[beerCount]," of beer.")
 
writes("Take one down and pass it around, ")
write(case x := beerCount-1 of {
0 : "no more bottles"
default : x||beerMap[x]
}," of beer on the wall.\n")
}
 
write("No more bottles of beer on the wall, no more bottles of beer.")
write("Go to the store and buy some more, ",
beerMax," bottles of beer on the wall.")
end

[edit] IDL

Pro bottles
 
for i=1,99 do begin
print, 100-i, " bottles of beer on the wall.", 100-i, $
" bottles of beer.", " Take one down, pass it around," , $
99-i, " bottles of beer on the wall."
endfor
End
 
 

Since in IDL "FOR"-loops are the embodiment of pure evil (see http://www.idlcoyote.com/tips/forloops.html and http://www.idlcoyote.com/tips/forloops2.html) there is also a loop free IDL way:

Pro bottles_noloop
b=(reverse(shift(sindgen(100),-1)))[1:99]
b2=reverse(sindgen(99))
wallT=replicate(' bottles of beer on the wall.', 100)
wallT2=replicate(' bottles of beer.', 100)
takeT=replicate('Take one down, pass it around,', 100)
print, b+wallT+string(10B)+b+wallT2+string(10B)+takeT+string(10B)+b2+wallT+string(10B)
End

[edit] Inform 6

[ Bottles i;
if(i == 1) return "bottle";
 
return "bottles";
];
 
[ Beer i;
print i, " ", (string) Bottles(i), " of beer on the wall^";
print i, " ", (string) Bottles(i), " of beer^";
print "Take one down, pass it around^";
i--;
print i, " ", (string) Bottles(i), " of beer on the wall^^";
 
if(i ~= 0) Beer(i);
];
 
[ Main;
Beer(99);
];
 

[edit] Inform 7

[edit] Programmatic solution

Beer Hall is a room.
 
When play begins:
repeat with iteration running from 1 to 99:
let N be 100 - iteration;
say "[N] bottle[s] of beer on the wall[line break]";
say "[N] bottle[s] of beer[line break]";
say "Take one down, pass it around[line break]";
say "[N - 1] bottle[s] of beer on the wall[paragraph break]";
end the story.

[edit] World model solution

This solution uses in-game objects to represent the wall and the bottles.

Beer Hall is a room.
 
The plural of bottle of beer is bottles of beer. A bottle of beer is a kind of thing.
 
The wall is a scenery supporter in Beer Hall. 99 bottles of beer are on the wall.
 
When play begins:
while something is on the wall:
say "[what's on the wall] on the wall[line break]";
say "[what's on the wall][line break]";
say "Take one down, pass it around[line break]";
remove a random thing on the wall from play;
say "[what's on the wall] on the wall[paragraph break]";
end the story.
 
To say what's on the wall:
if more than one thing is on the wall, say list of things on the wall;
otherwise say "[number of things on the wall in words] bottle[s] of beer".

[edit] Intercal

See 99 Bottles of Beer/Intercal

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

[edit] Ioke

bottle = method(i,
case(i,
0, "no more bottles of beer",
1, "1 bottle of beer",
"#{i} bottles of beer"))
 
(99..1) each(i,
"#{bottle(i)} on the wall, " println
"take one down, pass it around," println
"#{bottle(i - 1)} on the wall.\n" println
)

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

Output:

99 bottles of beer on the wall, 99 bottles of beer; take one down and pass it around, 98 bottles of beer on the wall
98 bottles of beer on the wall, 98 bottles of beer; take one down and pass it around, 97 bottles of beer on the wall
...
3 bottles of beer on the wall, 3 bottles of beer; take one down and pass it around, 2 bottles of beer on the wall
2 bottles of beer on the wall, 2 bottles of beer; take one down and pass it around, 1 bottle of beer on the wall
1 bottle of beer on the wall, 1 bottle of beer; take one down and pass it around, 0 bottles of beer on the wall

[edit] Java

[edit] Console

MessageFormat's choice operator is used to properly format plurals.

import java.text.MessageFormat;
public class Beer
{
static String bottles(final int n)
{
return MessageFormat.format("{0,choice,0#No more bottles|1#One bottle|2#{0} bottles} of beer", n);
}
public static void main(final 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");
}
}
}

Optimized

public class Beer
{
public static void main(final String[] args)
{
int beer = 99;
StringBuilder sb = new StringBuilder();
String data[] = new String[] { " bottles of beer on the wall\n",
" bottles of beer.\nTake one down, pass it around,\n",
"Better go to the store and buy some more." };
 
while (beer > 0)
sb.append(beer).append(data[0]).append(beer).append(data[1]).append(--beer).append(data[0]).append("\n");
 
System.out.println(sb.append(data[2]).toString());
}
}

Recursive

public class Beer
{
public static void main(String args[])
{
song(99);
}
 
public static void song(int b)
{
if(b>=0)
{
if(b>1)
System.out.println(b+" bottles of beer on the wall\n"+b+" bottles of beer\nTake one down, pass it around\n"+(b-1)+" bottles of beer on the wall.\n");
else if(b==1)
System.out.println(b+" bottle of beer on the wall\n"+b+" bottle of beer\nTake one down, pass it around\n"+(b-1)+" bottles of beer on the wall.\n");
else
System.out.println(b+" bottles of beer on the wall\n"+b+" bottles of beer\nBetter go to the store and buy some more!");
song(b-1);
}
}
}

[edit] An object-oriented solution

Translation of: C++

See: 99 Bottles of Beer/Java/Object Oriented

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

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
}
}
}

[edit] JavaScript

[edit] ES3-5

var beer = 99;
while (beer > 0) {
var verse = [
beer + " bottles of beer on the wall,",
beer + " bottles of beer!",
"Take one down, pass it around",
(beer - 1) + " bottles of beer on the wall!"
].join("\n");
 
console.log(verse);
 
beer--;
}
 

[edit] ES6

let beer = 99;
while (beer > 0) {
let verse = `${beer} bottles of beer on the wall,
${beer} bottles of beer!
Take one down, pass it around
${beer-1} bottles of beer on the wall`;
 
console.log(verse);
beer--;
}

[edit] Other Examples

More skilled solution "one-liner" with grammar check

// Line breaks are in HTML
var beer; while ((beer = typeof beer === "undefined" ? 99 : beer) > 0) document.write( beer + " bottle" + (beer != 1 ? "s" : "") + " of beer on the wall<br>" + beer + " bottle" + (beer != 1 ? "s" : "") + " of beer<br>Take one down, pass it around<br>" + (--beer) + " bottle" + (beer != 1 ? "s" : "") + " of beer on the wall<br>" );

Object Oriented

function Bottles(count) {
this.count = count || 99;
}
 
Bottles.prototype.take = function() {
var verse = [
this.count + " bottles of beer on the wall,",
this.count + " bottles of beer!",
"Take one down, pass it around",
(this.count - 1) + " bottles of beer on the wall!"
].join("\n");
 
console.log(verse);
 
this.count--;
};
 
Bottles.prototype.sing = function() {
while (this.count) {
this.take();
}
};
 
var bar = new Bottles(99);
bar.sing();

An alternative version:

function bottleSong(n) {
if (!isFinite(Number(n)) || n == 0) n = 100;
var a = '%% bottles of beer',
b = ' on the wall',
c = 'Take one down, pass it around',
r = '<br>'
p = document.createElement('p'),
s = [],
re = /%%/g;
 
while(n) {
s.push((a+b+r+a+r+c+r).replace(re, n) + (a+b).replace(re, --n));
}
p.innerHTML = s.join(r+r);
document.body.appendChild(p);
}
 
window.onload = bottleSong;

[edit] Joy

LIBRA
 
_beerlib == true ;
 
HIDE
beer == "of beer " putchars ;
wall == "on the wall" putchars ;
take1 == "Take one down and pass it around, " putchars ;
dup3 == dup dup dup ;
comma == ", " putchars ;
period == '. putch ;
bottles == [dup small]
[ [null] [pop "no more bottles " putchars] [put "bottle " putchars] ifte]
[put "bottles " putchars] ifte ;
sing-verse == dup3 bottles beer wall comma
bottles beer ".\n" putchars
take1 1 - bottles beer wall period newline newline ;
sing-verse-0 == "No more bottles of beer on the wall, no more bottles of beer\n" putchars
"Go to the store and buy some more, " putchars
99 bottles pop beer wall period newline ;
 
IN
(* n -- *)
sing-verses == [null]
[sing-verse-0]
[sing-verse 1 -] tailrec .

[edit] Julia

one-liner

for i = 99:-1:1 print("\n$i bottles of beer on the wall\n$i bottles of beer\nTake one down, pass it around\n$(i-1) bottles of beer on the wall\n") end

another solution, handling grammar cases "No more bottles", "1 bottle", "<n> bottles"

bottles(n) = n==0 ? "No more bottles" :
n==1 ? "1 bottle" :
"$n bottles"
 
for n = 99:-1:1
println("""
$(bottles(n)) of beer on the wall
$(bottles(n)) of beer
Take one down, pass it around
$(bottles(n-1)) of beer on the wall
""")
end

shorter, but more criptic, version of the previous `bottles` function

bottles(n) = "$(n==0 ? "No more" : n) bottle$(n==1 ? "" : "s")"

[edit] K

`0:\:{x[z],y,a,x[z],a,"Take one down, pass it around",a,x[z-1],y,a,a:"\n"}[{($x)," bottle",:[x=1;"";"s"]," of beer"};" on the wall"]'|1_!100

[edit] Kotlin

fun main(args : Array<String>) {
var i = 99
while (i > 0) {
 
System.out?.println("${i} bottles of beer on the wall")
System.out?.println("${i} bottles of beer")
System.out?.println("Take one down, pass it around")
i--;
}
System.out?.println("0 bottles of beer on the wall")
}
 

[edit] LabVIEW

This image is a VI Snippet, an executable image of LabVIEW code. The LabVIEW version is shown on the top-right hand corner. You can download it, then drag-and-drop it onto the LabVIEW block diagram from a file browser, and it will appear as runnable, editable code.
LabVIEW 99 Bottles of Beer.png


[edit] Lasso

[edit] Simple loop

local(
beer = 99,
song = ''
)
while(#beer > 0) => {
#song->append(
#beer + ' bottles of beer on the wall\n' +
#beer + ' bottles of beer\n' +
'Take one down, pass it around\n' +
(#beer-1) + ' bottles of beer on the wall\n\n'
)
#beer--
}
 
#song

[edit] Query Expression

(with beer in 99 to 1 by -1 select
#beer + ' bottles of beer on the wall' +
#beer + ' bottles of beer\n' +
'Take one down, pass it around\n' +
--#beer + ' bottles of beer on the wall\n'
)->join('\n')


[edit] Query Expression with Autocollect

// this example adds an "s" to bottle until there is only 1 bottle left on the wall
 
local(s = 's')
with n in 99 to 1 by -1 do {^
#n + ' bottle' + #s + ' of beer on the wall,<br>'
#n + ' bottle' + #s + ' of beer,<br>'
#n = #n - 1
#s = (#n != 1 ? 's' | '')
'Take one down, pass it around,<br>'
#n + ' bottle' + #s + ' of beer on the wall.<br><br>'
^}

[edit] LaTeX

[edit] Recursive

\documentclass{article}
 
\newcounter{beer}
 
\newcommand{\verses}[1]{
\setcounter{beer}{#1}
\par\noindent
\arabic{beer} bottles of beer on the wall,\\
\arabic{beer} bottles of beer!\\
Take one down, pass it around---\\
\addtocounter{beer}{-1}
\arabic{beer} bottles of beer on the wall!\\
\ifnum#1>0
\verses{\value{beer}}
\fi
}
 
\begin{document}
\verses{99}
\end{document
}

[edit] Iterative

The \loop macro is tail-recursive (Knuth 1984, page 219). Just for fun, this version uses Roman numerals.

\documentclass{article}
 
\newcounter{beer}
\newcounter{showC}
 
\newcommand{\verses}[1]{
\setcounter{beer}{#1}
\loop
\par\noindent
\Roman{beer} bottles of beer on the wall,\\
\Roman{beer} bottles of beer!\\
Take one down, pass it around---\\
\addtocounter{beer}{-1
}
% Romans didn't know how to write zero ;-)
\ifnum\value{beer}=0 ZERO \else\Roman{beer} \fi
bottles of beer on the wall!\\
\ifnum\value{beer}>0
\repeat
}
 
\begin{document}
\verses{99}
\end{document
}

[edit] References

  • Knuth, Donald E. (1984). The TeXbook, Addison Wesley.

[edit] lang5

: ~ 2 compress "" join ;
: verses(*)
dup " bottles of beer on the wall\n" ~ .
dup " bottles of beer\n" ~ .
"Take one down, pass it around\n" .
1 - " bottles of beer on the wall\n\n" ~ .
 ;
 
99 iota 1 + reverse verses

[edit] Lhogho

to bottle :i
if :i = 0 [output "|No more bottles of beer|]
if :i = 1 [output "|One bottle of beer|]
output word :i "| bottles of beer|
end
 
to it_one :n
if :n = 1 [output "it][output "one]
end
 
to verse :i
(print bottle :i "| on the wall,|)
(print word bottle :i ".)
(print "Take it_one :i "|down, pass it round|)
(print bottle :i - 1 "| on the wall.|)
print
end
 
to sing :i
if :i = 0
[
print "|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.|
stop
]
verse :i
sing :i - 1
end
 
;Using it:
sing 99

[edit] LiveCode

function beerMe numberOfBottles
   put "XX bottles of beer on the wall" into verseA
   put "Take one down, pass it around" into verseB
   repeat with N = numberOfBottles down to 1
      put replaceText(verseA,"XX",N) & cr & word 1 to 4 of \
replaceText(verseA,"XX",N) & cr & verseB & cr & replaceText(verseA,"XX",N-1) \
& cr & cr after theSong
   end repeat
   return theSong
end beerMe

[edit] Lisp

Bit of a beginner in Lisp, but this seems to work:

(defun beer-verse (count)
"Recurses the verses"
(format t "~A bottle~:P of beer on the wall~%" count)
(format t "~A bottle~:P of beer~%" count)
(format t "Take one down, pass it round~%")
(format t "~A bottle~A of beer on the wall~%~%"
(if (= count 1)
"No"
(- count 1))
(if (/= count 2)
"s"
""))
(if (> count 1)
(beer-verse (- count 1))))
(beer-verse 99)
 

Output (last three verses only):

3 bottles of beer on the wall
3 bottles of beer
Take one down, pass it round
2 bottles of beer on the wall

2 bottles of beer on the wall
2 bottles of beer
Take one down, pass it round
1 bottle of beer on the wall

1 bottle of beer on the wall
1 bottle of beer
Take one down, pass it round
No bottles of beer on the wall

[edit] LLVM

; "99 Bottles of Beer on the Wall" in LLVM Assembly
 
; This is not strictly LLVM, as it uses the C library function "printf".
; LLVM does not provide a way to print values, so the alternative would be
; to just load the string into memory, and that would be boring.
 
; The song lyrics are global constants.
; Lyrics for plural verses:
@pluralVerse = private constant [120 x i8]
c"%d bottles of beer on the wall, %d bottles of beer.\0ATake one down and pass it around, %d bottles of beer on the wall.\0A\0A\00"
; Lyrics for the singular verse:
@singularVerse = private constant [121 x i8]
c"1 bottle of beer on the wall, 1 bottle of beer.\0ATake one down and pass it around, no more bottles of beer on the wall.\0A\0A\00"
; Lyrics for the final verse:
@finalVerse = private constant [130 x i8]
c"No more bottles of beer on the wall, no more bottles of beer.\0AGo to the store and buy some more, %d bottles of beer on the wall.\0A\00"
 
; Initial number of bottles of beer.
; This must be a natural number.
@initialVerseNumber = private constant i32 99
 
; The declaration for the external C printf function.
declare i32 @printf(i8*, ...)
 
; Prints a verse, with %numberOfBottles being the initial number of bottles
; in that verse.
define fastcc void @printVerse(i32 %numberOfBottles) {
switch i32 %numberOfBottles,
label %pluralVerse
[ i32 1, label %singularVerse
i32 0, label %finalVerse ]
 
pluralVerse:
%pluralVersePointer = getelementptr [120 x i8]* @pluralVerse, i64 0, i64 0
%newNumberOfBottles = sub i32 %numberOfBottles, 1
call i32(i8*, ...)* @printf(
i8* %pluralVersePointer,
i32 %numberOfBottles,
i32 %numberOfBottles,
i32 %newNumberOfBottles)
ret void
 
singularVerse:
%singularVersePointer = getelementptr [121 x i8]* @singularVerse,i64 0,i64 0
call i32(i8*, ...)* @printf(i8* %singularVersePointer)
ret void
 
finalVerse:
%finalVersePointer = getelementptr [130 x i8]* @finalVerse, i64 0, i64 0
%initialVerseNumberL = load i32* @initialVerseNumber
call i32(i8*, ...)* @printf(i8* %finalVersePointer,i32 %initialVerseNumberL)
ret void
}
 
define i32 @main() {
loopHeader:
%initialVerseNumberL = load i32* @initialVerseNumber
br label %loop ; This br terminates the first basic block.
loop:
%verseNumber =
phi i32 [%initialVerseNumberL, %loopHeader], [%nextVerseNumber, %do]
%cond = icmp eq i32 -1, %verseNumber
br i1 %cond, label %break, label %do
do:
call fastcc void @printVerse(i32 %verseNumber)
%nextVerseNumber = sub i32 %verseNumber, 1
br label %loop
break:
ret i32 0
}

[edit]

to bottles :n
if :n = 0 [output [No more bottles]]
if :n = 1 [output [1 bottle]]
output sentence :n "bottles
end
to verse :n
print sentence bottles :n [of beer on the wall]
print sentence bottles :n [of beer]
print [Take one down, pass it around]
print sentence bottles :n-1 [of beer on the wall]
end
for [n 99 1] [verse :n (print)]

[edit] Logtalk

:- object(bottles).
 
:- initialization(sing(99)).
 
sing(0) :-
write('No more bottles of beer on the wall, no more bottles of beer.'), nl,
write('Go to the store and buy some more, 99 bottles of beer on the wall.'), nl, nl.
sing(N) :-
N > 0,
N2 is N -1,
beers(N), write(' of beer on the wall, '), beers(N), write(' of beer.'), nl,
write('Take one down and pass it around, '), beers(N2), write(' of beer on the wall.'), nl, nl,
sing(N2).
 
beers(0) :-
write('no more bottles').
beers(1) :-
write('1 bottle').
beers(N) :-
N > 1,
write(N), write(' bottles').
 
:- end_object.

[edit] LOLCODE

HAI 1.3
 
I HAS A bottles ITZ 99
I HAS A plural ITZ "Z"
I HAS A lyric ITZ "99 BOTTLZ OV BEER"
 
IM IN YR song
VISIBLE lyric " ON TEH WALL"
VISIBLE lyric
VISIBLE "TAEK 1 DOWN, PAZ IT AROUN"
 
bottles R DIFF OF bottles AN 1
NOT bottles, O RLY?
YA RLY, VISIBLE "NO MOAR BOTTLZ OV BEER ON TEH WALL", GTFO
OIC
BOTH SAEM bottles AN 1, O RLY?
YA RLY, plural R ""
OIC
 
lyric R SMOOSH bottles " BOTTL" plural " OV BEER" MKAY
VISIBLE lyric " ON TEH WALL:)"
IM OUTTA YR song
 
KTHXBYE

[edit] Lua

local bottles = 99
 
local function plural (bottles) if bottles == 1 then return '' end return 's' end
while bottles > 0 do
print (bottles..' bottle'..plural(bottles)..' of beer on the wall')
print (bottles..' bottle'..plural(bottles)..' of beer')
print ('Take one down, pass it around')
bottles = bottles - 1
print (bottles..' bottle'..plural(bottles)..' of beer on the wall')
print ()
end

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

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

[edit] make

[edit] BSD make

Library: jot
Works with: BSD make
START = 99
UP != jot - 2 `expr $(START) - 1` 1
 
0-bottles-of-beer: 1-bottle-of-beer
@echo No more bottles of beer on the wall!
 
1-bottle-of-beer: 2-bottles-of-beer
@echo One last bottle of beer on the wall!
@echo
@echo One last bottle of beer on the wall,
@echo One last bottle of beer,
@echo Take it down, pass it around.
 
.for COUNT in $(UP)
ONE_MORE != expr 1 + $(COUNT)
$(COUNT)-bottles-of-beer: $(ONE_MORE)-bottles-of-beer
@echo $(COUNT) bottles of beer on the wall!
@echo
@echo $(COUNT) bottles of beer on the wall,
@echo $(COUNT) bottles of beer,
@echo Take one down, pass it around.
.endfor
 
$(START)-bottles-of-beer:
@echo $(START) bottles of beer on the wall,
@echo $(START) bottles of beer.
@echo Take one down, pass it around.

Usage: make or make START=99

[edit] GNU make

Works with: GNU make version 3.81
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,"

Usage: make 99-bottles

This will fork 99 make processes. You might need to raise your process limit (ulimit -p).

[edit] GNU make

[edit] Without using a shell command to decrement the counter
Works with: GNU make version 3.81
digits:=9 8 7 6 5 4 3 2 1 0
numbers:=$(foreach x,$(filter-out 0,$(digits)),$(foreach y,$(digits),$x$y))
numbers+=$(digits)
 
bottles=bottle$(if $(findstring /1/,$@),,s)
num=$(if $(findstring /0/,$@),$(empty),$(@F))
action=$(if $(findstring /0/,$@),$(buy),$(pass))
 
beer:=of beer
wall:=on the wall
empty:=No more
pass:=Take one down and pass it around.
buy:=Go to the store and buy some more.
 
# Function to generate targets for each verse of the song.
define verse
.PHONY: $1
$1: verse/$1/$1 prelude/$2/$2 $2
 
.PHONY: $1-bottles
$1-bottles: $1
 
most?=$1
endef
 
# Recursive function that loops through the 100 numbers.
define verses
$$(eval $$(call verse,$$(word 1,$1),$$(word 2,$1)))
$$(if $$(word 2,$1),$$(eval $$(call verses,$$(filter-out $$(word 1,$1),$1))))
endef
 
# Generate the targets for the 100 numbers.
$(eval $(call verses,$(numbers)))
 
 
# Main lines in the verse.
.PHONY: verse/%
verse/%:
@echo "$(num) $(bottles) $(beer) $(wall)."
@echo "$(num) $(bottles) $(beer)."
@echo "$(action)"
 
# Last line of a verse, which is a prelude to the next verse.
.PHONY: prelude/%
prelude/%:
@echo "$(num) $(bottles) $(beer) $(wall)."
@echo ""
 
# Special target for the last line of the song.
.PHONY: prelude/
prelude/:
@echo "$(most) $(bottles) $(beer) $(wall)!"
@echo ""
 

Usage: make or make N-bottles or make N

A version of this script with more comments and an automated test can be found on github.com.

[edit] Mathematica

Bottle[n_] := ToString[n] <> If[n==1," bottle"," bottles"] <> " of beer"
 
BottleSong[n_] := Speak[
Bottle[n] <> " on the wall," <>
Bottle[n] <>
", take one down, pass it around," <>
Bottle[n-1] <> " on the wall."
]
 
BottleSong /@ Range[99,1,-1]

[edit] MATLAB

function ninetyNineBottlesOfBeer()
 
disp( [ sprintf(['%d bottles of beer on the wall, %d bottles of beer.\n'...
'Take one down, pass it around...\n'],[(99:-1:2);(99:-1:2)])...
sprintf(['1 bottle of beer on the wall, 1 bottle of beer.\nTake'...
'one down, pass it around;\nNo more bottles of beer on the wall.']) ] );
 
%The end of this song makes me sad. The shelf should always have more
%beer...like college.
 
end

[edit] Maxima

bottles(n) := for i from n thru 1 step -1 do (
printf(true, "~d bottle~p of beer on the wall~%", i, i),
printf(true, "~d bottle~p of beer~%", i, i),
printf(true, "Take one down, pass it around~%"),
printf(true, "~d bottle~p of beer on the wall~%", i - 1, i - 1),
disp(""))$
 
bottles(3);
/*
 
3 bottles of beer on the wall
3 bottles of beer
Take one down, pass it around
2 bottles of beer on the wall
 
2 bottles of beer on the wall
2 bottles of beer
Take one down, pass it around
1 bottle of beer on the wall
 
1 bottle of beer on the wall
1 bottle of beer
Take one down, pass it around
0 bottles of beer on the wall
 
*/

[edit] MAXScript

escapeEnable  = true 
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 -- this will iterate through 99 times use the escape key to terminate.
(
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
)

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

[edit] Mirah

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
 

[edit] mIRC Scripting Language

var %x = 99
while (%x) {
echo -ag %x bottles of beer on the wall
echo -ag %x bottles of beer
echo -ag Take one down, pass it around
dec %x
echo -ag %x bottles of beer on the wall
}

[edit] ML/I

[edit] Simple iterative version

MCSKIP "WITH" NL
"" 99 bottles - simple iterative version
MCSKIP MT,<>
MCINS %.
"" Macro to generate singular or plural bottle(s)
MCDEF BOT WITHS () AS <bottle<>MCGO L0 IF %A1. EN 1
s>
"" Main macro - argument is initial number of bottles
MCDEF BOTTLES NL AS <MCSET T1=%A1.
%L1.%T1. BOT(%T1.) of beer on the wall
%T1. BOT(%T1.) of beer
Take one down, pass it around
MCSET T1=T1-1
%T1. BOT(%T1.) of beer on the wall
MCGO L0 IF T1 EN 0
 
MCGO L1
>
"" Do it
BOTTLES 99

[edit] Recursive version

MCSKIP "WITH" NL
"" 99 bottles - recursive version
MCSKIP MT,<>
MCINS %.
"" Macro to generate singular or plural bottle(s)
MCDEF BOT WITHS () AS <bottle<>MCGO L0 IF %A1. EN 1
s>
"" Main macro - recurses for each verse - argument is initial number of bottles
MCDEF BOTTLES NL AS <MCSET T1=%A1.
%T1. BOT(%T1.) of beer on the wall
%T1. BOT(%T1.) of beer
Take one down, pass it around
MCSET T1=T1-1
%T1. BOT(%T1.) of beer on the wall
MCGO L0 IF T1 EN 0
 
BOTTLES %T1.
>
"" Do it
BOTTLES 99


[edit] Macro Processing generalized version in 99 lines

This version demonstrates the macro text replacement capabilities central to ML/I.

The code defines a macro

Sing n containers of contents somewhere : deed ! replenish .

where the text (macro call)

Sing 99 bottles of beer on the wall: Take one down, pass it around ! Go to the store and buy some more .

is macro substituted with the specified 99 bottles of beer song. The text

Sing 7 bottles of Armagnac on the table: Take a swig, throw it down ! Emilie vists, she brings some more .

would be substituted with a shorter, more expensive, less social and sexier lyric.

Internal macros define English word replacements for decimal numbers from 0 to 99.

 
MCSKIP - WITH - NL
-- The line above defines the comment syntax: -- through to newline is completely deleted.
-- 99 Bottles of beer in 99 lines of ML/I by Parzival Herzog.
-- ML/I is P.J. Brown's famous general purpose macro processor designed in 1967.
--
-- Define nestable quotes {...}, replaced by the unevaluated text within:
MCSKIP MT, {}
-- Define non-nestable quotes "...", replaced by the unevaluated text within:
MCSKIP T, ""
-- Define the argument insertion and expression evaluation syntax:
-- ?e. is replaced by the value of macro expression e:
MCINS ?.
--
-- Top level macro: Sing N CONTAINERS of CONTENTS SOMEWHERE : DO THE DEED! REPLENISH.
MCDEF "Sing WITH SPACE SPACE of WITH SPACE SPACE  :  ! ." AS --
{MCDEF "CONTAINERS" AS "{"?A2."}"
MCDEF "CONTAINER" AS "{"MCSUB(CONTAINERS,1,-1)"}"
MCDEF "CONTENTS" AS "{"?A3."}"
MCDEF "SOMEWHERE" AS "{"?A4."}"
MCDEF "DO WITHS THE WITHS DEED" AS "{"?A5."}"
MCDEF "REPLENISH" AS "{"?A6."}"
MCSET T1 = ?A1.
MCDEF "n" AS "("?T1.")"
MCDEF "N" AS "{"n"}"
?L1.n of CONTENTS SOMEWHERE,
n of CONTENTS.
MCGO L2 UNLESS ?T1. GR 0
MCSET T1 = T1 - 1
MCDEF "n" AS "("?T1.")"
DO THE DEED:
n of CONTENTS SOMEWHERE.
 
MCGO L1
?L2.REPLENISH:
N of CONTENTS SOMEWHERE!}
--
-- (n): Wordify 0 to 99 CONTAINERS
MCDEF "()" AS {MCSET T1=?A1.
MCGO L1 UNLESS T1 GR 99
?T1. CONTAINERS-- Return the decimal number instead of words.
MCGO L0
?L1.MCGO L2 IF T1 GR 9
MCDEF "0units" AS ?T1."Unit"
MCGO L3
?L2.MCSET T3 = T1 - T1/10*10
MCDEF "0units" AS ?T3."unit"
MCSET T1 = T1 / 10
MCDEF "0tens" AS ?T1."Ten"
0tens?L3.0units CONTAINERS}
-- Exceptions:
MCDEF "(WITH 0 WITH)" AS {"No more" CONTAINERS}
MCDEF "(WITH 1 WITH)" AS {"One more" CONTAINER}
MCDEF "(WITH 11 WITH)" AS {"Eleven" CONTAINERS}
MCDEF "(WITH 12 WITH)" AS {"Twelve" CONTAINERS}
MCDEF "(WITH 13 WITH)" AS {"Thirteen" CONTAINERS}
MCDEF "(WITH 14 WITH)" AS {"Fourteen" CONTAINERS}
MCDEF "(WITH 15 WITH)" AS {"Fifteen" CONTAINERS}
MCDEF "(WITH 16 WITH)" AS {"Sixteen" CONTAINERS}
MCDEF "(WITH 17 WITH)" AS {"Seventeen" CONTAINERS}
MCDEF "(WITH 18 WITH)" AS {"Eighteen" CONTAINERS}
MCDEF "(WITH 19 WITH)" AS {"Nineteen" CONTAINERS}
-- Regular cases:
MCDEF "2Unit" AS {"Two"}
MCDEF "3Unit" AS {"Three"}
MCDEF "4Unit" AS {"Four"}
MCDEF "5Unit" AS {"Five"}
MCDEF "6Unit" AS {"Six"}
MCDEF "7Unit" AS {"Seven"}
MCDEF "8Unit" AS {"Eight"}
MCDEF "9Unit" AS {"Nine"}
MCDEF "0unit" AS
MCDEF "1unit" AS {" one"}
MCDEF "2unit" AS {" two"}
MCDEF "3unit" AS {" three"}
MCDEF "4unit" AS {" four"}
MCDEF "5unit" AS {" five"}
MCDEF "6unit" AS {" six"}
MCDEF "7unit" AS {" seven"}
MCDEF "8unit" AS {" eight"}
MCDEF "9unit" AS {" nine"}
MCDEF "1Ten" AS {"Ten"}
MCDEF "2Ten" AS {"Twenty"}
MCDEF "3Ten" AS {"Thirty"}
MCDEF "4Ten" AS {"Forty"}
MCDEF "5Ten" AS {"Fifty"}
MCDEF "6Ten" AS {"Sixty"}
MCDEF "7Ten" AS {"Seventy"}
MCDEF "8Ten" AS {"Eighty"}
MCDEF "9Ten" AS {"Ninety"}
--
-- The specified song:
Sing 99 bottles of beer on the wall: Take one down, pass it around! --
Go to the store and buy some more.
--
--
-- Try uncommenting the next two lines:
-- Sing 7 flasks of Armagnac on the table: Take a swig, throw it down!
-- Emilie vists, she brings some more.
 

[edit] Usage:

ml1 "Bottles of Beer.ml1"


[edit] Output:

 
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.
 
Ninety eight bottles of beer on the wall,
Ninety eight bottles of beer.
Take one down, pass it around:
Ninety seven bottles of beer on the wall.
 
...
 
 
One more bottle of beer on the wall,
One more bottle of beer.
Take one down, pass it around:
No more bottles of beer on the wall.
 
No more bottles of beer on the wall,
No more bottles of beer.
Go to the store and buy some more:
Ninety nine bottles of beer on the wall!
 
 

[edit] Modula-2

MODULE b99;
IMPORT InOut;
 
VAR nr : CARDINAL;
 
BEGIN
nr := 99;
REPEAT
InOut.WriteCard (nr, 4);
InOut.WriteString (" bottles of beer on the wall");
InOut.WriteLn;
InOut.WriteCard (nr, 4);
InOut.WriteString (" bottles of beer");
InOut.WriteLn;
InOut.WriteString ("Take one down, pass it around");
InOut.WriteLn;
DEC (nr);
InOut.WriteCard (nr, 4);
InOut.WriteString (" bottles of beer on the wall");
InOut.WriteLn;
InOut.WriteLn
UNTIL nr = 0
END b99.

[edit] Modula-3

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.

[edit] Monkey

Tic's every one and a half seconds and sings(text's) the song out.

 
 
Import mojo
 
Function Main ()
New NintyNineBottles
End
 
 
Class NintyNineBottles Extends App
 
Field _bottles:Int = 99
Field _y:Int=640
Field tic:Int
Field duration:Int = 1500
Field lyric:Int = 1
Method OnCreate ()
SetUpdateRate 60
End
 
' Stuff to do while running...
Method OnUpdate ()
If Millisecs()-Self.tic > Self.duration
Self.tic=Millisecs()
If Self.lyric= 4 Then Self._bottles-=1
Self.lyric+=1
 
 
End If
End
 
' Drawing code...
 
Method OnRender ()
Cls
 
Select Self.lyric
Case 1
DrawText(_bottles+" bottles of beer on the wall",10,10)
Case 2
DrawText(_bottles+" bottles of beer",10,10)
Case 3
If Self._bottles > 1
DrawText("take one down",10,10)
Else
DrawText("take it down",10,10)
End If
Case 4
DrawText("Pass it around",10,10)
Case 5
If Self._bottles>0
DrawText(Self._bottles+" bottles of beer on the wall",10,10)
Else
DrawText("no more bottles of beer on the wall",10,10)
End If
Case 6
If Self._bottles>0
Self.lyric=1'DrawText(Self._bottles+" bottles of beer on the wall",10,10)
Else
DrawText("no more bottles of beer",10,10)
End if
Case 7
DrawText("go to the store",10,10)
 
Case 8
DrawText("and buy some more",10,10)
Case 9
Self._bottles=99
DrawText(_bottles+" more bottles of beer on the wall",10,10)
Case 10
Self.lyric=1
End Select
 
End
 
 
End
 
 
 

[edit] MOO

bottles = 99;
while (bottles > 0)
unit = (bottles == 1 ? "bottle" | "bottles");
player:tell(bottles, " ", unit, " of beer on the wall.");
player:tell(bottles, " ", unit, " of beer.");
player:tell("Take one down, pass it around.");
bottles = bottles - 1;
endwhile
player:tell("0 bottles of beer on the wall.");

[edit] MoonScript

p = (i) ->
i != 1 and 's' or ''
 
for b = 99,1,-1
for i = 1,4
print if i == 3
'Take one down, pass it around'
else
string.format '%s bottle%s of beer%s',
i < 4 and b or b-1,
i < 4 and (p b) or (p b-1),
i%3 == 1 and ' on the wall' or ''
io.write '\n'

[edit] MUMPS

[edit] Recursive

beer(n)	If n<1 Write "No bottles of beer on the wall... " Quit
Write !!,n," bottle",$Select(n=1:"",1:"s")," of beer on the wall."
Write !,n," bottle",$Select(n=1:"",1:"s")," of beer."
Write !,"Take one down, pass it around."
Do beer(n-1)
Quit
 
Do beer(99)

[edit] Iterative

beer(n)	If n<1 Write "No bottles of beer on the wall... " Quit
Write !!,n," bottle",$Select(n=1:"",1:"s")," of beer on the wall."
Write !,n," bottle",$Select(n=1:"",1:"s")," of beer."
Write !,"Take one down, pass it around."
Quit
 
For ii=99:-1:0 Do beer(ii)

[edit] NASL

bottles = 99;
repeat {
display(bottles, ' bottles of beer on the wall\n');
display(bottles, ' bottles of beer\n');
display('Take one down, pass it around\n');
display(--bottles, ' bottles of beer on the wall\n\n');
} until bottles < 1;

[edit] Nemerle

using System;
using System.Console;
 
module Bottles
{
Sing(x : int, bev = "beer", surface = "wall") : void
{
match(x)
{
|0 => WriteLine($"No more bottles of $bev on the $surface, no more bottles of $bev");
WriteLine($"Go to the store and get some more $bev, 99 bottles of $bev on the $surface")
|1 => WriteLine($"One bottle of $bev on the $surface, one bottle of $bev");
WriteLine($"Take it down, pass it around, no more bottles of $bev on the $surface")
|_ => WriteLine($"$x bottles of $bev on the $surface, $x bottles of $bev");
WriteLine($"Take one down and pass it around, $(x-1) bottles of $bev on the $surface")
}
}
 
Main() : void
{
foreach (i in [99, 98 .. 0])
Sing(i)
}
}

[edit] NetRexx

 
beer = "bottles of beer on the wall"
removeOne = "Take one down, pass it arround,"
say 99 beer","
say 99 beer.subword(1,3)","
loop i = 98 to 2 by -1
say removeOne
say i beer"."
say
say i beer","
say i beer.subword(1,3)","
end
lastCall = "bottle" beer.delword(1,1)
say removeOne
say i lastCall"."
say
say i lastCall","
say i lastCall.subword(1,3)","
say removeOne
say "No more" beer
 

[edit] NewLISP

(for (n 99 1) 
(println n " bottles of beer on the wall," n " bottles of beer. Take one down, pass it around. ")
(println (- n 1) "bottles of beer on the wall!"))
 
;;recursive
;;also shows list afterword
(define (rec bottles)
(if (!= 0 bottles) (print "/n" bottles " bottles of beer on the wall" bottles " bottles of beer.
\nTake one down, pass it around, "
(- bottles 1)
" bottles of beer on the wall" (rec ( - bottles 1))))(list bottles))
 
(rec 99)

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

[edit] Nimrod

proc GetBottleNumber(n: int): string =
var bs: string
if n == 0:
bs = "No more bottles"
elif n == 1:
bs = "1 bottle"
else:
bs = $n & " bottles"
return bs & " of beer"
 
for bn in countdown(99, 1):
var cur = GetBottleNumber(bn)
echo(cur, " on the wall, ", cur, ".")
echo("Take one down and pass it around, ", GetBottleNumber(bn-1), " on the wall.\n")
 
echo "No more bottles of beer on the wall, no more bottles of beer."
echo "Go to the store and buy some more, 99 bottles of beer on the wall."

other:

from strutils import format
 
for i in countdown(99, 1):
case i
of 3..99:
echo format("""$1 bottles of beer on the wall
$1 bottles of beer
Take one down, pass it around
$2 bottles of beer on the wall""", i, i-1)
of 2:
echo format("""$1 bottles of beer on the wall
$1 bottles of beer
Take one down, pass it around
$2 bottle of beer on the wall""", i, i-1)
of 1:
echo format("""$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""", i)
else:
discard

compact:

from strutils import format
 
proc pluralize(a: int): string =
if a > 1 or a == 0: return "s"
else: return ""
 
for i in countdown(99, 1):
echo format("""$1 bottle$3 of beer on the wall
$1 bottle$3 of beer
Take one down, pass it around
$2 bottle$4 of beer on the wall""", i, i-1, pluralize(i), pluralize(i-1))

organized:

from strutils import format
 
var verse = """$1 bottle$3 of beer on the wall
$1 bottle$3 of beer
Take one down, pass it around
$2 bottle$4 of beer on the wall"""
 
proc pluralize(a: int): string =
if a > 1 or a == 0: return "s"
else: return ""
 
for i in countdown(99, 1):
echo format(verse, i, i-1, pluralize(i), pluralize(i-1))

[edit] Objective-C

#import <Foundation/Foundation.h>
 
int main()
{
@autoreleasepool {
int bottles = 99;
do
{
NSLog(@"%i bottles of beer on the wall\n", bottles);
NSLog(@"%i bottles of beer\n", bottles);
NSLog(@"Take one down, pass it around\n");
NSLog(@"%i bottles of beer on the wall\n\n", --bottles);
} while (bottles > 0);
 
}
return 0;
}

[edit] Oberon-2

MODULE b99;
 
IMPORT Out;
 
VAR nr : INTEGER;
 
BEGIN
nr := 99;
REPEAT
Out.Int (nr, 4);
Out.String (" bottles of beer on the wall");
Out.Ln;
Out.Int (nr, 4);
Out.String (" bottles of beer");
Out.Ln;
Out.String ("Take one down, pass it around");
Out.Ln;
DEC (nr);
Out.Int (nr, 4);
Out.String (" bottles of beer on the wall");
Out.Ln;
Out.Ln
UNTIL nr = 0
END b99.

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

Recursive version that handles plurals.

let verse n = 
let
line2 = function
| 0 -> "No more bottles of beer"
| 1 -> "1 bottle of beer"
| n -> string_of_int n ^ " bottles of beer"
in
let
line1or4 y = line2 y ^ " on the wall"
in
let
line3 = function
| 1 -> "Take it down, pass it around"
| _ -> "Take one down, pass it around"
in
line1or4 n ^ "\n" ^
line2 n ^ "\n" ^
line3 n ^ "\n" ^
line1or4 (n-1) ^ "\n";;
 
let rec beer n =
print_endline (verse n);
if n > 1 then beer (n-1);;
 
beer 99;;

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

[edit] OOC

 
sing_line: func (b: Int, suffix: Bool) {
"#{b > 0 ? "#{b}" : "No more"} bottle#{b == 1 ? "" : "s"}" print()
" of beer#{suffix ? " on the wall" : ""}" println()
}
 
sing_verse: func (b: Int) {
println()
sing_line(b, true)
sing_line(b, false)
if (b > 0) {
"Take one down, pass it around" println()
} else {
"Go to the store and buy some more" println()
b += 100
}
sing_line(b-1, true)
}
 
main: func {
b := 100
while (b > 0) {
sing_verse(--b)
}
}
 

[edit] ooRexx

The rexx example below runs unchanged on ooRexx

[edit] OpenEdge/Progress

DEFINE VARIABLE amountofbottles AS INTEGER NO-UNDO INITIAL 99.
&GLOBAL-DEFINE bbm bottles OF beer
&GLOBAL-DEFINE bbs bottle OF beer
&GLOBAL-DEFINE otw ON the wall
&GLOBAL-DEFINE tow Take one DOWN AND pass it around,
&GLOBAL-DEFINE gts Go TO the store AND buy some more,
FUNCTION drinkBottle RETURNS INTEGER PRIVATE (INPUT bc AS INTEGER) FORWARD.
 
OUTPUT TO OUTPUT.txt.
drinkBottle(amountofbottles).
OUTPUT CLOSE.
 
FUNCTION drinkBottle RETURNS INTEGER.
IF bc >= 0 THEN DO:
CASE bc:
WHEN 2 THEN
PUT UNFORMATTED bc " {&bbm} {&otw}, " bc " {&bbm}" SKIP
"{&tow} " bc - 1 " {&bbs} {&otw}" SKIP.
WHEN 1 THEN
PUT UNFORMATTED bc " {&bbs} {&otw}, " bc " {&bbs}" SKIP
"{&tow} no more {&bbm} {&otw}" SKIP.
WHEN 0 THEN
PUT UNFORMATTED "no more" " {&bbm} {&otw}, no more {&bbm}" SKIP
"{&gts} " amountofbottles " {&bbm} {&otw}" SKIP.
OTHERWISE
PUT UNFORMATTED bc " {&bbm} {&otw}, " bc " {&bbm}" SKIP
"{&tow} " bc - 1 " {&bbm} {&otw}" SKIP.
END CASE.
drinkBottle(bc - 1).
RETURN bc.
END.
RETURN 0.
END FUNCTION.

[edit] Order

These examples are taken directly from a much longer tutorial in the Order documentation, which explains the construction of the solution to this problem in great detail.

[edit] "Pure" Order

This solution uses only Order language constructs to generate and manipulate tokens:

#include "order/interpreter.h"
 
ORDER_PP
(8let((8B, 8fn(8N,
8cond((8greater(8N, 1),
8separate(8N, 8quote(bottles)))
(8equal(8N, 1),
8quote(1 bottle))
(8else,
8quote(no more bottles))))),
8for_each_in_range
(8fn(8N,
8print(8ap(8B, 8N) (of beer on the wall,) 8space
8ap(8B, 8N) (of beer,) 8space
(take one down, pass it around,) 8space
8ap(8B, 8dec(8N)) (of beer on the wall.))),
100, 1)))

[edit] C Preprocessor

...but since most of the logic is simple substitution, it makes more sense (and is significantly more efficient) to make the C Preprocessor do most of the work without the help of the Order interpreter. This version shows how to integrate normal C Preprocessor macros into an Order program:

#include "order/interpreter.h"
 
#define GEN_phrase(N_bottles, N_minus_1_bottles) \
N_bottles of beer on the wall, \
N_bottles of beer, take one down, pass it around, \
N_minus_1_bottles of beer on the wall.

 
#define ORDER_PP_DEF_8bottles \
ORDER_PP_FN(8fn(8N, \
8cond((8greater(8N, 1), \
8separate(8N, 8quote(bottles))) \
(8equal(8N, 1), \
8quote(1 bottle)) \
(8else, \
8quote(no more bottles)))))

 
ORDER_PP(8for_each_in_range
(8fn(8N,
8emit(8quote(GEN_phrase),
8tuple(8bottles(8N),
8bottles(8dec(8N))))),
100, 1))
 
#undef GEN_phrase

Either example could obviously also form the core of a C solution (demonstrating the intended use of Order).

[edit] Oxygene

 
namespace ConsoleApplication2;
 
interface
 
type
ConsoleApp = class
public
class method Main(args: array of String);
end;
 
implementation
 
method bottles(number: Integer): String;
begin
if (number = 1) then
Result := "bottle"
else
Result := "bottles";
end;
 
class method ConsoleApp.Main(args: array of String);
begin
for n: Integer := 99 downto 1 do
begin
Console.WriteLine("{0} {1} of beer on the wall,",n,bottles(n));
Console.WriteLine("{0} {1} of beer,",n,bottles(n));
Console.WriteLine("Take one down, and pass it around,");
Console.WriteLine("{0} {1} of beer on the wall.",n-1,bottles(n-1));
Console.WriteLine();
end;
Console.ReadKey();
end;
 
end.
 


[edit] Oz

[edit] Constraint Programming

Note: In real life, you would never solve a simple iterative task like this with constraint programming. This is just for fun.

declare
%% describe the possible solutions of the beer 'puzzle'
proc {BeerDescription Solution}
N = {FD.int 1#99} %% N is an integer in [1, 99]
in
%% distribute starting with highest value
{FD.distribute generic(value:max) [N]}
 
Solution =
{Bottles N}#" of beer on the wall\n"#
{Bottles N}#" bottles of beer\n"#
"Take one down, pass it around\n"#
{Bottles N-1}#" of beer on the wall\n"
end
 
%% pluralization
proc {Bottles N Txt}
cond N = 1 then Txt ="1 bottle"
else Txt = N#" bottles"
end
end
in
%% show all solutions to the 'puzzle'
{ForAll {SearchAll BeerDescription}
System.showInfo}

[edit] Iterative

declare
fun {Bottles N}
if N == 1 then "1 bottle"
else N#" bottles"
end
end
in
for I in 99..1;~1 do
{System.showInfo
{Bottles I}#" of beer on the wall\n"#
{Bottles I}#" bottles of beer\n"#
"Take one down, pass it around\n"#
{Bottles I-1}#" of beer on the wall\n"}
end

[edit] PARI/GP

forstep(n=99,3,-1,
print(n" bottles of beer on the wall");
print(n" bottles of beer");
print("Take one down, pass it around");
print(n-1," bottles of beer on the wall\n")
);
print("2 bottles of beer on the wall\n2 bottles of beer\nTake one down, pass it around\n1 bottle of beer on the wall\n");
print("1 bottle of beer on the wall\n1 bottle of beer\nTake one down, pass it around\nNo more bottles of beer on the wall")

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

[edit] Perl

#!/usr/bin/perl -w
 
my $verse = <<"VERSE";
100 bottles of beer on the wall,
100 bottles of beer!
Take one down, pass it around!
99 bottles of beer on the wall!
 
VERSE

 
{
$verse =~ s/(\d+)/$1-1/ge;
$verse =~ s/\b1 bottles/1 bottle/g;
my $done = $verse =~ s/\b0 bottle/No bottles/g; # if we make this replacement, we're also done.
 
print $verse;
redo unless $done;
}

Alternatively:

for $n (reverse(0..99))
{
$bottles = sprintf("%s bottle%s of beer on the wall\n",(($n==0)?"No":$n), (($n==1)?"":"s"));
print( (($n==99)?"":"$bottles\n") .
(($n==0)?"":(substr(${bottles}x2,0,-12) . "\nTake one down, pass it around\n")) );
}

Correct grammar and nice spacing in modern perl:

use 5.10.0;                                                                        
 
$num = 99;
while ($num > 0) {
my $s = "s" unless ($num == 1);
say "$num bottle$s of beer on the wall, $num bottle$s of beer";
$num--;
my $s = "s" unless ($num == 1);
$num = "No more" if ($num == 0);
say "Take one down, pass it around, $num bottle$s of beer on the wall\n"
}
 
say "No more bottles of beer on the wall, no more bottles of beer.";
say "Go to the store and buy some more, 99 bottles of beer on the wall.";

Using perl5 as a DSL factory leveraging $_'s global nature:

 
#!/usr/bin/env perl
use strict;
use warnings;
 
sub bottles() { sprintf qq{%s bottle%s of beer}
, $_ || 'No'
, $_==1 ? '' : 's';
}
sub store() { $_=99; qq{Go to the store, buy some more...\n}; }
sub wall() { qq{ on the wall\n} }
sub take() { $_-- ? qq{Take one down, pass it around\n} : store }
do { print bottles, wall
, bottles, qq{\n}
, take
, bottles, qq{\n\n}
} for reverse 0..99;

[edit] Perl 6

[edit] A Simple Way

my $b = 99;
 
sub b($b) {
"$b bottle{'s'.substr($b == 1)} of beer";
}
 
repeat while --$b {
.say for "&b($b) on the wall",
b($b),
'Take one down, pass it around',
"&b($b-1) on the wall",
'';
}
 

[edit] A Clearer Way

Similar to "A Simple Way", but with proper variable and subroutine naming, declarator documentation, strongly-typed function definition, default parameters, better code reuse, and clearer external ternary logic instead of misusing substr side-effects within an interpolated string.

 
#= Sings a verse about a certian number of beers, possibly on a wall.
sub sing(
Int $number, #= Number of bottles of beer.
Bool $has_wall = False #= Mention that the beers are on a wall?
) {
my $quantity = $number == 0 ?? "No more" !! $number;
my $plural = $number == 1 ?? "" !! "s";
my $wall = $has_wall ?? " on the wall" !! "";
return "{$quantity} bottle{$plural} of beer{$wall}"
}
 
for 99...1 -> $bottles {
.say for
sing($bottles, True),
sing($bottles),
"Take one down, pass it around",
sing($bottles-1, True),
"";
}
 

[edit] A More Extravagant Way

Works with: Rakudo version #22 "Thousand Oaks"
my @quantities = (99 ... 1), 'No more', 99;
my @bottles = 'bottles' xx 98, 'bottle', 'bottles' xx 2;
my @actions = 'Take one down, pass it around' xx 99,
'Go to the store, buy some more';
 
for @quantities Z @bottles Z @actions Z
@quantities[1 .. *] Z @bottles[1 .. *]
-> $a, $b, $c, $d, $e {
say "$a $b of beer on the wall";
say "$a $b of beer";
say $c;
say "$d $e of beer on the wall\n";
}

[edit] PHL

Translation of: C
module bottles;
extern printf;
 
@Integer main [
@Integer bottles = 99;
do
{
printf("%u bottles of beer on the wall\n", bottles);
printf("%u bottles of beer\n", bottles);
printf("Take one down, pass it around\n");
bottles = bottles::dec;
printf("%u bottles of beer on the wall\n\n", bottles);
} while(bottles > 0);
return 0;
]

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

[edit] shorter way

<?php
foreach(range(99,1) as $i) {
$p = ($i>1)?"s":"";
echo <<< EOV
$i bottle$p of beer on the wall
$i bottle$p of beer
Take one down, pass it around
 
 
EOV
;
}
echo "No more Bottles of beer on the wall";
?>

[edit] modifing way:

<?php
$verse = <<<VERSE
100 bottles of beer on the wall,
100 bottles of beer!
Take one down, pass it around!
99 bottles of beer on the wall!
 
 
VERSE
;
 
foreach (range(1,99) as $i) { // loop 99 times
$verse = preg_replace('/\d+/e', '$0 - 1', $verse);
$verse = preg_replace('/\b1 bottles/', '1 bottle', $verse);
$verse = preg_replace('/\b0 bottle/', 'No bottles', $verse);
 
echo $verse;
}
?>

[edit] ultra compact alternative

supports grammar and has no leading and trailing new lines or spaces. Also one does not have to close the <?php tag, it is even recommended not to close it, if closing it is not necessary

<?php
for($i=100;$i>0;$i--){
$p2=$i." bottle".(($i>1)?"s":"")." of beer";
$p1=$p2." on the wall\n";
$p3="Take one down, pass it around\n";
echo (($i<100)?$p1."\n":"").$p1.$p2."\n".$p3.(($i<2)?($i-1).substr($p1,1,28):"");
}

[edit] gettext alternative

supports grammar and translations.

<?php
 
$bottles = 99;
 
while ($bottles > 0) {
printf(ngettext('%d bottle', '%d bottles', $bottles) . " of beer on the wall\n", $bottles); //X bottles of beer on the wall
printf(ngettext('%d bottle', '%d bottles', $bottles) . " of beer\n", $bottles); //X bottles of beer
printf("Take one down, pass it around\n"); //Take one down, pass it around
 
$bottles--;
 
if ($bottles > 0) {
printf(ngettext('%d bottle', '%d bottles', $bottles) . " of beer on the wall\n\n", $bottles); //X bottles of beer on the wall
}
}
printf('No more bottles of beer on the wall'); //No more bottles of beer on the wall

[edit] PicoLisp

(de bottles (N)
(case N
(0 "No more beer")
(1 "One bottle of beer")
(T (cons N " bottles of beer")) ) )
 
(for (N 99 (gt0 N))
(prinl (bottles N) " on the wall,")
(prinl (bottles N) ".")
(prinl "Take one down, pass it around,")
(prinl (bottles (dec 'N)) " on the wall.")
(prinl) )

[edit] Piet

see image

[edit] Pike

int main(){
for(int i = 99; i > 0; i--){
write(i + " bottles of beer on the wall, " + i + " bottles of beer.\n");
write("Take one down and pass it around, " + (i-1) + " bottles of beer on the wall.\n\n");
}
write("No more bottles of beer on the wall, no more bottles of beer.\n");
write("Go to the store and buy some more, 99 bottles of beer on the wall.\n");
}

alternate version:

// disclaimer: i prefer gingerale
 
void main()
{
array numbers = ({ "no more", "one", "two", "three", "four", "five", "six", "seven",
"eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen",
"fifteen", "sixteen", "seventeen", "eighteen", "nineteen" });
array decades = ({ "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty",
"ninety" });
 
foreach (decades;; string decade)
{
numbers += decade+(({ "" }) + numbers[1..9])[*];
}
numbers = reverse(numbers);
 
array bottles = ((numbers[*]+" bottles of ale on the wall, ")[*] +
(numbers[*]+" bottles of ale.\n")[*]);
 
bottles[-2] = replace(bottles[-2], "one bottles", "one bottle");
 
string song = bottles * "take one down, pass it around,\n";
write(song);
}

[edit] PIR

Works with: Parrot version Tested with 2.4.0
.sub sounding_smart_is_hard_after_drinking_this_many
.param int b
if b == 1 goto ONE
.return(" bottles ")
ONE:
.return(" bottle ")
end
.end
 
.sub main :main
.local int bottles
.local string b
bottles = 99
LUSH:
if bottles == 0 goto DRUNK
b = sounding_smart_is_hard_after_drinking_this_many( bottles )
print bottles
print b
print "of beer on the wall\n"
print bottles
print b
print "of beer\nTake one down, pass it around\n"
dec bottles
b = sounding_smart_is_hard_after_drinking_this_many( bottles )
print bottles
print b
print "of beer on the wall\n\n"
goto LUSH
DRUNK:
end
.end

[edit] PlainTeX

\def\ifbeer{\ifnum\number\bottles}
\def\beers{
\par\ifbeer>0 \the\bottles~\else No more \fi
bottle\ifbeer=1\else s\fi~of beer%
}
 
\def\take #1 down,{
\par\advance\bottles by -#1
Take #1 down, pass it around,\par
}
 
\long\def\verse{
\beers~on the wall, \beers.
\take 1 down, % curious TeX \def syntax
\beers~on the wall.
\bigskip
}
 
\newcount\bottles\bottles99
\loop\verse
\ifnum\number\bottles>0\repeat
 
\bye

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

[edit] PostScript

%!PS
/Helvetica findfont 9 scalefont setfont
 
/printBeer {
dup
20 string cvs show
( bottle) show
1 ne
{ (s) show } if
( of beer) show
} def
 
/printVerse {
dup
dup
dup
7 mul
50 add
/yPos exch def
15 yPos moveto
printBeer
( on the wall, ) show
printBeer
(. ) show
(Take one down, pass it around, ) show
1 sub
printBeer
( on the wall. ) show
} def
 
/song {
100 -1 1 { printVerse } for
} def
 
song
showpage
%%EOF

[edit] PowerShell

[edit] A standard impementation using a For loop

for($n=99; $n -gt 0; $n--) {
"$n bottles of beer on the wall"
"$n bottles of beer"
"Take one down, pass it around"
[string]($n-1) + " bottles of beer on the wall"
""
}


[edit] My standard implementation using for loop

[int]$i = 99;
for($i=99; $i -gt 0; $i--) {
write-host $i " bottles of beer on the wall";
write-host $i " bottles of beer";
write-host "Take one down, pass it around"
write-host ($i-1) " bottles of beer on the wall"
write-host ""
}
 

[edit] Consolidating the static text and using a Do...while loop

$n=99
do {
"{0} bottles of beer on the wall`n{0} bottles of beer`nTake one down, pass it around`n{1} bottles of beer on the wall`n" -f $n, --$n
} while ($n -gt 0)

[edit] Consolidating the static text and using a Do...until loop

$n=99
do {
"{0} bottles of beer on the wall`n{0} bottles of beer`nTake one down, pass it around`n{1} bottles of beer on the wall`n" -f $n, --$n
} until ($n -eq 0)


[edit] Consolidating the static text even more

$s = "{0} bottles of beer on the wall`n{0} bottles of beer`nTake one down, pass it around`n{1} bottles of beer on the wall`n"
$n=99
do { $s -f $n, --$n } while ($n -gt 0)

[edit] Using the Pipeline

99..1 | ForEach-Object { 
$s=$( if( $_ -ne 1 ) { 's' } else { '' } )
$s2=$( if( $_ -ne 2 ) { 's' } else { '' } )
"$_ bottle$s of beer on the wall`n$_ bottle$s of beer`nTake one down`npass it around`n$( $_ - 1 ) bottle$s2 of beer on the wall`n"}

[edit] ProDOS

editvar /newvar /value=a=99
:a
printline -a- bottles of beer on the wall
printline -a- bottles of beer
printline Take one down, pass it round
editvar /newvar /value=a=-a-1
if -a- /hasvalue 1 goto :1
printline -a- bottles of beer on the wall.
goto :a
:1
printline 1 bottle of beer on the wall
printline 1 bottle of beer
printline take it down, pass it round
printline no bottles of beer on the wall.
editvar /newvar /value=b /userinput=1 /title=Keep drinking?
if -b- /hasvalue yes goto :a else exitprogram

[edit] Prolog

Works with: SWI Prolog
bottles(0):-!.
bottles(X):-
writef('%t bottles of beer on the wall \n',[X]),
writef('%t bottles of beer\n',[X]),
write('Take one down, pass it around\n'),
succ(XN,X),
writef('%t bottles of beer on the wall \n\n',[XN]),
bottles(XN).
 
:- bottles(99).

An other version that handles plural/not plural conditions.

line1(X):- line2(X),write(' on the wall'). 
line2(0):- write('no more bottles of beer').
line2(1):- write('1 bottle of beer').
line2(X):- writef('%t bottles of beer',[X]).
line3(1):- write('Take it down, pass it around').
line3(X):- write('Take one down, pass it around').
line4(X):- line1(X).
 
bottles(0):-!.
bottles(X):-
succ(XN,X),
line1(X),nl,
line2(X),nl,
line3(X),nl,
line4(XN),nl,nl,
!,
bottles(XN).
 
:- bottles(99).

[edit] Python

[edit] Normal Code

def plural(word, amount): # Correctly pluralize a word.
if amount == 1:
return word
else:
return word + 's'
 
def sing(b, end): # Sing a phrase of the song, for b bottles, ending in end
print b or 'No more', plural('bottle', b), end
 
for i in range(99, 0, -1):
sing(i, 'of beer on the wall,')
sing(i, 'of beer,')
print 'Take one down, pass it around,'
sing(i-1, 'of beer on the wall.\n')

[edit] Using a template

verse = '''\
%i bottles of beer on the wall
%i bottles of beer
Take one down, pass it around
%i bottles of beer on the wall
'''

 
for bottles in range(99,0,-1):
print verse % (bottles, bottles, bottles-1)

[edit] New-style template (Python 2.6)

verse = '''\
{some} bottles of beer on the wall
{some} bottles of beer
Take one down, pass it around
{less} bottles of beer on the wall
'''

 
for bottles in range(99,0,-1):
print verse.format(some=bottles, less=bottles-1)

[edit] "Clever" generator expression

a, b, c, s = " bottles of beer", " on the wall\n", "Take one down, pass it around\n", str
print "\n".join(s(x)+a+b+s(x)+a+"\n"+c+s(x-1)+a+b for x in xrange(99, 0, -1))

[edit] Enhanced "Clever" generator expression using lambda

a = lambda n: "%u bottle%s of beer on the wall\n" % (n, "s"[n==1:])
print "\n".join(a(x)+a(x)[:-13]+"\nTake one down, pass it around\n"+a(x-1) for x in xrange(99, 0, -1))

[edit] Using a generator expression (Python 3)

#!/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="")

[edit] A wordy version

ones = (
'', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'
)
prefixes = ('thir', 'four', 'fif', 'six', 'seven', 'eigh', 'nine')
tens = ['', '', 'twenty' ]
teens = ['ten', 'eleven', 'twelve']
for prefix in prefixes:
tens.append(prefix + 'ty')
teens.append(prefix +'teen')
tens[4] = 'forty'
 
def number(num):
"get the wordy version of a number"
ten, one = divmod(num, 10)
if ten == 0 and one == 0:
return 'no'
elif ten == 0:
return ones[one]
elif ten == 1:
return teens[one]
elif one == 0:
return tens[ten]
else:
return "%s-%s" % (tens[ten], ones[one])
 
def bottles(beer):
"our rephrase"
return "%s bottle%s of beer" % (
number(beer).capitalize(), 's' if beer > 1 else ''
)
 
onthewall = 'on the wall'
takeonedown = 'Take one down, pass it around'
for beer in range(99, 0, -1):
print bottles(beer), onthewall
print bottles(beer)
print takeonedown
print bottles(beer-1), onthewall
print

[edit] String Formatting

for n in xrange(99, 0, -1):
## The formatting performs a conditional check on the variable.
## If it formats the first open for False, and the second for True
print n, 'bottle%s of beer on the the wall.' % ('s', '')[n == 1]
print n, 'bottle%s of beer.' % ('s', '')[n == 1]
print 'Take one down, pass it around.'
print n - 1, 'bottle%s of beer on the wall.\n' % ('s', '')[n - 1 == 1]

[edit] Qore

[edit] Simple Solution

#!/usr/bin/env qore
 
%enable-all-warnings
 
for (my $i = 99; $i > 0; $i--) {
printf("%d bottles of beer on the wall\n", $i);
printf("%d bottles of beer\n", $i);
printf("take one down, pass it around\n");
printf("%d bottles of beer on the wall\n", $i);
}

[edit] Concurrent (Unordered) Solution

#!/usr/bin/env qore                                                                        
 
%enable-all-warnings
%require-types
 
# global variables (truly shared among threads) must be declared with "our" keyword
%require-our
 
our Counter $count();
 
sub t() {
on_exit {
$count.dec();
}
my int $i = gettid()-1;
printf("%d bottles of beer on the wall\n", $i);
printf("%d bottles of beer\n", $i);
printf("take one down, pass it around\n");
printf("%d bottles of beer on the wall\n", $i);
}
 
#-- following run by main thread
for (my int $i = 99; $i > 0; $i--) {
$count.inc();
background t();
}
 
$count.waitForZero();

[edit] Quill

bottles := void(int count) {
(count > 0) if {
new_count := count - 1;
(
count, " bottles of beer on the wall", nl,
count, " bottles of beer", nl,
"Take one down, pass it around", nl,
new_count, " bottles of beer on the wall"
) print;
new_count bottles
} else {
"No more bottles of beer on the wall!" print
}
};
99 bottles

[edit] R

[edit] Simple looping solution

#a naive function to sing for N bottles of beer...
 
song = function(bottles){
 
for(i in bottles:1){ #for every integer bottles, bottles-1 ... 1
 
cat(bottles," bottles of beer on the wall \n",bottles," bottles of beer \nTake one down, pass it around \n",
bottles-1, " bottles of beer on the wall \n"," \n" ,sep="") #join and print the text (\n means new line)
 
bottles = bottles - 1 #take one down...
 
}
 
}
 
song(99)#play the song by calling the function

[edit] Vector solutions

#only one line!
cat(paste(99:1,ifelse((99:1)!=1," bottles"," bottle")," of beer on the wall\n",99:1,ifelse((99:1)!=1," bottles"," bottle")," of beer\n","Take one down, pass it around\n",98:0,ifelse((98:0)!=1," bottles"," bottle")," of beer on the wall\n\n",sep=""),sep="")
 
#alternative
cat(paste(lapply(99:1,function(i){paste(paste(rep(paste(i,' bottle',if(i!=1)'s',' of beer',sep=''),2),collapse =' on the wall\n'),'Take one down, pass it around',paste(i-1,' bottle',if(i!=2)'s',' of beer on the wall',sep=''), sep='\n')}),collapse='\n\n'))

[edit] Racket

 
#lang racket
(define (sing bottles)
(define (plural n) (~a n " bottle" (if (= n 1) "" "s")))
(printf "~a of beer on the wall\n~a of beer\n~
Take one down, pass it around\n~a of beer on the wall\n\n"
(plural bottles) (plural bottles) (plural (sub1 bottles)))
(unless (= 1 bottles) (sing (sub1 bottles))))
(sing 100)
 

[edit] Rascal

 
module demo::basic::Bottles
 
import IO;
 
str bottles(0) = "no more bottles";
str bottles(1) = "1 bottle";
default str bottles(int n) = "<n> bottles";
 
public void sing(){
for(n <- [99 .. 1]){
println("<bottles(n)> of beer on the wall, <bottles(n)> of beer.");
println("Take one down, pass it around, <bottles(n-1)> of beer on the wall.\n");
}
println("No more bottles of beer on the wall, no more bottles of beer.");
println("Go to the store and buy some more, 99 bottles of beer on the wall.");
}
 

[edit] Raven

99 0 1 range each as $i
$i 1 = if
"bottle" as $b
else
"bottles" format as $b
$b $i "%d %s of beer on the wall,\n" print
$b $i "%d %s of beer,\n" print
"Take one down, pass it around,\n" print
$i 2 = if
"1 bottle"
else
$i 1 - "%d bottles" format
"%s of beer on the wall.\n\n" print
Output:

Last couple of stanzas are:

3 bottles of beer on the wall,
3 bottles of beer,
Take one down, pass it around,
2 bottles of beer on the wall.

2 bottles of beer on the wall,
2 bottles of beer,
Take one down, pass it around,
1 bottle of beer on the wall.

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

[edit] REBOL

rebol [
Title: "99 Bottles of Beer"
Author: oofoe
Date: 2009-12-11
URL: http://rosettacode.org/wiki/99_Bottles_of_Beer
]

 
; The 'bottles' function maintains correct grammar.
 
bottles: func [n /local b][
b: either 1 = n ["bottle"]["bottles"]
if 0 = n [n: "no"]
reform [n b]
]
 
for n 99 1 -1 [print [
bottles n "of beer on the wall" crlf
bottles n "of beer" crlf
"Take one down, pass it around" crlf
bottles n - 1 "of beer on the wall" crlf
]]

Output (selected highlights):

99 bottles of beer on the wall    2 bottles of beer on the wall 
99 bottles of beer                2 bottles of beer             
Take one down, pass it around     Take one down, pass it around 
98 bottles of beer on the wall    1 bottle of beer on the wall  
                                                                
...Continues...                   1 bottle of beer on the wall  
                                  1 bottle of beer              
                                  Take one down, pass it around 
                                  no bottles of beer on the wall

This one prints with proper grammar. "Bottles" changed to "bottle" at the end of the 2 line, and throughout the 1 line. 0 changed to "No" in the last line:

for i 99 1 -1 [ 
x: rejoin [
i b: " bottles of beer" o: " on the wall. " i b
". Take one down, pass it around. " (i - 1) b o "^/"
]
r: :replace j: "bottles" k: "bottle"
switch i [1 [r x j k r at x 10 j k r x "0" "No"] 2 [r at x 40 j k]]
print x
] halt

Here's a simple 1 line console version:

for i 99 1 -1[print rejoin[i b:" bottles of beer"o:" on the wall. "i b". Take one down, pass it around. "(i - 1)b o"^/"]]

[edit] Retro

This is based on the Forth example.

[ dup "%d bottles" puts ]
[ "1 bottle" puts ]
[ "no more bottles" puts ]
create bottles , , ,
 
: .bottles dup 2 ^math'min bottles + @ do ;
: .beer .bottles " of beer" puts ;
: .wall .beer " on the wall" puts ;
: .take "Take one down, pass it around" puts ;
: .verse .wall cr .beer cr
1- .take cr .wall cr ;
: ?dup dup 0; ;
: verses [ cr .verse dup 0 <> ] while drop ;
 
99 verses
bye

[edit] REXX

/*REXX pgm displays words to the song "99 Bottles of Beer on the Wall". */
 
do j=99 by -1 to 1 /*start countdown | singdown*/
say j 'bottle's(j) "of beer on the wall," /*sing the #bottles of beer.*/
say j 'bottle's(j) "of beer." /* ... and the refrain. */
say 'Take one down, pass it around,' /*get a bottle and share it.*/
n=j-1 /*N is #bottles we have now.*/
if n==0 then n='no' /*use "no" instead of 0. */
say n 'bottle's(n) "of beer on the wall." /*sing beer bottle inventory*/
say /*blank line between verses.*/
end /*j*/
 
say 'No more bottles of beer on the wall,' /*Finally! The last verse.*/
say 'no more bottles of beer.' /*so sad ... */
say 'Go to the store and buy some more,' /*replenishment of the beer.*/
say '99 bottles of beer on the wall.' /*All is well in the tavern.*/
exit /*we're done & also sloshed.*/
/*───────────────────────────────────S subroutine───────────────────────*/
s: if arg(1)=1 then return ''; return 's' /*a simple pluralizer funct.*/

output Below is the first and last three verses of the song.

99 bottles of beer on the wall,
99 bottles of beer.
Take one down, pass it around,
98 bottles of beer on the wall.

98 bottles of beer on the wall,
98 bottles of beer.
Take one down, pass it around,
97 bottles of beer on the wall.

97 bottles of beer on the wall,
97 bottles of beer.
Take one down, pass it around,
96 bottles of beer on the wall.
  
  ∙
  ∙
  ∙
  
2 bottles of beer on the wall,
2 bottles of beer.
Take one down, pass it around,
1 bottle of beer on the wall.

1 bottle of beer on the wall,
1 bottle of beer.
Take one down, pass it around,
no bottles of beer on the wall.

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.

[edit] RPL/2

[edit] Simple solution

BEER
<<
99 do
dup ->str PLURAL " on the wall," + disp
dup ->str PLURAL "." + disp
"Take one down, pass it around," disp
1 -
if dup then
dup ->str
else
"No more"
end
PLURAL " on the wall." + disp
"" disp
until dup 0 == end
drop
>>
 
PLURAL
<<
" bottle" + over if 1 <> then "s" + end " of beer" +
>>

[edit] Recursive and multithreaded solution

BOTTLES
<<
// Child process is started.
100 'RECURSIVE' detach
-> PROC
<<
do PROC recv until end drop2
 
do
// Parent waits for datas sent by child.
do PROC recv until end
list-> drop dup " on the wall," + disp "." + disp
"Take one down, pass it around," disp
 
if dup 1 same not then
do PROC recv until end list-> drop
else
1 "No more bottles of beer"
end
" on the wall." + disp drop "" disp
until
1 same
end
 
// Parent waits for Child's death.
PROC wfproc
>>
>>
 
RECURSIVE
<<
while
dup
repeat
1 - dup dup ->str
if over 1 > then " bottles " else " bottle " end +
"of beer" + 2 ->list dup
// Child send datas to parent process.
send send
// Recursive function is caught.
RECURSIVE
end
>>

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

Ruby has variable traces, so we can do

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

or...

def bottles(of_beer, ending)
puts "#{of_beer} bottle#{ending} of beer on the wall,"
puts "#{of_beer} bottle#{ending} of beer"
puts "Take one down, pass it around!"
end
 
99.downto(0) do |left|
if left > 1
bottles(left, "s")
elsif left == 1
bottles(left, "")
else
puts "No more bottles of beer on the wall!"
end
end

or...

def bottles(beer, wall = false)
"#{beer>0 ? beer : "no more"} bottle#{"s" if beer!=1} of beer#{" on the wall" if wall}"
end
 
99.downto(0) do |remaining|
puts "#{bottles(remaining,true).capitalize}, #{bottles(remaining)}."
if remaining==0
print "Go to the store and buy some more"
remaining=100
else
print "Take one down, pass it around"
end
puts ", #{bottles(remaining-1,true)}.\n\n"
end

[edit] Simple solution

 
99.downto(1) do |bottles|
puts "#{bottles} bottle#{"s" if bottles != 1} of beer on the wall.",
"#{bottles} bottle#{"s" if bottles != 1} of beer.",
"Take one down, pass it around.",
"#{bottles - 1} bottle#{"s" if bottles - 1 != 1} of beer on the wall.\n\n"
end
 

[edit] Rust

Works with: rustc version 0.12.0-pre-nightly
use std::iter::range_step_inclusive;
 
trait Bottles {
fn bottles_of_beer(&self) -> Self;
fn on_the_wall(&self);
}
 
impl Bottles for int{
 
fn bottles_of_beer(&self) -> int {
match *self {
1 => print!("{} bottle of beer", self),
0 => print!("No bottles of beer"),
_ => print!("{} bottles of beer", self)
}
*self //for chaining
}
 
fn on_the_wall(&self) {
println!(" on the wall!");
}
}
 
fn main() {
for i in range_step_inclusive(99i, 1, -1) {
i.bottles_of_beer().on_the_wall();
i.bottles_of_beer();
println!("\nTake one down, pass it around...");
(i - 1).bottles_of_beer().on_the_wall();
println!("-----------------------------------");
}
}

[edit] Sather

class MAIN is
main is
s :STR;
p1 ::= "<##> bottle<#> of beer";
w  ::= " on the wall";
t  ::= "Take one down, pass it around\n";
loop i ::= 99.downto!(0);
if i /= 1 then s := "s" else s := ""; end;
#OUT + #FMT(p1 + w + "\n", i, "s");
#OUT + #FMT(p1 + "\n", i, "s");
if i > 0 then #OUT + t; end;
end;
end;
end;

[edit] Scala

See 99 Bottles of Beer/Scala

[edit] Scheme

Works with: Chicken 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))))

[edit] Scratch

Scratchbeer.jpg

[edit] sed

s/.*/99 bottles of beer on the wall/
h
: b
s/^0//
/^0/q
s/^1 bottles/1 bottle/
p
s/on.*//
p
s/.*/Take one down, pass it around/
p
g
/^.[1-9]/{
h
s/^.//
y/123456789/012345678/
x
s/^\(.\).*$/\1/
G
s/\n//
h
bb
}
y/0123456789/9012345678/
h
bb

[edit] Seed7

$ include "seed7_05.s7i";
 
const proc: main is func
local
var integer: number is 0;
begin
for number range 99 downto 2 do
write( number <& " bottles of beer on the wall, ");
writeln( number <& " bottles of beer.");
write( "Take one down and pass it around, ");
writeln( pred(number) <& " bottles of beer on the wall.");
writeln;
end for;
writeln("1 bottle of beer on the wall, 1 bottle of beer.");
writeln("Take one down and pass it around, no more bottles of beer on the wall.");
writeln;
writeln("No more bottles of beer on the wall, no more bottles of beer.");
writeln("Go to the store and buy some more, 99 bottles of beer on the wall.")
end func;

[edit] Shiny

for 99 i:99-a
s: if i > 1 's' end
 
if i > 0 and i < 99 switch
if i = 6 say "A six-pack on the wall!\n" break
if i = 24 say "A carton on the wall!\n" break
say "$i bottle$s of beer on the wall!\n"
ends
 
say "$i bottle$s of beer on the wall,"
say "$i bottle$s of beer!"
say "Take one down, pass it around!"
end
say "Aww...no more bottles of beer on the wall... it must be your shout :)"

[edit] Sidef

99.downto(0).each { |i|
var bottles = "#{i == 0 ? 'No' : i} bottle#{i == 1 ? '' : 's'}";
var sentence = "#{bottles} of beer on the wall" -> say;
i > 0 && (
sentence.substr(0, bottles.length + 8).say;
"Take one down, pass it around\n".say;
);
};

Simpler:

99.downto(2).each { | n |
say "#{n} bottles of beer on the wall, #{n} bottles of beer!";
say "Take one down, pass it around, #{n - 1} bottle#{n > 2 ? 's' : ''} of beer on the wall.\n";
};
 
say "One bottle of beer on the wall, one bottle of beer!";
say "Take one down, pass it around, no more bottles of beer on the wall.";

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

[edit] Smalltalk

A straightforward approach:

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. ].
].

[edit] SNOBOL4

	x = 99
again output = X " bottles of beer on the wall"
output = X " bottles of beer"  ?eq(X,0) :s(zero)
output = "Take one down, pass it around"
output = (X = gt(x,0) X - 1) " bottle of beer on the wall..." :s(again)
zero output = "Go to store, get some more"
output = "99 bottles of beer on the wall"
end

[edit] Function

Works with: Macro Spitbol
Works with: CSnobol

Function version with string composition. Function returns one verse for x bottles. Correctly handles bottle/bottles.

        define('bottles(x)')
nl = char(13) char(10) ;* Win/DOS, change as needed
s2 = ' of beer'; s3 = ' on the wall'
s4 = 'Take one down, pass it around'
s5 = 'Go to the store, get some more' :(bottles_end)
bottles s1 = (s1 = ' Bottle') ne(x,1) 's'
output = nl x s1 s2 s3 nl x s1 s2
x = gt(x,0) x - 1 :f(done)
s1 = (s1 = ' Bottle') ne(x,1) 's'
output = s4 nl x s1 s2 s3 :(return)
done output = s5 nl 99 s1 s2 s3 :(return)
bottles_end
 
* # Test and display, only 2 bottles!
n = 2
loop bottles(n); n = gt(n,0) n - 1 :s(loop)
end

Output:

2 Bottles of beer on the wall
2 Bottles of beer
Take one down, pass it around
1 Bottle of beer on the wall

1 Bottle of beer on the wall
1 Bottle of beer
Take one down, pass it around
0 Bottles of beer on the wall

0 Bottles of beer on the wall
0 Bottles of beer
Go to the store, get some more
99 Bottles of beer on the wall

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

[edit] Sparkling

var bottles = 99;
 
do {
printf("%u bottles of beer on the wall\n", bottles);
printf("%u bottles of beer\n", bottles);
printf("Take one down, pass it around\n");
printf("%u bottles of beer on the wall\n\n", --bottles);
} while(bottles > 1);
 
printf("1 bottle of beer on the wall\n1 bottle of beer\nTake it down, pass it around\n0 bottles of beer on the wall\n");

[edit] SQL

 
 
 
DELIMITER $$
DROP PROCEDURE IF EXISTS bottles_$$
CREATE PROCEDURE `bottles_`(INOUT bottle_count INT, INOUT song text)
BEGIN
DECLARE bottles_text VARCHAR(30);
 
 
IF bottle_count > 0 THEN
 
 
IF bottle_count != 1 THEN
SET bottles_text := ' bottles of beer ';
ELSE SET bottles_text = ' bottle of beer ';
END IF;
 
SELECT concat(song, bottle_count, bottles_text, ' \n') INTO song;
SELECT concat(song, bottle_count, bottles_text, 'on the wall\n') INTO song;
SELECT concat(song, 'Take one down, pass it around\n') INTO song;
SELECT concat(song, bottle_count -1 , bottles_text, 'on the wall\n\n') INTO song;
SET bottle_count := bottle_count -1;
CALL bottles_( bottle_count, song);
END IF;
END$$
 
SET @bottles=99;
SET max_sp_recursion_depth=@bottles;
SET @song='';
CALL bottles_( @bottles, @song);
SELECT @song;
 

This Statement does also work with T-SQL, but only up to 32 beers

 
CREATE PROCEDURE bottles
@bottle_count INT,
@song VARCHAR(MAX)
 
AS
BEGIN
 
DECLARE @bottles_text VARCHAR(MAX);
 
 
IF @bottle_count > 0
BEGIN
IF @bottle_count != 1
BEGIN
SET @bottles_text = ' bottles of beer ';
END
ELSE
BEGIN
SET @bottles_text = ' bottle of beer ';
END
 
 
 
SET @song = @song + CAST(@bottle_count AS VARCHAR) + @bottles_text + '\n';
 
SET @song = @song + CAST(@bottle_count AS VARCHAR) + @bottles_text + 'on the wall\n'
SET @song = @song + 'Take one down, pass it around\n'
SET @song = @song + CAST((@bottle_count - 1) AS VARCHAR) + @bottles_text + 'on the wall\n'
 
 
SET @bottle_count = (@bottle_count - 1);
 
 
 
 
EXEC bottles @bottle_count, @song
 
END
ELSE
SELECT @song AS 'RESULT'
END
 
/*****
AND IN ORDER TO CALL PROCEDURE:
****/

EXECUTE bottles 31, '';
 
 

[edit] Squirrel

 
function rec(bottles)
{
if (bottles > 0)
{
print(bottles+" bottles of beer on the wall\n")
print(bottles+" bottles of beer\n");
print("Take one down, pass it around\n");
print(--bottles+" bottles of beer on the wall\n\n")
return rec(bottles);
}
print("No more bottles of beer on the wall, no more bottles of beer\n");
print("Go to the store and get some more beer, 99 bottles of beer on the wall\n");
}
 
rec(99);
 

[edit] Standard ML

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)
)

[edit] Suneido

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
if i is 0
Print('Ahh poo, we are out of beer\n')
else
Print(i $ ' bottles of beer on the wall\n')
}

[edit] Swift

 
var bottles = 99
 
if bottles<=99{
do{
println("\n\n\(bottles) bottles of beer on the wall, \(bottles) bottles of beer.")
bottles=bottles-1
println("Take one down and pass it around, \(bottles) bottles of beer on the wall.\n\n")
}while bottles>1
}
if bottles==1{
println("\(bottles) bottle of beer on the wall, \(bottles) bottle of beer.\nTake one down and pass it around, no more bottles of beer on the wall.\n\n")
bottles=bottles-1
}
if bottles==0{
println("No more bottles of beer on the wall, no more bottles of beer.\n\n")
 
}
else{
//If "var bottles" > 99 (first line)
println("It's unpossible to have so many bottles of bear on the wall")
}
 
 

[edit] Tcl

set s "s"; set ob "of beer"; set otw "on the wall"; set more "Take one down and pass it around"
for {set n 100} {$n ne "No more"} {} {
switch -- [incr n -1] {
1 {set s ""}
0 {set s "s"; set n "No more"; set more "Go to the store and buy some more"}
}
lappend verse ". $n bottle$s $ob $otw.\n"
lappend verse "\n$n bottle$s $ob $otw, [string tolower $n] bottle$s $ob.\n$more"
}
puts -nonewline [join [lreplace $verse 0 0] ""][lindex $verse 0]

Version which converts numbers to words, optimized for script length while retaining readability:

proc 0-19 {n} {
lindex {"no more" one two three four five six seven eight nine ten eleven
twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen} $n
}
 
proc TENS {n} {
lindex {twenty thirty fourty fifty sixty seventy eighty ninety} [expr {$n - 2}]
}
 
proc num2words {n} {
if {$n < 20} {return [0-19 $n]}
set tens [expr {$n / 10}]
set ones [expr {$n % 10}]
if {$ones == 0} {return [TENS $tens]}
return "[TENS $tens]-[0-19 $ones]"
}
 
proc get_words {n} {
return "[num2words $n] bottle[expr {$n != 1 ? "s" : ""}] of beer"
}
 
for {set i 99} {$i > 0} {incr i -1} {
puts [string totitle "[get_words $i] on the wall, [get_words $i]."]
puts "Take one down and pass it around, [get_words [expr {$i - 1}]] on the wall.\n"
}
 
puts "No more bottles of beer on the wall, no more bottles of beer."
puts "Go to the store and buy some more, 99 bottles of beer on the wall."

See also 99 Bottles of Beer/Tcl

[edit] Thyrd

main
detail

[edit] TIScript

 
var beer = 99;
while (beer > 0)
{
stdout.printf( "%d bottles of beer on the wall\n", beer);
stdout.printf( "%d bottles of beer\n", beer);
stdout.println( "Take one down, pass it around" );
stdout.printf( "%d bottles of beer on the wall\n", --beer );
}
 

[edit] TorqueScript

 
for(%i = 99; %i >= 0; %i--)
{
%n = %i - 1;
echo(%i SPC (%n == 1 ? "bottle" : "bottles") SPC "of beer on the wall ~");
echo("Take one down, pass it around,");
echo(%n SPC (%i == 1 ? "bottle" : "bottles") SPC "of beer on the wall.");
}
 

[edit] TUSCRIPT

 
$$ MODE TUSCRIPT
LOOP bottle=1,100
SET bottlenr=100-bottle
IF (bottlenr==0) THEN
PRINT "no bottle of beer on the wall"
EXIT
ELSEIF (bottlenr==1) THEN
PRINT bottlenr, " bottle of beer on the wall"
PRINT bottlenr, " bottle of beer"
ELSE
PRINT bottlenr, " bottles of beer on the wall"
PRINT bottlenr, " bottles of beer"
ENDIF
PRINT "Take one down, pass it around"
ENDLOOP
 

[edit] TXR

The (range 99 -1 -1) expression produces a lazy list of integers from 99 down to -1. The mapcar* function lazily maps these numbers to strings, and the rest of the code treats this lazy list as text stream to process, extracting the numbers with some pattern matching cases and interpolating them into the song's text. Functional programming with lazy semantics meets text processing, pattern matching and here documents.

@(next :list @(mapcar* (fun tostring) (range 99 -1 -1)))
@(collect)
@number
@ (trailer)
@number_less_1
@ (cases)
@ (bind number "1")
@ (output)
1 bottle of beer one the wall
1 bottle of beer
@ (end)
@ (or)
@ (output)
@number bottles of beer one the wall
@number bottles of beer
@ (end)
@ (end)
@ (cases)
@ (bind number "0")
@ (output)
Go to the store and get some more,
99 bottles of beer on the wall!
 
@ (end)
@ (or)
@ (output)
Take one down and pass it around
@number_less_1 bottles of beer on the wall
 
@ (end)
@ (end)
@(end)

To make the song repeat indefinitely, change the first line to:

@(next :list @(mapcar* (fun tostring) (repeat (range 99 0 -1))))

Now it's processing an infinite lazy lists consisting of repetitions of the integer sequences 99 98 ... 0.

[edit] UNIX Shell

Works with: Bourne Shell
#!/bin/sh
 
i=99 s=s
 
while [ $i -gt 0 ]; do
echo "$i bottle$s of beer on the wall"
echo "$i bottle$s of beer
Take one down, pass it around"

# POSIX allows for $(( i - 1 )) but some older Unices didn't have that
i=`expr $i - 1`
[ $i -eq 1 ] && s= || s=s
echo "$i bottle$s of beer on the wall
"

done
Works with: Bash
Works with: ksh93
Works with: zsh
bottles() {
beer=$1
[ $((beer)) -gt 0 ] && echo -n $beer || echo -n "No more"
echo -n " bottle"
[ $((beer)) -ne 1 ] && echo -n "s"
echo -n " of beer"
}
 
for ((i=99;i>=0;i--)); do
((remaining=i))
echo "$(bottles $remaining) on the wall"
echo "$(bottles $remaining)"
if [ $((remaining)) -eq 0 ]; then
echo "Go to the store and buy some more"
((remaining+=99))
else
echo "Take one down, pass it around"
((remaining--))
fi
echo "$(bottles $remaining) on the wall"
echo
done

[edit] C Shell

@ i=99
set s=s
while ($i > 0)
echo "$i bottle$s of beer on the wall"
echo "$i bottle$s of beer"
echo "Take one down, pass it around"
@ i = $i - 1
if ($i == 1) then
set s=
else
set s=s
endif
echo "$i bottle$s of beer on the wall"
echo ""
end

[edit] es

i = 99
s = s
while {test $i -gt 0} {
echo $i bottle$s of beer on the wall
echo $i bottle$s of beer
echo Take one down, pass it around
i = `{expr $i - 1}
if {test $i -eq 1} {s = ''} {s = s}
echo $i bottle$s of beer on the wall
echo
}

[edit] UnixPipes

# Unix Pipes, avoiding all the turing complete sub programs like sed, awk,dc etc.
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

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

[edit] V

[bottles
[newline <nowiki>''</nowiki> 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

[edit] Vala

void main() {
uint bottles = 99;
do {
print("%u bottles of beer on the wall.\n", bottles);
print("%u bottles of beer!\n", bottles);
print("Take one down, pass it around!\n");
--bottles;
if (bottles == 0) {
print("No bottles");
}
else if (bottles == 1) {
print("1 bottle");
}
else {
print("%u bottles", bottles);
}
print(" of beer on the wall!\n\n");
} while (bottles != 0);
}

[edit] VBA

This version uses tail recursion and inline if-statements, plus a Static variable to count the number of bottles emptied.

Public Function countbottles(n As Integer, liquid As String) As String
countbottles = IIf(n > 1, Format$(n), IIf(n = 0, "no more", "one")) & " bottle" & IIf(n = 1, "", "s") & " of " & liquid
End Function
 
Public Sub drink(fullbottles As Integer, Optional liquid As String = "beer")
Static emptybottles As Integer
 
Debug.Print countbottles(fullbottles, liquid) & " on the wall"
Debug.Print countbottles(fullbottles, liquid)
 
If fullbottles > 0 Then
Debug.Print "take " & IIf(fullbottles > 1, "one", "it") & " down, pass it around"
Debug.Print countbottles(fullbottles - 1, liquid) & " on the wall"
Debug.Print
emptybottles = emptybottles + 1
drink fullbottles - 1, liquid
Else
Debug.Print "go to the store and buy some more"
Debug.Print countbottles(emptybottles, liquid) & " on the wall"
End If
 
End Sub

Usage: type "drink 99" in the Immediate window of the VBA editor. If you're not a beer drinker, you can specify your own favourite drink as the second argument; for example:

drink 3, "Johnnie Walker"

3 bottles of Johnnie Walker on the wall
3 bottles of Johnnie Walker
take one down, pass it around
2 bottles of Johnnie Walker on the wall

2 bottles of Johnnie Walker on the wall
2 bottles of Johnnie Walker
take one down, pass it around
one bottle of Johnnie Walker on the wall

one bottle of Johnnie Walker on the wall
one bottle of Johnnie Walker
take it down, pass it around
no more bottles of Johnnie Walker on the wall

no more bottles of Johnnie Walker on the wall
no more bottles of Johnnie Walker
go to the store and buy some more
3 bottles of Johnnie Walker on the wall

[edit] VBScript

[edit] Simple Method

sub song( numBottles )
dim i
for i = numBottles to 0 step -1
if i > 0 then
wscript.echo pluralBottles(i) & " of beer on the wall"
wscript.echo pluralBottles(i) & " of beer"
if i = 1 then
wscript.echo "take it down"
else
wscript.echo "take one down"
end if
wscript.echo "and pass it round"
wscript.echo pluralBottles(i-1) & " of beer on the wall"
wscript.echo
else
wscript.echo "no more bottles of beer on the wall"
wscript.echo "no more bottles of beer"
wscript.echo "go to the store"
wscript.echo "and buy some more"
wscript.echo pluralBottles(numBottles) & " of beer on the wall"
wscript.echo
end if
next
end sub
 
function pluralBottles( n )
select case n
case 1
pluralBottles = "one bottle"
case 0
pluralBottles = "no more bottles"
case else
pluralBottles = n & " bottles"
end select
end function
 
song 3

Outputs:

3 bottles of beer on the wall
3 bottles of beer
take one down
and pass it round
2 bottles of beer on the wall
 
2 bottles of beer on the wall
2 bottles of beer
take one down
and pass it round
one bottle of beer on the wall
 
one bottle of beer on the wall
one bottle of beer
take it down
and pass it round
no more bottles of beer on the wall
 
no more bottles of beer on the wall
no more bottles of beer
go to the store
and buy some more
3 bottles of beer on the wall

[edit] Regular Expressions and Embedded Scripting

Another way of doing it, using Regular Expressions to locate executable code inside {} and replacing the code with the result of its evaluation.

function pluralBottles( n )
select case n
case 1
pluralBottles = "one bottle"
case 0
pluralBottles = "no more bottles"
case else
pluralBottles = n & " bottles"
end select
end function
 
function eef( b, r1, r2 )
if b then
eef = r1
else
eef = r2
end if
end function
 
Function evalEmbedded(sInput, sP1)
dim oRe, oMatch, oMatches
dim sExpr, sResult
Set oRe = New RegExp
'Look for expressions as enclosed in braces
oRe.Pattern = "{(.+?)}"
sResult = sInput
do
Set oMatches = oRe.Execute(sResult)
if oMatches.count = 0 then exit do
for each oMatch in oMatches
'~ wscript.echo oMatch.Value
for j = 0 to omatch.submatches.count - 1
sExpr = omatch.submatches(j)
sResult = Replace( sResult, "{" & sExpr & "}", eval(sExpr) )
next
next
loop
evalEmbedded = sResult
End Function
 
sub sing( numBottles )
dim i
for i = numBottles to 0 step -1
if i = 0 then
wscript.echo evalEmbedded("no more bottles of beer on the wall" & vbNewline & _
"no more bottles of beer" & vbNewline & _
"go to the store and buy some more" & vbNewline & _
"{pluralBottles(sP1)} of beer on the wall" & vbNewline, numBottles)
else
wscript.echo evalEmbedded("{pluralBottles(sP1)} of beer on the wall" & vbNewline & _
"{pluralBottles(sP1)} of beer" & vbNewline & _
"take {eef(sP1=1,""it"",""one"")} down and pass it round" & vbNewline & _
"{pluralBottles(sP1-1)} of beer on the wall" & vbNewline, i)
end if
next
end sub
 
sing 3

[edit] Visual Prolog

 
implement main
open core, std, console
 
class predicates
bottles : (integer) -> string procedure (i).
 
clauses
bottles(1) = "bottle" :- !.
bottles(_) = "bottles".
 
run():-
init(),
foreach B = downTo(99,1) do
write(B," ",bottles(B), " of beer on the wall,\n"),
write(B," ",bottles(B), " of beer,\n"),
write("Take one down, pass it around,\n"),
write(B-1," ",bottles(B-1)," of beer on the wall.\n\n")
end foreach,
 
succeed().
end implement main
 
goal
mainExe::run(main::run).
 

[edit] Vox

 
// translated from <http://rosettacode.org/wiki/99_Bottles_of_Beer#JavaScript>
 
local beer;
while((beer = typeof beer == "null" ? 99 : beer) > 0)
println(
beer + " bottle" +
(beer != 1 ? "s" : "") +
" of beer on the wall\n" + beer + " bottle" +
(beer != 1 ? "s" : "") +
" of beer\nTake one down, pass it around\n" +
(--beer) + " bottle" +
(beer != 1 ? "s" : "") + " of beer on the wall\n"
);
 

[edit] Wart

def (beer n)
when (n > 0)
prn n " bottles of beer on the wall"
prn n " bottles of beer"
prn "take one down, pass it around"
prn n-1 " bottles of beer on the wall"
prn ""
beer n-1

[edit] Whenever

1 defer (4 || N(1)<N(2) && N(2)<N(3)) print(N(1)+" bottles of beer on the wall, "+N(1)+" bottles of beer,");
2 defer (4 || N(1)==N(2)) print("Take one down and pass it around,");
3 defer (4 || N(2)==N(3)) print(N(1)+" bottles of beer on the wall.");
4 1#98,2#98,3#98;

[edit] Wortel

!console.log @unlines ~!* 99..0 !? {
0 "0 bottles of beer on the wall\n0 bottles of beer\nbetter go to the store and buy some more."
"{@x} bottle{@?@x{1 @e 's}} of beer on the wall\n{@x} bottle{@?@x{1 @e 's}} of beer\nTake one down, pass it around"
}

[edit] Wrapl

MOD Bottles;
 
IMP IO.Terminal USE Out;
IMP Std.String;
 
VAR i, s <- "s", ob <- "of beer", otw <- "on the wall",
more <- "Take one down and pass it around", verse <- [];
 
EVERY i <- 99:to(0,-1) DO (
(i = 1) & (s <- "");
(i = 0) & (s <- "s"; i <- "No more"; more <- "Go to the store and buy some more");
verse:put('. {i} bottle{s} {ob} {otw}.\n');
verse:put('\n{i} bottle{s} {ob} {otw}, {([email protected]):lower} bottle{s} {ob}.\n{more}');
);
 
Out:write(verse[2,0]@(String.T, "") + verse[1]);
 
END Bottles.

[edit] X86 Assembly

[edit] Using Windows/MASM32

.386
.model flat, stdcall
option casemap :none
 
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
 
.DATA
buffer db 1024 dup(?)
str1 db "%d bottles of beer on the wall.",10,13,0
str2 db "%d bottles of beer",10,13,0
str3 db "Take one down, pass it around",10,13,0
str4 db "No more bottles of beer on the wall!",10,13,0
nline db 13,10,0
 
bottles dd 99
 
.CODE
start:
INVOKE wsprintfA, offset buffer, offset str1, [bottles]
INVOKE StdOut, offset buffer
 
INVOKE wsprintfA, offset buffer, offset str2, [bottles]
INVOKE StdOut, offset buffer
 
INVOKE StdOut, offset str3
 
DEC [bottles]
 
INVOKE wsprintfA, offset buffer, offset str1, [bottles]
INVOKE StdOut, offset buffer
INVOKE StdOut, offset nline
 
CMP [bottles], 1
JNE start
 
INVOKE StdOut, offset str4
INVOKE ExitProcess, 0
end start

[edit] Implemented in the nasm preprocessor

bits 32
 
section .data
str:
%assign bottles 99
%rep 99
%defstr bottles_str bottles
%if bottles == 1
%define bottle_plur " bottle"
%else
%define bottle_plur " bottles"
%endif
db bottles_str, bottle_plur, " of beer on the wall", 10
db bottles_str, bottle_plur, " of beer", 10
db "Take one down, pass it around", 10, 10
%assign bottles bottles-1
%endrep
db "0 bottles of beer on the wall", 10
str_len: equ $ - str
 
section .text
global _start
_start:
mov edx, str_len
mov ecx, str
mov ebx, 1
mov eax, 4
int 0x80
 
mov ebx, 0
mov eax, 1
int 0x80

[edit] XPL0

code IntOut=11, Text=12;
int B;
[B:= 99;
repeat IntOut(0, B); Text(0, " bottles of beer on the wall^M^J");
IntOut(0, B); Text(0, " bottles of beer^M^J");
Text(0, "Take one down, pass it around^M^J");
B:= B-1;
IntOut(0, B); Text(0, " bottles of beer on the wall^M^J^J");
until B=0;
]

[edit] Yorick

[edit] Looped version

bottles = 99;
while(bottles) {
write, format=" %d bottles of beer on the wall\n", bottles;
write, format=" %d bottles of beer\n", bottles;
write, "Take one down, pass it around";
write, format=" %d bottles of beer on the wall\n\n", --bottles;
}

[edit] Vectorized version

song = "%d bottles of beer on the wall\n";
song += "%d bottles of beer\n";
song += "Take one down, pass it around\n";
song += "%d bottles of beer on the wall\n";
beer = indgen(99:1:-1);
write, format=song, beer, beer, beer-1;


[edit] Z80 Assembly

For Sinclair ZX Spectrum.

org 32768
 
start:
ld a, 2 ; Spectrum: channel 2 = "S" for screen
call $1601 ; Spectrum: Select print channel using ROM
 
ld c,99 ; Number of bottles to start with
 
loopstart:
call printc ; Print the number of bottles
ld hl,line1 ; Print the rest of the first line
call printline
 
call printc ; Print the number of bottles
ld hl,line2_3 ; Print rest of the 2nd and 3rd lines
call printline
 
dec c ; Take one bottle away
call printc ; Print the number of bottles
ld hl,line4 ; Print the rest of the fourth line
call printline
 
ld a,c
cp 0 ; Out of beer bottles?
jp nz,loopstart ; If not, loop round again
ret ; Return to BASIC
 
printc: ; Routine to print C register as ASCII decimal
ld a,c
call dtoa2d ; Split A register into D and E
 
ld a,d ; Print first digit in D
cp '0' ; Don't bother printing leading 0
jr z,printc2
rst 16 ; Spectrum: Print the character in 'A'
 
printc2:
ld a,e ; Print second digit in E
rst 16 ; Spectrum: Print the character in 'A'
ret
 
printline: ; Routine to print out a line
ld a,(hl) ; Get character to print
cp '$' ; See if it '$' terminator
jp z,printend ; We're done if it is
rst 16 ; Spectrum: Print the character in 'A'
inc hl ; Move onto the next character
jp printline ; Loop round
 
printend:
ret
 
dtoa2d: ; Decimal to ASCII (2 digits only), in: A, out: DE
ld d,'0' ; Starting from ASCII '0'
dec d ; Because we are inc'ing in the loop
ld e,10 ; Want base 10 please
and a ; Clear carry flag
 
dtoa2dloop:
inc d ; Increase the number of tens
sub e ; Take away one unit of ten from A
jr nc,dtoa2dloop ; If A still hasn't gone negative, do another
add a,e ; Decreased it too much, put it back
add a,'0' ; Convert to ASCII
ld e,a ; Stick remainder in E
ret
 
; Data
line1: defb ' bottles of beer on the wall,',13,'$'
line2_3: defb ' bottles of beer,',13,'Take one down, pass it around,',13,'$'
line4: defb ' bottles of beer on the wall.',13,13,'$'

[edit] zkl

[99..0,-1].pump(fcn(n){
println(beers(n), " on the wall, ", beers(n).toLower(), ".\n",
n==0 and ("Go to the store and buy some more, 99 bottles of beer") or
("Take one down and pass it around, " + beers(n-1).toLower()),
" on the wall.\n")
});
fcn beers(n){
(n==0 and "No more bottles" or (n==1 and "1 bottle" or "" + n + " bottles"))
+ " of beer"
}
Output:
99 bottles of beer on the wall, 99 bottles of beer.
Take one down and pass it around, 98 bottles of beer on the wall.
...
1 bottle of beer on the wall, 1 bottle of beer.
Take one down and pass it around, no more bottles of beer on the wall.

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.
Personal tools
Namespaces

Variants
Actions
Community
Explore
Misc
Toolbox