99 Bottles of Beer
One program in 571 languages
 
     
  Submit new example     Change log     History     Links     Tip: internet.ls-la.net     Thanks, Oliver     Guestbook      
Choose languages starting with letter:
0-9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
E   EasyBatch   Easytrieve   eC   EDI C   Eiffel (object orientated)   Eiffel   ELAN   elastiC   Eloquence   Emacs LISP   Ember   Emerald   Erlang   Esofunk   ETA   Ethos Basic   Euphoria   Ex   Excel (single cell)   Excel 4 Macro   Excel   Exec   Expect   Express  
 
  Programming language: E
 
E is the macro language for IBM's EPM editor.

;  99 bottles of beer in E, the macro language for IBM's EPM editor.
-- Todd Fox
/* The most interesting thing about this language is that it has 3
 * different commenting styles and that the macros must be recompiled
 * directly into the editor to be used. */

defproc make_bottle_text(num_bottles)
   if (num_bottles > 1) then
      bottle_text = num_bottles || ' bottles'
   elseif (num_bottles = 1) then
      bottle_text = num_bottles || ' bottle'
   else
      bottle_text = 'No bottles'
   endif

   return(bottle_text)

defproc sing_beer_main_line(num_bottles, is_long)
   lyrics = make_bottle_text(num_bottles) || ' of beer'

   if (is_long) then
      lyrics = lyrics || ' on the wall'
   endif

   insertline lyrics

defproc sing_beer_song()
   init_bottle_cnt = 99
   curr_bottle_cnt = init_bottle_cnt

   do while curr_bottle_cnt >= 1
      sing_beer_main_line(curr_bottle_cnt, 1)
      sing_beer_main_line(curr_bottle_cnt, 0)
      insertline 'Take one down and pass it around'
      curr_bottle_cnt = curr_bottle_cnt - 1
      sing_beer_main_line(curr_bottle_cnt, 1)
      insertline '' -- don't use "insert", existing text will get mixed 
in
   enddo

   sing_beer_main_line(curr_bottle_cnt, 1)
   sing_beer_main_line(curr_bottle_cnt, 0)
   insertline 'Go to the store and buy some more'
   curr_bottle_cnt = init_bottle_cnt
   sing_beer_main_line(curr_bottle_cnt, 1)


; Define a command to execute it from the EPM command line.

defc sing_beer_song
   call sing_beer_song()

; Execute with ctrl-X

def c_X = 'sing_beer_song'

; done
 
  Programming language: EasyBatch
 
' EasyBatch version of 99 Bottles of beer (Bottles.wsb)
' See http://www.gwsoftware.de/easybatch/index.htm
' Philipp Winterberg, http://www.winterbergs.de
'
GLOBALPROZEDUR(main)
	DIM(b;99)
	CONST(@A;STRCAT(" bottle";NUM2CHAR(40);"s";NUM2CHAR(41);" of beer"))	
	CONST(@C;STRCAT(@A;" on the wall"))
	CONST(@D;STRCAT(NUM2CHAR(13);NUM2CHAR(10)))
	CONST(@E;"Take one down, pass it around,")
	CONST(@K;",")
	CONST(@P;".")
	CONST(@T;"99 Bottles of Beer")
DOWHILE(%b%;>;0)
	DISPLAYSHOW(@T;STRCAT(CSTR(%b%);@C;@K;@D;CSTR(%b%);@A;@P;@D))
	WAIT(1)
	DEC(b)
	DISPLAYSHOW(@T;STRCAT(@E;@D;CSTR(%b%);@C;@P;@D))
	WAIT(1)
LOOP()
	DISPLAYCLOSE()
ENDSUB()
 
  Programming language: Easytrieve
 
* 99 bottles of beer
* Easytrieve programming language (Computer Associates)
* (c) R. Heemskerk, systeemprogrammeur@zonnet.nl

JOB INPUT(NULL) NAME BOTTLE-99
DEFINE BOTTLES W 2 N MASK 'Z9'
DEFINE BOTTLEWORD W 7 A
BOTTLES = 99
BOTTLEWORD = 'bottles'
DO WHILE BOTTLES > 0
   DISPLAY BOTTLES ' ' BOTTLEWORD ' of beer on the wall, ' +
      BOTTLES ' ' BOTTLEWORD ' of beer.'
   DISPLAY 'Take one down, pass it around.'
   BOTTLES = BOTTLES - 1
   IF BOTTLES = 1
      BOTTLEWORD = 'bottle'
   END-IF
