real language

Bookmarking Digg Diigo DZone Earthlink Google
Windows Live LookLater Ma.gnolia Reddit Rojo StumbleUpon Technorati

Language Expect

Author:Don Libes
Score: (3.01 in 136 votes)

# 99 bottles of beer on the wall, Expect-style
# Author: Don Libes <>

# Unlike programs (
# 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

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

Download Source | Write Comment

Alternative Versions


>>  ron hudson said on 06/05/06 07:30:11

ron hudson Cool, it must be actually drinking the beer as it goes...

>>  Kiyoshi Akima said on 06/06/06 20:30:21

Kiyoshi Akima Shouldn't the program mistype the punctuation now and then?

Download Source | Write Comment

Add Comment

Please provide a value for the fields Name, Comment and Security Code.
This is a gravatar-friendly website.
E-mail addresses will never be shown.
Enter your e-mail address to use your gravatar.

Please don't post large portions of code here! Use the form to submit new examples or updates instead!




Security Code: