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