END-DO
DISPLAY 'No more bottles of beer on the wall, no more bottles of beer.'
DISPLAY 'Go to the store and buy some more.'
STOP
 
  Programming language: eC
 
// eC version of 99 Bottles of beer (Bottles.ec)
// See http://sunset.backbone.olemiss.edu/~bobcook/eC/
// Philipp Winterberg, http://www.winterbergs.de

#include <iostream.h>
#include <iomanip.h>

unsigned int b;

void main () {
        for (b = 99; b > 0; b--) {
                cout<<setw(2)<<b<<" bottle(s) of beer on the wall,\n"<<b;
                cout<<" bottle(s) of beer.\nTake one down, pass it around,\n";
                cout<<setw(2)<<(b-1)<<" bottle(s) of beer on the wall.\n\n";
        }; 
};
 
  Programming language: EDI C
 
// Author: Kurt Svensson, www.inobiz.se, 2003-05-23
const drinkingtime = -300; // Milliseconds
main()
    {
    for (integer bottles = 99; bottles; )
        {
       println (bottles & txt(bottles) & " of beer on the wall");
       println (bottles-- & txt(bottles) & " of beer.");
       println ("Take one down, pass it around,\r\n");
       sleep (drinkingtime);
       }
    println ("Now they are all gone");
    }

string txt (integer bottles)
    {
    string b = " bottle";
    b &= bottles > 1 ? "s";
    return b;
    }
// end-of-program
 
  Programming language: Eiffel (object orientated)
 
class SHELF

      -- A shelf of bottles

creation

   make

feature

   make (l_bottles: INTEGER) is
      require
         positive_bottles: l_bottles >= 0
      do
         bottles := l_bottles
      end

   remove is
      require
         bottles_exist: bottles > 0
      do
         bottles := bottles - 1
      ensure
         removed: bottles = old bottles - 1
      end

   bottles: INTEGER

   short_description: STRING is
      do
         if bottles = 0 then
            Result := "No"
         else
            Result := bottles.out
         end
         Result.append (" bottle")
         if bottles /= 1 then
            Result.append ("s")
         end
         Result.append (" of beer")
      ensure
         result_exists: Result /= Void
      end

   description: STRING is
      do
         Result := short_description
         Result.append (" on the wall, ")
         Result.append (short_description)
         Result.append ("%N")
      ensure
         result_exists: Result /= Void
      end

   empty: BOOLEAN is
      do
         Result := bottles = 0
      end

invariant

   positive_bottles: bottles >= 0
         
end -- class SHELF

class BEER

   -- Produuce the ditty
   -- Nick Leaton

creation

   make

feature

   shelf: SHELF

   make is
      do
         from
            !!shelf.make (99)
         until
            shelf.empty
         loop
            io.put_string (shelf.description)
            shelf.remove
            io.put_string ("Take one down, pass it all around%N%N")
         end
         io.put_string (shelf.description)
         io.put_string ("Go to the store and buy some more%N%N")
         shelf.make (99)
         io.put_string (shelf.description)
      end   
            
end -- class BEER
 
  Programming language: Eiffel
 
class BEERS

creation

    make

feature     -- Creation

    make is
        local
            i : INTEGER
            b : STRING;
        do
            from i := 99 variant i until i <= 0 loop
                if i = 1 then
                    b := " bottle";
                else
                    b := " bottles"
                end -- if
                io.put_integer(i);
                io.put_string(b);
                io.put_string(" of beer on the wall, ");
                io.put_integer(i);
                io.put_string(b);
                io.put_string(" of beer,");
                io.new_line;
                io.put_string("Take one down and pass it around, ");
                i := i - 1;
                io.put_integer(i);
                io.put_string(b);
                io.put_string(" bottles of beer on the wall.");
                io.new_line;
            end -- loop
            io.put_string("Go to the store and buy some more,");
            io.new_line;
            io.put_string("99 bottles of beer on the wall.");
            io.new_line;
        end;

end -- class BEERS
 
  Programming language: ELAN
 
// By Michael Hocke (2002.06.24)

INT VAR number of bottles;

PROCEDURE print how many bottles are on the wall (INT CONST number):

  print number;
  print bottle;
  print trailing text.

  print number:
    IF number = 0 THEN
      put ("No")
    ELSE
      put (number)
    END IF.

  print bottle:
    out ("Bottle");
    IF no <> 1 THEN
      out ("s")
    END IF.

  print trailing text:
    out (" of beer").

END PROCEDURE print how many bottles are on the wall;

say hello;
print song;
say goodbye.

say hello:
  putline ("99 Bottles of Beer");
  putline ("==================");
  line.

print song:
  FOR number of bottles FROM 99 DOWNTO 1 REPEAT
    print first line;
    print second line;
    print third line
  END REPEAT.

say goodbye:
  line;
  putline ("=====================");
  putline ("You need a ride home?");
  line.

print first line:
  print how many bottles are on the wall (number of bottles);
  out (" on the wall, ");
  print how many bottles are on the wall (number of bottles);
  line.

print second line:
  putline ("Take one down and pass it around,").

print third line:
  print how many bottles are on the wall (number of bottles - 1);
  putline (" on the wall");
  line.
 
  Programming language: elastiC
 
// elastiC version of 99 Bottles of beer (Bottles.ec)
// Philipp Winterberg, http://www.winterbergs.de

package bottles;
import basic;

local b = 99;
while (b > 0)
{        
    basic.print(b, " bottle(s) of beer on the wall,\n", 
                b, " bottle(s) of beer.\n");
    b = b - 1;
    basic.print("Take one down, pass it around,\n", 
                b, " bottle(s) of beer on the wall.\n\n");
}
 
  Programming language: Eloquence
 
REM Eloquence-version www.hp-eloquence.com/ By Gunnar Klevefors gk@cyberstore.se
DLG SET ".driver","@localhost"
FOR X=10 TO 1 STEP -1
    POPUP BOX "[Eloqouence version]["&VAL$(X)&" 
    Bottle"&RPT$("s",(X>1))&" of beer on the wall,|"&VAL$(X)&" 
    bottle"&RPT$("s",(X>1))&" of beer.|Take one down and pass it 
    around,|"&VAL$(X-1)&" bottle"&RPT$("s",(X>2))&" of beer on the wall.][OK]"
NEXT X
END
 
  Programming language: Emacs LISP
 
;;Geza Gyuk - gyuk@oddjob.uchicago.edu"

(defun beersong (n)
  "Does the n-beers song."

(progn (insert (int-to-string n) " bottle" (cond ((= n 1) "")
                                                 (t "s")) 
                                         " of beer on the wall,\n")
       (insert (int-to-string n) " bottle" (cond ((= n 1) "")
                                                 (t "s"))
                                         " of beer,\n")
       (insert "take one down and pass it around,\n")
       (insert (cond ((= n 1) "no more")
                     (t (int-to-string (- n 1)))) 
               " bottle" (cond ((= n 2) "")
                               (t "s")) 
               " of beer on the wall.\n\n")
       (cond ((> n 1) (beersong (- n 1))))))
 
  Programming language: Ember
 
#!/usr/local/ember/bin/ember

/* 99 Bottles of Ember Fluid                                  */
/* Phil Homewood dot@atat.dotat.org, 20020905                 */
/* Written in Ember, http://www.hughes.com.au/products/ember/ */

funct yob (int $nbot, int $f)
{
  if ($nbot == 1) { $s = ""; } else { $s = "s"; }
  if ($f==0) {
    if ($nbot == 0) {
      echo ("no more bottles of beer on the wall.\n");
      return (0);
    }
    echo ("$nbot bottle$s of beer on the wall.\n\n");
  }
  echo ("$nbot bottle$s of beer on the wall,\n$nbot bottle$s of beer,\n");
  $nbot--;
  echo ("take one down, pass it around,\n");
  if ($nbot >= 0) { return (yob ($nbot, 0)); }
}

yob (99, 1);
 
  Programming language: Emerald
 
