1#!/depot/path/expect -f
2
3# 99 bottles of beer on the wall, Expect-style
4# Author: Don Libes <libes@nist.gov>
5
6# Unlike programs (http://www.ionet.net/~timtroyr/funhouse/beer.html)
7# which merely print out the 99 verses, this one SIMULATES a human
8# typing the beer song.  Like a real human, typing mistakes and timing
9# becomes more erratic with each beer - the final verse is barely
10# recognizable and it is really like watching a typist hunt and peck
11# while drunk.
12
13# Finally, no humans actually sing all 99 verses - particularly when
14# drunk.  In reality, they occasionally lose their place (or just get
15# bored) and skip verses, so this program does likewise.
16
17# Because the output is timed, just looking at the output isn't enough
18# - you really have to see the program running to appreciate it.
19# Nonetheless, for convenience, output from one run (it's different
20# every time of course) can be found in the file beer.exp.out
21# But it won't show the erratic timing; you have to run it for that.
22
23# For an even fancier version, see http://expect.nist.gov/scripts/superbeer.exp
24
25proc bottles {i} {
26    return "$i bottle[expr {$i!=1?"s":""}] of beer"
27}
28
29proc line123 {i} {
30    out $i "[bottles $i] on the wall,\n"
31    out $i "[bottles $i],\n"
32    out $i "take one down, pass it around,\n"
33}
34
35proc line4 {i} {
36    out $i "[bottles $i] on the wall.\n\n"
37}
38
39proc out {i s} {
40    foreach c [split $s ""] {
41	# don't touch punctuation; just looks too strange if you do
42	if {[regexp "\[,. \n\]" $c]} {
43	    append d $c
44	    continue
45	}
46
47	# keep first couple of verses straight
48	if {$i > 97} {append d $c; continue}
49
50	# +3 prevents it from degenerating too far
51	# /2 makes it degenerate faster though
52
53	set r [rand [expr {$i/2+3}]]
54	if {$r} {append d $c; continue}
55
56	# do something strange
57	switch [rand 3] {
58	    0 {
59		# substitute another letter
60
61		if {[regexp \[aeiou\] $c]} {
62		    # if vowel, substitute another
63		    append d [string index aeiou [rand 5]]
64		} elseif {[regexp \[0-9\] $c]} {
65		    # if number, substitute another
66		    append d [string index 123456789 [rand 9]]
67		} else {
68		    # if consonant, substitute another
69		    append d [string index bcdfghjklmnpqrstvwxyz [rand 21]]
70		}
71	    } 1 {
72		# duplicate a letter
73		append d $c$c
74	    } 2 {
75		# drop a letter
76	    }
77	}
78    }
79
80    set arr1 [expr {.4 - ($i/333.)}]
81    set arr2 [expr {.6 - ($i/333.)}]
82    set shape [expr {log(($i+2)/2.)+.1}]
83    set min 0
84    set max [expr {6-$i/20.}]
85
86    set send_human "$arr1 $arr2 $shape $min $max"
87
88    send -h $d
89}
90
91set _ran [pid]
92
93proc rand {m} {
94    global _ran
95
96    set period 259200
97    set _ran [expr {($_ran*7141 + 54773) % $period}]
98    expr {int($m*($_ran/double($period)))}
99}
100
101for {set i 99} {$i>0} {} {
102    line123 $i
103    incr i -1
104    line4 $i
105
106    # get bored and skip ahead
107    if {$i == 92} {
108	set i [expr {52+[rand 5]}]
109    }
110    if {$i == 51} {
111	set i [expr {12+[rand 5]}]
112    }
113    if {$i == 10} {
114	set i [expr {6+[rand 3]}]
115    }
116}
117