% 99 Bottles of Beer in Emerald
% by David Eddyshaw <david@jeddyshaw.freeserve.co.uk>

const beer <- object beer
  initially
    for i : Integer <- 99 while i > 0 by i <- i - 1
       self.bottles[i]
       stdout.putstring[" of beer on the wall,\n"]
       self.bottles[i]
       stdout.putstring[" of beer.\n"]
       stdout.putstring["Take one down and pass it around;\n"]
       self.bottles[i-1]
       stdout.putstring[" of beer on the wall.\n\n"]
    end for
  end initially
  operation bottles [x : Integer]
    if x = 0 then
       stdout.putstring["No more bottles"]
    elseif x = 1 then
       stdout.putstring["1 bottle"]
    else
       stdout.putint[x,0]
       stdout.putstring[" bottles"]
    end if
  end bottles
end beer
 
  Programming language: Erlang
 
<a href=http://www.ericsson.se/cslab/erlang/>Erlang</a> is a language used for real-time control systems.

% ---------------------------------------------------------------
% Erlang version of the beer song
% Kent Engström, kenen@ida.liu.se
% ---------------------------------------------------------------
% See http://www.ericsson.se/cslab/erlang/ for Erlang information
% ---------------------------------------------------------------

-module(beer).
-export([song/0]).

song() ->
    song(100).

song(0) ->
    done;
song(N) ->
    Bottles=bottles(N),
    Bottles1=bottles(N-1),
    io:format("~s of beer on the wall, ~s of beer.~n",
	      [Bottles,Bottles]),
    io:format("Take one down and pass it around, ~s of beer on the wall.~n",
	      [Bottles1]),
    song(N-1).

bottles(0)->
    "no more bottles";
bottles(1)->
    "1 bottle";
bottles(N)->
    lists:append(integer_to_list(N)," bottles").
 
  Programming language: Esofunk
 
See http://www.azstarnet.com/~jeffryj/esofunk.html

'label, offset, memory positions used
int N  0
int X1 1
int X2 2
int X3 3
io     3
N=99
until N<=0 {
  call NUM : call SONGA : call SONGB
  output ",",0Dh,0Ah
  call NUM : call SONGA
  output ".",0Dh,0Ah,"Take one down, pass it around,",0Dh,0Ah
  N-=1
  call SONGA : call SONGB
  output ".",0Dh,0Ah
}
goto END
*NUM {
  X1=N : X2=X1 : X2/=10 : X3=X2 : X3*=10 : X1-=X3
  X1+="0" : X2+="0"
  output X1,X2
}
*SONGA { output " bottles of beer" }
*SONGB { output " on the wall" }
*END
'#AB,<CR>#AC#AB.<CR>
'99 bottles of beer on the wall,
'99 bottles of beer.
'Take one down, pass it around,
'98 bottles of beer on the wall.
 
  Programming language: ETA
 
See: http://www.miketaylor.org.uk/tech/eta/doc/

*** NASTY ENID BLIETON! *** ("bottles.eta", written by Mike Taylor)
	Nutmeg.  Why?  Burnt eats are improved by its characteristic odour
	Nude.  Why?  Runty default suggests it's not such a HOT idea.
vvvvvvvv	Brandenburg tess3r@ct [1-6] --
Sun 3/80: turkey?  Dung-TECH CRT
^^^^^^^^	>>> O! <<<
		Nut grenade CRT
		Drunken quake chum
Uncle handymen: cutesy dust
fungus sell-out (null turkey @ Dung-TECH turf)
	-- puny, ugly, rubbery chum
Brandenburg tesst 504 468
 sbcdnfgtejklmnapqrieutwxyz	*b*d*fg**jklm**pq***u**xyz
  nbcdtfgoejklme*pqr**uvwxyz	*bc**f*****lm***qr**uv*x**
   nbcdefgnsjklmsepqrssuvwxyz	*bcd*fg**jk*m**pqr**uvw*yz
	(@ Dung-TECH ...)
@unt1e @untie T (Auntie?  And what's with all the Dung-TECH stuff?)
	[Antena 4 ET]
NT *ex -- Dung-TECH turf!
Dung-TECH!!
	[Anten@ 4 (tt) ET]
>> nenaaaenahoenahoenahheniienahienatseniie <<	NT-eat: No optimisation
>>> naaoenahoenatoenaaienaaienatsenahheniie <<<	NT-eat: No optimisation
Ant grenade, truly.
@unt1e Dung-TECH turf!!!
Dung-TECH!!!!
Ant grenad3 set (2 ugly!)
>> nenatoenatoentssenaoheniienahoe <<	NT-eat: No optimisation
>>> nahsenaaieniienatnenatseniie <<<	NT-eat: No optimisation
Ant grenade: truly ugly & cruddy.
Nurture Dung-TECH turf!!!! (it needs watering & occasional feeding)
fungal chute,
	NE [hanten] ->	"concept"
	NS [aeoni] ->	"video"
	NE [hanten] ->	"asymmetry"
	NT [*] ->	"Romeo"
	    >> nentoenahaenatnenaanenatse <<
	   >>> naaaentsseniienaaienatheniie <<<
	  >>>> naaoenaaoentssenaaheniiensae <<<<
	 >>>>> natnenaohenatsenahaeniienahoe <<<<<
	>>>>>> natnenatseniienahoenataentssentnhe <<<<<<
Antena <- ET,
Runty Jules;
Unruly Czech lantern concept
	2nd toe; 2nd toe; Oo!
	2nd belch => ninety
		*** NEWT!! ***
 
  Programming language: Ethos Basic
 
rem 'Ethos Basic version of 99 Bottles of beer (Bottles.eto)'
rem 'See http://www.ethos.tv/show_downloads.asp'
rem 'Philipp Winterberg, www.winterbergs.de'
     
for b = 99 to 1 step -1
 output b;" bottle(s) of beer on the wall,"
 output b;" bottle(s) of beer."
 output "Take one down, pass it around,"
 output b-1;" bottle(s) of beer on the wall." : output " "
next
 
  Programming language: Euphoria
 
-- Euphoria
-- www.rapideuphoria.com
--
-- Author: Don Phillips
-- 
atom Beers
sequence Bottles

Beers = 99
while Beers != 0 do
	Bottles = "Bottle" & (Beers!=1)*'s'
	printf( 1, "%d %s of beer on the wall,\n", {Beers,Bottles} )
	printf( 1, "%d %s of beer.\n", {Beers,Bottles} )
	printf( 1, "Take one down, pass it around,\n", {} )
	Beers -= 1
	Bottles = "Bottle" & (Beers!=1)*'s'
	printf( 1, "%d %s of beer on the wall.\n\n", {Beers,Bottles} )
end while
 
  Programming language: Ex
 
a
XX bottles of beer on the wall.

XX bottles of beer on the wall,
XX bottles of beer,
Take one down, pass it around,
/^\$/d e|@e
9 8 7 6 5 4 3 2 1 0
$ ya b|$put b|$s/. //
@c|@c|@c|@c|@c|@c|@c|@c|@c
.
$d d|$d c|@d
$-9,$s/^\(.\).*/X\1/
/^X9/,ya y
$-9,s=^X\(.\)$=s/X/\1/=
$-9,s=^=$put y|$-9,$=
/^\//d c|@d|@c
/^90/ma f|/^89/,/^80/mo 'f
6,$s=^..$=$put y|%s/^XX/&/=
1,5d y
g/^\$/d e|@e
1,2d
%s/^0//
$s/.*/Go to the store, buy some more./
%s/^1 bottles/1 bottle/
%p
 
  Programming language: Excel (single cell)
 
/*26.09.2002 by AMi  <mailto:amiundyvonne@web.de*/> amiundyvonne@web.de*/
/*Used german Excel-version: WENN means IF, ZEILE means ROW            */

=WENN(ZEILE(A1)<100;100-ZEILE(A1) & " bottles of beer on the wall, " &
100-ZEILE(A1) & " bottles of beer, take one down and pass it
around,";WENN(ZEILE(A1)=100;"no more bottles of beer on the wall, no more
bottles, go to the store and by some more, 99 bottles of beer";""))
 
  Programming language: Excel 4 Macro
 
Paste the following lines into an Excel 4 Macro file 
(.xlm extension - it wont work with a regular sheet) 
in the cells A1:A10.

99 bottles of beer - Excel 4 Macro - by Christian Schmidt
To run the macro: right click on cell A3 and select "Run ..."
=SET.VALUE(B1; 99)
=SET.VALUE(B2; "99 bottles of beer")
=SET.VALUE(B3; B2 & " on the wall, " & B2 & ", " & IF(B1 > 0; "take one down and pass it around, "; "go to the store and buy some more, "))
=SET.VALUE(B1; B1-1)
=SET.VALUE(B2; IF(B1>0; B1; IF(B1=0; "no more"; 99)) & " bottle" & IF(B1<>1; "s"; "") & " of beer")
=SET.VALUE(INDEX(C1:C100;99-B1;1);B3&B2&" on the wall")
=IF(B1>=0; GOTO(A5))
=HALT()
 
  Programming language: Excel
 
Admittedly, yet another VB application.

Sub Beers()
' 99 bottles of beer on the wall
' Visual Basic for Excel version
' by Alejandro Julien (ajulien@tonatiuh.sis.uia.mx)
' Done with Excel 7 (Windows '95)
'
' It will start from the first cell of the first worksheet
' and move on downwards.
    Dim Cervezas As Integer 'Cervezas = beer in spanish
    Dim miCelda As Integer  'miCelda = myCell in spanish
    Worksheets(1).Activate
    ' Colors
    Range("A1:AA1").Interior.Color = RGB(0, 0, 128)
    ActiveCell.Offset(1, 0).Value = "by Alejandro Julien"
    Range("A1:A204").Font.Color = RGB(0, 0, 128)
    ' Title
    Range("A1").Select
    With ActiveCell
        .Value = "The 99 bottles of beer on the wall song"
        .Font.Size = 18
        .Font.Color = RGB(255, 255, 255)
    End With
    With ActiveCell.Offset(2, 0)
        .Value = "(ajulien@tonatiuh.sis.uia.mx)"
        With .Font
            .Italic = True
            .Size = 8
        End With
    End With
    miCelda = 3
    ' GO!
    For Cervezas = 99 To 2 Step -1
        ActiveCell.Offset(miCelda, 0).Value = Cervezas & " bottles of beer on the wall, " & Cervezas & " bottles of beer"
        miCelda = miCelda + 1
        ActiveCell.Offset(miCelda, 0).Value = "take one down and pass it around"
        miCelda = miCelda + 1
    Next
    ' ONE_BEER_EXCEPTION handling *whew!*
    ActiveCell.Offset(miCelda, 0).Value = "One bottle of beer on the wall, one bottle of beer"
    miCelda = miCelda + 1
    ActiveCell.Offset(miCelda, 0).Value = "take it down and pass it around"
    miCelda = miCelda + 1
    ' Beer's over
    ActiveCell.Offset(miCelda, 0).Value = "No more bottles of beer on the wall, no more bottles of beer"
    miCelda = miCelda + 1
    ActiveCell.Offset(miCelda, 0).Value = "Go to the store and buy some more"
    miCelda = miCelda + 1
    ' Sponsor's message
    With ActiveCell.Offset(miCelda, 0)
        .Value = "...but make sure it's mexican beer!"
        .Font.Italic = True
        .Font.Size = 8
    End With
    Application.Caption = "Cerveza mexicana siempre!"
    ' No kidding. If you have the chance, try a good mexican beer (:
    '-------
    ' This piece of code goes for the "99 bottles of beer" homepage,
    ' and may be used by whoever finds it useful to show Language,
    ' way of doing the chore, or proof that programmers seem to have
    ' no life (even though this is not a complete truth...)
    ' <#include "disclaim.h>
End Sub
 
  Programming language: Exec
 
* EXEC version of 99 Bottles of beer program
* By Torbjørn Vaaje (<a href="mailto:etotv@eto.ericsson.se">etotv@eto.ericsson.se</a>)
*
&BEERS = 99
&S = ES
&LOOP 5 99
&TYPE &BEERS BOTTL&S OF BEER ON THE WALL, &BEERS BOTTL&S OF BEER.
&BEERS = &BEERS - 1
&IF &BEERS = 1 &S = E
&IF &BEERS = 0 &BEERS = NO_MORE
&TYPE TAKE ONE DOWN AND PASS IT AROUND, &BEERS BOTTL&S OF BEER ON THE WALL
 
  Programming language: Expect
 
#!/usr/local/bin/expect

# 99 bottles of beer on the wall, Expect-style
# Author: Don Libes <libes@nist.gov>

# Unlike programs (http://www.ionet.net/~timtroyr/funhouse/beer.html)
# which merely print out the 99 verses, this one SIMULATES a human
# typing the beer song.  Like a real human, typing mistakes and timing
# becomes more erratic with each beer - the final verse is barely
# recognizable and it is really like watching a typist hunt and peck
# while drunk.

# Finally, no humans actually sing all 99 verses - particularly when
# drunk.  In reality, they occasionally lose their place (or just get
# bored) and skip verses, so this program does likewise.

# Because the output is timed, just looking at the output isn't enough
# - you really have to see the program running to appreciate it.
# Nonetheless, for convenience, output from one run (it's different
# every time of course) can be found in the file beer.exp.out
# But it won't show the erratic timing;  you have to run it for that.

proc bottles {i} {
	return "$i bottle[expr $i!=1?"s":""] of beer"
}

proc line123 {i} {
	out $i "[bottles $i] on the wall,\n"
	out $i "[bottles $i],\n"
	out $i "take one down, pass it around,\n"
}

proc line4 {i} {
	out $i "[bottles $i] on the wall.\n\n"
}

proc out {i s} {
	foreach c [split $s ""] {
		# don't touch punctuation; just looks too strange if you do
		if [regexp "\[,. \n\]" $c] {
			append d $c
			continue
		}

		# keep first couple of verses straight
		if {$i > 97} {append d $c; continue}

		# +3 prevents it from degenerating too far
		# /2 makes it degenerate faster though

		set r [rand [expr $i/2+3]]
		if {$r} {append d $c; continue}

		# do something strange
		switch [rand 3] {
		    0 {
			# substitute another letter

			if [regexp \[aeiou\] $c] {
				# if vowel, substitute another
				append d [string index aeiou [rand 5]]
			} elseif [regexp \[0-9\] $c] {
				# if number, substitute another
				append d [string index 123456789 [rand 9]]
			} else {
				# if consonant, substitute another
				append d [string index bcdfghjklmnpqrstvwxyz [rand 21]]
			}
		    } 1 {
			# duplicate a letter
			append d $c$c
		    } 2 {
			# drop a letter
		    }
		}
	}

	set arr1 [expr .4 - ($i/333.)]
	set arr2 [expr .6 - ($i/333.)]
	set shape [expr log(($i+2)/2.)+.1]
	set min 0
	set max [expr 6-$i/20.]

	set send_human "$arr1 $arr2 $shape $min $max"

	send -h $d
}

set _ran [pid]

proc rand {m} {
	global _ran

	set period 259200
	set _ran [expr ($_ran*7141 + 54773) % $period]
	expr int($m*($_ran/double($period)))
}

for {set i 99} {$i>0} {} {
	line123 $i
	incr i -1
	line4 $i

	# get bored and skip ahead
	if {$i == 92} {
		set i [expr 52+[rand 5]]
	}
	if {$i == 51} {
		set i [expr 12+[rand 5]]
	}
	if {$i == 10} {
		set i [expr 6+[rand 3]]
	}
}

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

11 botqle off baer oc tbe wakl,
1 botplo of beer,
take onne da, pass itt arounm,
0 yotglees oof beeeer on tte walll.
 
  Programming language: Express
 
Custom language used by IRI Software

"  Language:  Express
"  Written by Lori Smallwood, IRI Software
"  April 12, 1997

vrb _beer  int
_beer = 99

while _beer gt 0
  do
    shw joinchars(_beer ' bottles of beer on the wall,')
    shw joinchars(_beer ' bottles of beer... ')
    shw 'Take one down, pass it around,'
    _beer = _beer - 1
    shw joinchars(_beer ' bottles of beer on the wall!')
  doend
 
  © Oliver Schade <os@ls-la.net>, Generated: 06.06.2003 17:38:32