There's more than one way to do things PerlMonks

### Drunk on golf: 99 Bottles of Beer

by eyepopslikeamosquito (Chancellor)
 on May 08, 2011 at 12:41 UTC Need Help??

In my opinion, its simplicity and directness reflects the basic nature of existence. Eventually, we all will have passed around 99 bottles of beer and there will be no more bottles on the wall.

-- Modern Drunkard Magazine (top 86 alcohol songs of all time, featuring 99 bottles of beer at #1)

Apart from its popularity as a drinking song, the classic 99 Bottles of Beer is ideal for singing to while away the hours on long trips because it takes a long time to sing and its repetitive format is easily memorized. It also pops up often in popular culture, especially film and TV. I remember the late Patrick Swayze, for example, singing it over and over again to Whoopi Goldberg in the movie Ghost in order to get her to go downtown (which she would never normally do).

The article capitalizes on the tendency of popular songs to evolve from long and content-rich ballads to highly repetitive texts with little or no meaningful content. Knuth writes that "our ancient ancestors invented the concept of refrain" to reduce the space complexity of songs, which becomes crucial when a large number of songs is to be committed to one's memory ... more ingenious approaches yield songs of complexity O(logN), a class known as "m bottles of beer on the wall".

-- The Complexity of Songs by Donald Knuth (1977)

While the affection for this song among computer programmers may have begun in 1977, with the publication of Knuth's seminal paper, it didn't become wildly popular until 1994, when some nitwit posted the entire lyrics of the song to a humour mailing list, provoking a BASIC version to be written:

```10 REM BASIC Version of 99 Bottles of beer
20 FOR X=100 TO 1 STEP -1
30 PRINT X;"Bottle(s) of beer on the wall,";X;"bottle(s) of beer"
40 PRINT "Take one down and pass it around,"
50 PRINT X-1;"bottle(s) of beer on the wall"
60 NEXT
to "save mailing list bandwidth". It snowballed from there until today we can now choose from more than 1400 programming language variations.

Over the years, many different Perl solutions have been proposed. On December 25 1998, for instance, Damian Conway composed a version using his Lingua::EN::Inflect module:

```use Lingua::EN::Inflect 'inflect';
\$n=shift||99;
print inflect<<BURP while \$n;
NO(bottle of beer,\$n) on the wall, NO(bottle of beer,\$n)!
Take one down, pass it around,
NO(bottle of beer,@{[--\$n]}) on the wall.
BURP

Finally, we come to the reason for this node. Despite being the most popular code golf game of all time, precious few quality bottle golf solutions have ever been published. While there are vast hordes of really awful bottle golf solutions out there, the only half way decent one I'm aware of was whipped up in a few hours by Ton Hospel and Mtv Europe way back in 2003:

```sub
b{[@b=(abs||No,bottle."s"x!!++\$_,of,beer),on,the,wall]}print
"@{+b},\n@b,\nTake one down, pass it around,\n@{+b}.\n"
for-pop||-99..-1

Many top quality golf solutions have been concocted though. For example, the 99 Bottles of Beer challenge at codegolf.com attracted over 1000 entries, more than twice as many as the next most popular game. And the leading scoreboard entries there are very short. It's just that none of them are available for public viewing.

Being a repeat codegolf vandal, I'm not shy about publishing my codegolf entries here, especially given the codegolf site seems to have been abandoned, and their beer bottle challenge has been running for over five years now. There is one caveat though: after discussions with the founders of this new PHP golf site, I won't be discussing my PHP solutions in this node, so as not to spoil their most popular game. Apart from that, I won't hold back, analysing general approaches to writing the shortest possible code to emit the lyrics of the classic drinking song and revealing all interesting Perl, Ruby and Python solutions I found while playing this game.

Rules of the game

In this 99 Bottles of Beer challenge, your program takes no input and must emit the entire lyrics of the song to stdout as follows:

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

97 bottles of beer on the wall, 97 bottles of beer.
Take one down and pass it around, 96 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.
Go to the store and buy some more, 99 bottles of beer on the wall.
Your program's stdout must match the above output exactly, with one exception: the codegolf.com entry checking program strips trailing whitespace, so emitting any amount of trailing whitespace is permitted. Note that anything written to stderr is ignored, as is the program's exit code. So terminating your program by crashing it (dividing by zero, for example) is legitimate ... and surprisingly common and strangely satisfying.

Getting Started

The five times this game has been played here at Perl Monks:

did not turn up anything useful. Perhaps because of its popularity and low barrier of entry, if you randomly google for "99 bottles of beer golf", you'll be overwhelmed by some mind-bogglingly awful golf. Given the high number of hits, it's possible I overlooked some gems, but the only useful prior art I found for this game was from a Korean (kldp) web site where two different 174 stroke solutions had been posted:
```sub b{[@b=(abs||99,bottle."s"x!!++\$_,of,beer),on,the,wall]}print"@{+b}
+, @b.
",\$_?"Take one down and pass it around":"Go to the store and buy some
+more",", @{+b}.

"for-99..-1
and:
```sub b{@b=(-\$_++||99,bottl.(\$_?es:e),of,beer);"@b on the wall"}print+b,
+", @b.
",\$_?"Take one down and pass it around, ":"Go to the store and buy som
+e more, ",b,".

"for-99..-1
If you squint, you'll see that these two are based on the venerable 2003 solution of Hospel and Europe.

Given that the leader at this time, Polish golfing veteran "0xF", had already posted a 165-stroker, I was not hopeful that this approach could seriously threaten this experienced Polish golfing maestro. Still, I had to try at least.

First, I noticed that Ton and Mtv's snippet can be further shortened by changing "s" to 's' and embedding the sub inside the first @{} block like so:

```@{sub b{[@b=(abs||No,bottle.'s'x!!++\$_,of,beer),on,the,wall]}b}
This saves a single stroke because the first +b in the original is replaced by a bald b.

I then stared at the kldp solution, looking for anything unsightly. Well, that -99..-1 is an eyesore ... so I just hacked it out, reducing this solution from 174 to 168 strokes:

```print"@{sub b{[@y=(\$n||=99,bottle.'s'x1!~\$n,of,beer),on,the,wall]}b},
+@y.
\$_, @{b--\$n}.

"for("Take one down and pass it around")x98,"Go to the store and buy s
+ome more"
Notice that this solution exploits undeclared Perl variables (i.e. \$n above) being initialized to undef. I employed this tactical trick time and time again in this game in both Perl and PHP ... though not in Python, where it can't be done. You can pull it off in Ruby too, though you must scour RubyDoc for any "Perl-compatible" Ruby special variables (e.g. \$., \$_, \$&, \$', \$`, ...) that might be gainfully employed.

Around this time, I also composed Python (195) and Ruby (191) equivalents of my early Perl subroutine-based solution.

Note that in the Python solution:

```n=99
z=lambda:`n or 99`+" bottle"+"s of beer on the wall"[n==1:]
while n:y=z();n-=1;print"%s, %s.\n"*2%(y,y[:-12],n and"Take one down a
+nd pass it around"or"Go to the store and buy some more",z())
string slices are employed, which is almost mandatory when golfing in Python.

Though my first Ruby attempt:

```def z
"#{N<1?99:N} bottle#{'s'if N!=1} of beer"end
(N=99).times{puts"%s, %s.
"*2%[z+w=" on the wall",z,1>(N-=1)?"Go to the store and buy some more"
+:"Take one down and pass it around",z+w],""}
is ungainly in the extreme, notice the curious expression:
```z+w=" on the wall"
This syntactic quirk, where an assignment expression, sans parentheses, can be placed at the end of an expression, is used ad nauseam in both Ruby and PHP golf ... though not in Perl or Python, where it produces a syntax error.

I felt quite hungover around this time because these solutions were over ten strokes behind in Python and nearly twenty behind in Ruby! It was becoming increasingly obvious that using a function was consuming far too many strokes and therefore had to be eliminated. Less obvious in Perl perhaps, given I was only three behind, but my golfing instincts were telling me that a Perl solution without a sub should be considerably shorter than my 168-stroke subroutine-based solution.

Though I reached this conclusion some years ago, I didn't have the time to pursue it back then, and so put this game on hold for a little while. Actually, I forgot about it for several years until "reminded" of it by approaches from the founders of a new PHP golf site, where they were hosting the identical game.

When I returned to this game earlier this year, I noticed that "Rhebus", a young whipper snapper from London, had posted a sensational 162 strokes, thus snatching the Perl lead from the grasp of grizzled Polish expert 0xF.

Bottle Golf Tip No 1: Don't use a function

To eliminate the function, you need somehow to set up the loop so that the count of beer bottles is the same for each loop iteration. That is, instead of the "natural":

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

97 bottles of beer on the wall, 97 bottles of beer.
Take one down and pass it around, 96 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.
Go to the store and buy some more, 99 bottles of beer on the wall.
where each paragraph must emit both n bottles and n-1 bottles, you might try breaking up the song as shown below:
```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.

97 bottles of beer on the wall, 97 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.
-----------------------------------------------------------------
Go to the store and buy some more, 99 bottles of beer on the wall.
That's better! Note that, crucial for a function-free solution, the two lines between the lines of dashes above now contain the same beer bottle count. There is a catch though: you must deal somehow with the annoyance of the first iteration, which does not contain a Take one down... line. The last line is also a pest, but can be dealt with simply by printing it after the main loop has terminated. As a variation, you can place the pestiferous last line first:
```Go to the store and buy some more, 99 bottles of beer on the wall.

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.

97 bottles of beer on the wall, 97 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.
which nicely clarifies the essentially circular nature of the ditty. The "uniformity" of this output is attractive for a golfer because uniformity often means shorter code. To exploit this uniformity, however, you cannot just print the song on the fly; you must instead build a string or list in a loop, then print two separate bits of it at the end.

Let's see how this might look in Perl:

```join("Take one down and pass it around",map{@c=(@b=(99-\$_,bottle.'s'x!
+/98/,of,beer),on,the,wall);", @c.

@c, @b.
"}0..98)=~/

/;print\$'."Go to the store and buy some more\$`"
Hmmm, 173 strokes. Not bad for a first attempt!

Regexes always win (Mtv's law of golf)

As you can see, the regex "side-effect variables", \$' and \$`, look very promising in this game -- as they so often are in golf.

It seems that Mtv's law applies to Ruby too, because this algorithm is actually better suited to Ruby than Perl due to some quirky Ruby syntactic sugar. You see, in Ruby:

```somearray.join("string")
can be equivalently expressed as:
```somearray*"string"
So, in Ruby, this new function-free approach effortlessly shaved eleven strokes from my earlier function-based solution:
```"Go to the store and buy some more"+(-99..-1).map{|n|", #{c="#{b=-n,"
+bottle"+"s of beer"[1/-n,9]} on the wall"}.

#{c}, #{b}.
"}*"Take one down and pass it around"=~/

/;puts\$'+\$`
180 strokes! Though hardly the shortest, this is one of my favourite solutions because it directly expresses the (circular) idea of putting the last line first.

Update: Much later I reduced this by three strokes to 177:

```"Go to the store and buy some more"+(-99..-1).map{|n|", #{b=-n," bottl
+es"[0,6-n]+" of beer"," on the wall"}.

#{b}, %s%s.
"%b}*"Take one down and pass it around"=~/

/;puts\$'+\$`

What about Python? Alas, Python places many obstacles in the way of this approach:

• Python does not have a short 0..98 range operator. The best you can do is range(99), which generates the sequence 0..98.
• Unlike Perl and Ruby, regexes are not built into the Python language, usually making them too long for golf.
• While map in Perl and Ruby takes a block/closure, Python map takes a function or lambda (both too long for golf) while list comprehensions/generator expressions take an expression, which nicely encourages side-effect-free functional purity, while being an utter nuisance for golfers.
• Finally, and worst of all, notice that assignment is an operator in Perl and Ruby and may therefore be used as part of larger expressions. Not so in Python, where assignment is a statement and cannot be used as part of a larger expression. This cruel design decision has inflicted incalculable pain on Python golfers over a period of many years.
In any case, I couldn't make this approach short in Python. For example, though this one does work:
```r="Take one down and pass it around".join(", %s.\n\n"%c+c+", %s.\n"%c[
+:-12]for c in[`99-z`+" bottle"+"s of beer on the wall"[z/98:]for z in
+ range(99)])
print r[35:]+"Go to the store and buy some more"+r[:34]
it's 207 strokes in length. Ouch. Of course, it's perfectly possible that I've overlooked some more golfish Python list comprehension syntax here. If so, please respond away.

After giving up on a functional approach, the shortest way I could find to implement this idea in Python was the following 193-stroker:

```n=99
y="Go to the store and buy some more"
while n:c=`n`+" bottle"+"s of beer on the wall"[1/n:];y+=", %s.\n\n"%c
++c+", %s.\nTake one down and pass it around"%c[:-12];n-=1
print y[68:-32]+y[:66]
Though admittedly two strokes better than my original function-based entry, this solution is a gaping eleven strokes behind the lead, 182 strokes, held by Norwegian teetotaler "hallvabo" -- who I contend has nowadays taken over the mantle of No. 1 Python golfer from Mark Byers.

In desperation, I tried a completely different line-at-a-time function-free approach in Python:

```c=198
while c:y=`c/2or 99`+" bottle"+"s of beer on the wall"[3/c%3:];print[y
+,"Take one down and pass it around","Go to the store and buy some mor
+e"][1/c+c%2]+",",[y[:-12]+".",y+".\n"][c%2];c-=1
To my enormous frustration, this solution, in addition to being unspeakably ugly, turned out to have exactly the same score, 193 strokes. No improvement. At all. Aaargh!

The 187-stroke Ruby translation below is presented as an example of an accepted solution that "cleanly terminates" by dividing by zero:

```n=198
loop{\$><<[y=[n/2%-99+99," bottle"+"s of beer"[3/n%3,9]," on the wall"]
+,"Take one down and pass it around","Go to the store and buy some mor
+e"][j=1/n+1&~n-=1]<<", #{y[0,2+j]}.
"+\$/*j}
Note that the three stroke 198 above is routinely replaced by the two stroke ?ascii-char-with-ord-198 when golfing in Ruby.

Bottle Golf Tip No 2: Consider counting from 1 up to 99 not 99 down to 1

Though counting down from 99 to 1 seems "natural", golfers should always experiment with switching things around, to see if doing so shortens the code.

General golfing tip: Look for the part of your solution that makes you pull a face and try to shorten it.

With the possible exception of Python, all the above attempts at solving the crucial "1 bottle" versus "2-99 bottles" plural inflection problem have caused me to pull a face. Here is the parade of horrors seen so far:

```bottle."s"x!!++\$_,of,beer        # Perl
bottl.(\$_?es:e),of,beer          # Perl
bottle.'s'x1!~\$n,of,beer         # Perl
bottle.'s'x!/98/,of,beer         # Perl
"bottle#{'s'if N!=1} of beer"    # Ruby
" bottle"+"s of beer"[1/-n,9]    # Ruby
" bottles"[0,6-n]+" of beer"     # Ruby
"bottle"+"s of beer"[3/n%3,9]    # Ruby
"bottle"+"s of beer"[1/n:]       # Python

As you might expect, I was eager to eliminate all this inflective claptrap, replacing it with something simple and short like:
```"bottle\$x of beer"
where \$x is the empty string for n==1 and "s" for n>1. Can this be achieved? Well, in languages where uninitialized variables display an empty string, it's easily pulled off simply by counting upwards from 1 to 99 ... so long as you can find a short way to set \$x to "s" right after the first iteration. Of course, you'd need to build the output string in a loop and emit it at the end, yet the regex solutions described above already do that, courtesy of the \$' and \$` special variables.

Instead of \$x, how about applying Mtv's law yet again and (indirectly) exploit a regex variable? As is common in golf, once I'd thought of the basic idea, a short solution materialized pretty quickly:

```@c=(@b=(++\$n,bottle.\$&,of,beer),on,the,wall),s/^/Take one down and pas
+s it around, @c.

@c, @b.
/,/s/for(\$_)x99;/,.*

/;print\$'."Go to the store and buy some more\$&"
165 strokes! Caught 0xF at last!

Here we're building the string from the end to the beginning, from 1 to 99, in \$_ by using the regex substitution s/^/.../. We're also exploiting a starting value of zero for the uninitialized \$n. Finally, note that we're further exploiting an aliasing quirk of the perl for loop by building a single \$_ value via a (\$_)x99 list. I remembered this surprising trick from the 2002 Cantor game in TPR03 (see Mtv's pdf book of Golf), where a winning Cantor solution was:

```s/./\$& \$&/gfor(\$_="-
")x pop;print

After a further period of shuffling things around, I finally tied for the lead at 162 strokes by replacing for with until like so:

```/s/until@c=(@b=(++\$n,bottle.\$&,of,beer),on,the,wall),s/^/Take one down
+ and pass it around, @c.

@c, @b.
/,/, 99.*

/;print\$'."Go to the store and buy some more\$&"
Note that the /, 99.*\n\n/ expression serves a dual purpose in that, in addition to terminating the until loop, this regex sets the \$' and \$& special variables to the desired values. Note further that if leading whitespace were allowed (as it is at phpgolf.org), this regex can be shortened by two strokes to /, 99.*/.

Further 162-stroke variations are:

```/s/until@c=(\$b=++\$n." bottle\$& of beer",on,the,wall),s/^/Take one down
+ and pass it around, @c.

@c, \$b.
/,/, 99.*

/;print\$'."Go to the store and buy some more\$&"
and:
```/s/until@c=(++\$n." bottle\$& of beer",on,the,wall),s/^/Take one down an
+d pass it around, @c.

@c, \$c[0].
/,/99.*

/;print\$'."Go to the store and buy some more, \$&"

I have an uneasy feeling that this solution is not the end of the road and that a future Perl golfer may further shorten it.

Can we translate this approach into Ruby? Yes. It's not as effective as the Perl version because Ruby lacks Perl's built-in s/^/.../ substitution operator. But it still shaves two strokes off our previous best Ruby solution:

```1.upto(99){|n|~/s/;\$_="Take one down and pass it around, #{c="#{b=n,"
+bottle#\$& of beer"} on the wall"}.

#{c}, #{b}.
#\$_"}
~/,.*

/;puts\$'+"Go to the store and buy some more"+\$&
178 strokes. And here's an alternative 178-stroker using until:
```n=0
~/s/ until/, 99.*

/=~\$_="Take one down and pass it around, #{c="#{b=n+=1," bottle#\$& of
+beer"} on the wall"}.

#{c}, #{b}.
#\$_";puts\$'+"Go to the store and buy some more"+\$&
The need for a space before until is unfortunate. As is the need for the n=0 initialization, which is not required in Perl.

As already discussed, I saw no hope of translating this approach into Python, where short "special variables" (e.g. \$_, \$&) do not exist and where regexes are not built into the language.

Bottle Golf Tip No 3: Unearth language-specific tactical tricks

My previous golfing articles focused mostly on the dark art of magic formulae. As you may have noticed above, magic formulae hardly feature in this game. You must rely instead on old fashioned classical golf technique, especially language-specific tactical tricks.

Of course. The true&tested method of "Can't possibly work, let's try it anyway."

-- Eugene van der Pijll

One of the best ways to find tactical tricks in the dusty corners of a programming language is to simply try ridiculous things and see what happens. Modern languages are so large and complex that it's not practical to precisely specify every little detail in the core language and libraries ... which offers opportunities for golfers to exploit implementation quirks.

Desperate to save a stroke or two, I experimented with how the % printf-like operator behaves when given more arguments than expected:

```b=[99," bottles of beer"," on the wall"]
print "%s%s\n"%b
Running this little test program produces:
```99 bottles of beer
in Ruby, but:
```TypeError: not enough arguments for format string
in Python.

In case you're interested, running this little test program in Perl:

```@b=(99," bottles of beer"," on the wall");
printf "%s%s\n",@b;
produces the same result as Ruby. That is, Ruby and Perl silently ignore extra arguments to printf. They also automatically "flatten" the array. Python does not. Python also checks the number of printf arguments more strictly; that is, this Python program:
```b=[99," bottles of beer"," on the wall"]
print "%s%s\n"%tuple(b)
fails with:
```TypeError: not all arguments converted during string formatting
whereas this one:
```b=[99," bottles of beer"," on the wall"]
print "%s%s%s\n"%tuple(b)
works, printing:
```99 bottles of beer on the wall

I was able to exploit Ruby's printf behaviour, described above, to shave two precious strokes and so move into outright second place, three strokes behind "Ruby golfing god", flagitious:

```1.upto(99){|n|~/s/;\$_="Take one down and pass it around, #{c=n," bottl
+e#\$& of beer"," on the wall"}.

#{c}, %s%s.
#\$_"%c}
~/,.*

/;puts\$'+"Go to the store and buy some more"+\$&
176 strokes! Cheers! Staggering into second place in Ruby was a pleasant surprise after languishing twenty strokes behind the leaders early in this game.

I hope you've enjoyed my long journey through this game. It's time for me to sober up now and give the game of golf a rest for a while.

All languages (1237 entries):

```  1st  162  rhebus                             Perl
2nd  162  eyepopslikeamosquito               Perl
3rd  165  0xF                                Perl
4th  166  dgzj001                            Perl
5th  167  shinh                              Perl
6th  170  komondorok                         Perl
7th  170  ySas                               Perl
8th  171  flagitious                         Perl
9th  171  o0lit3                             Perl
10th  171  gorash                             Perl

Perl (273 entries):

```  1st  162  rhebus
2nd  162  eyepopslikeamosquito
3rd  165  0xF
4th  166  dgzj001
5th  167  shinh
6th  170  komondorok
7th  170  ySas
8th  171  flagitious
9th  171  o0lit3
10th  171  gorash
11th  173  jgoon
12th  173  volte
13th  174  g.allen
14th  174  terjek
15th  174  bearstearns
16th  174  raymundo
17th  174  ott
18th  174  ozy4dm
19th  174  sixmen
20th  174  Aidy
21st  174  szeryf
22nd  174  Shuman
23rd  174  stressedlemming
24th  175  Ciaran
26th  175  ergasun
27th  175  Nisse
28th  176  jojo
29th  176  Zeithase
30th  177  moq
31st  177  olivier
32nd  178  leus
33rd  179  kounoike
34th  179  yojeb
35th  180  Bryan
36th  181  lima1
37th  181  agenticarus
38th  181  pace_t_zulu
39th  181  zkhr
40th  182  fluffle
...
60th  193  grizzley
65th  195  Jasper
89th  204  chargrill
98th  209  yanick

Ruby (338 entries):

```  1st  173  flagitious
2nd  176  eyepopslikeamosquito
3rd  177  eban
4th  177  bitsweat
5th  177  leonid
6th  180  tal
7th  180  emiltin
8th  181  yowa
9th  182  oxy4dm
10th  182  shinh
11th  182  noop
12th  182  J-_-L
13th  183  kik
14th  183  yvl
15th  184  tobyaw
16th  185  ksk
17th  186  jojo
18th  186  carldr
19th  186  pace_t_zulu

Python (423 entries):

```  1st  182  hallvabo
2nd  183  logan
3rd  183  uli
4th  189  Mark Byers
5th  190  hiro.suzuki
6th  192  primo
7th  193  eyepopslikeamosquito
8th  195  recursive
9th  195  tryeng
10th  195  etaronis
11th  196  kt3k
12th  197  gtalpo
13th  197  ProfessorO
14th  198  lifthrasiir
15th  198  Jay
16th  198  SergeantPepper
17th  199  hirose
18th  199  max
19th  200  Dilb
20th  200  yonilevy

PHP (264 entries):

```  1st 172  ToastyX
2nd 173  eyepopslikeamosquito
3rd 175  alab
4th 175  Morgil
5th 178  jln
6th 178  cms
7th 179  hamori
8th 180  hiro.suzuki
9th 183  eyepopper
10th 185  Leafy
11th 186  carldr
12th 191  shinh
13th 193  heavyware
15th 198  davidpogson
16th 198  lxlh
17th 199  echofish
18th 200  phoe
19th 201  underdonges
20th 203  Theory

References

Update: As described in detail in a three part series Compression in Golf: Part I, this 160-stroke Perl solution was later whittled to around 150 strokes, by using pack u compression.

Replies are listed 'Best First'.
Re: Drunk on golf: 99 Bottles of Beer
by Limbic~Region (Chancellor) on May 08, 2011 at 23:46 UTC
eyepopslikeamosquito,
t also pops up often in popular culture, especially film and TV. I remember the late Patrick Swayze, for example, singing it over and over again to Whoopi Goldberg in the movie Ghost in order to get her to go downtown (which she would never normally do).

It has been a while but I think you are wrong. I remember the song he sang as "I'm Henery The Eighth, I am I am". On a side note, I do believe there was a reference in a ghost show. According to 99 Bottles of Beer, it appeared on an episode of the Ghostbuster's cartoon.

I always enjoy your posts and this is no exception - I just seldom have anything to contribute :-)

Cheers - L~R

Yes, you are right re "Henery the Eighth, I am". I found a youtube clip which shows Patrick Swayze singing Henry the Eighth to Whoopi Goldberg, as you say. Ghost is one of my all-time favourite movies, and I've seen it many times, but don't own a copy. It's been a while, but I remember a later street scene, where Whoopi tries to renege on going downtown and Patrick responds by singing 99 bottles of beer. Whoopi then quickly changes her mind and goes downtown as agreed. I could be mistaken though, and can't find a supporting youtube clip.

Re: Drunk on golf: 99 Bottles of Beer
by eyepopslikeamosquito (Chancellor) on May 25, 2011 at 11:47 UTC

Despite being shocked that Jasper and I had totally different 101 stroke solutions to the Saving Time challenge, I had a feeling that Rhebus and I would have similar solutions to this one. There just seemed to be much less scope for magic formulae and general weirdness in the beer bottle game. I've contacted Rhebus and am pleased to report that he was as curious as I was and happy to compare our solutions in the hope of unearthing an even shorter one. Here is his 162 stroke winning entry:

```@a=(++\$a." bottle\$& of beer",on,the,wall),s/^/
Take one down and pass it around, @a.

@a, \$a[0]./,/s/until/
99/;print"99\$'
Go to the store and buy some more, @a."

If you compare his with mine:

```/s/until@c=(@b=(++\$n,bottle.\$&,of,beer),on,the,wall),s/^/Take one down
+ and pass it around, @c.

@c, @b.
/,/, 99.*

/;print\$'."Go to the store and buy some more\$&"
you'll see some similarities and some differences. The major difference is that Rhebus used a five stroke shorter terminating regex, namely /\n99/ instead of my /, 99.*\n\n/, that unfortunately cost five strokes elsewhere: two strokes for the extra 99 at the front of the printed string and three for the terminating , @a. (instead of \$&) at its end.

Can these two solutions be combined somehow to produce a shorter one? I can assure you that many variations are possible but I couldn't find any reductions. So if you can further shorten it, you can claim to be the inventor of the shortest solution to the most popular golf game of all. :)

In the middle of the night it occurred to me that a further stroke can be shaved by changing the terminating regex from /, 99.*\n\n/ to /, 99\D+/, producing the following 161 stroker:

```/s/until@c=(@b=(++\$n,bottle.\$&,of,beer),on,the,wall),s/^/Take one down
+ and pass it around, @c.

@c, @b.
/,/, 99\D+/;print\$'."Go to the store and buy some more\$&"
The same trick can be applied to Ruby also.

After applying the new terminating regex to Ruby via the following 175 stroker:

```n=0;~/s/ until/, 99\D+/=~\$_="Take one down and pass it around, #{c=n+=
+1," bottle#\$& of beer"," on the wall"}.

#{c}, %s%s.
#\$_"%c;puts\$'+"Go to the store and buy some more"+\$&
I could not restrain myself from trying to reduce it further. Two eyesores that I found extremely annoying were:
• The space between the ~/s/ and until.
• The n=0; initialization, which is not needed in Perl.
Can anything be done about them? To get rid of the wretched space, I tried reorganizing via:
```n=0;\$_="Take one down and pass it around, #{~/s/;c=n+=1," bottle#\$& of
+ beer"," on the wall"}.

#{c}, %s%s.
#\$_"%c until~/, 99\D+/;puts\$'+"Go to the store and buy some more"+\$&
Still a space before the until and still 175 strokes. Rats. Chanting Eugene's "can't possibly work, try it anyway" mantra, I changed ~/, 99\D+/ to /, 99\D+/ and it worked! Though it now emits a "warning: regex literal in condition" message to stderr, that does not matter to codegolf. Another stroke shaved. Not as I intended, but no matter. Only one more needed to catch flagitious.

What about the n=0; initialization? At this point, I remembered the Roman to Decimal challenge, where I was able to avoid an initialization by hijacking the \$. variable. Indeed, if you want a numeric variable initialized to a known value, that is the only built-in variable Ruby makes available. Given my program is four lines in length, \$. is initialized to the value four. So I scribbled this down during my lunchtime walk to Neutral Bay today:

```n=0;n+=1
4-\$.-=1
Hmmm, well that's clearly one stroke less. But will it work? Or will Ruby complain when the \$. "line number" becomes negative? Nope, not a whimper about a negative line number. So, much to my surprise, I've now tied flagitious for the Ruby lead on 173 strokes:
```\$_="Take one down and pass it around, #{~/s/;c=4-\$.-=1," bottle#\$& of
+beer"," on the wall"}.

#{c}, %s%s.
#\$_"%c until/, 99\D+/;puts\$'+"Go to the store and buy some more"+\$&

Update: an alternative 173 using Ruby symbols:

```\$_="Take one down and pass it around, #{c=4-\$.-=1," bottle#{c&&:s} of
+beer"," on the wall"}.

#{c}, %s%s.
#\$_"%c until/, 99\D+/;puts\$'+"Go to the store and buy some more"+\$&

Re: Drunk on golf: 99 Bottles of Beer
by eyepopslikeamosquito (Chancellor) on Jun 12, 2011 at 07:25 UTC

Python Update

It disturbed me that the 99 bottles of beer analysis in the root node was incomplete without a short Python solution. Unable to concoct one myself, I contacted hallvabo, who was delighted to share his winning solution and the circumstances behind it.

If I just reveal his solution now, however, you might just exclaim "What the f*#?! is that?" and move on. Armed with an understanding of Python string slices though, hallvabo's wacky-looking concoction becomes logical and comprehensible. So I'll start with an overview of Python slices so as to make his solution more accessible.

Introduction to Python Slices

"Regexes always win" -- Mtv's law of Perl golf

"String bitwise operators always win" -- ToastyX's law of PHP golf

"Slices always win" -- Hallvabo's law of Python golf

When playing golf, it's vital to know which language features tend to produce the shortest code. While the above "laws" are admittedly outrageous oversimplifications, they are catchy and easy to remember. Perl regexes frequently trump alternative approaches. As do Python slices.

The Python slicing operator s[i:j:stride] extracts subsequences, where [i,j) is a semi-open range of indices in sequence s. All slicing arguments are optional. Negative indices (relative to the end of the string) and negative strides (reverse direction) are supported. Some examples should clarify:

```x = "012345"
s = x[0:3]       # s contains "012"
s = x[:3]        # same thing (using default)
s = x[4:]        # s contains "45"
s = x[1:4]       # s contains "123"
s = x[-5:-2]     # same thing using negative indices
s = x[-2:99]     # s contains "45" - negative index from end of
# string allowed, as is index outside string (99)
s = x[::2]       # s contains "024"
s = x[1::2]      # s contains "135"
s = x[1:4:2]     # s contains "13"
s = x[1:5:2]     # s contains "13"
s = x[1:6:2]     # s contains "135"
s = x[-1::-2]    # s contains "531"
s = x[::-2]      # same thing (using default)
s = x[::-1]      # s contains "543210" (i.e. string reverse)
s = x[::0]       # "ValueError: slice step cannot be zero"
If you want to be competitive at Python golf, you must master all the intricacies and defaults of string slicing.

Ruby also supports complex and powerful string slicing, but not strides. Though Perl supports array and hash slices, when it comes to slicing and dicing strings, Perl's substr function is nowhere near as concise as Python and Ruby slices and, accordingly, is rarely sighted in a winning Perl golf entry. By the way, I'd love to see Perl support more concise string slicing.

The "Slice and Dice" Golfing Manoeuvre

From my early 195-stroke function-based Python solution:

```n=99
z=lambda:`n or 99`+" bottle"+"s of beer on the wall"[n==1:]
while n:y=z();n-=1;print"%s, %s.\n"*2%(y,y[:-12],n and"Take one down a
+nd pass it around"or"Go to the store and buy some more",z())
notice the expression:
```n and"Take one down and pass it around"or"Go to the store and buy some
+ more"
Shortening the two strings above to "Take" and "Go to" for clarity, let's consider the many and varied ways of doing this in Python (TMTOWTDI):
```"Take"if n else"Go to"
(n>0)*"Take"or"Go to"
["Go to","Take"][n>0]
("Go to","Take")[n>0]
n and"Take"or"Go to"
"GToa kteo"[n>0::2]          # "Slice and Dice" wins this golf!
As you can see, I missed the winning Python "Slice and Dice" tactical trick in this game.

Good Things Come in Threes

Three quarks for Muster Mark!
Sure he hasn't got much of a bark
And sure any he has it's all beside the mark.

-- James Joyce in Finnegans Wake (inspiration for naming the quark)

In addition to missing the "Slice and Dice" tactical trick, I overlooked a crucial strategic idea, namely to break up each verse into threes, like so:

```99 bottles of beer on the wall,<space>
99 bottles of beer.\nTake one down and pass it around,<space>
98 bottles of beer on the wall.\n\n
Yet again in golf, uniformity pays dividends. Notice that each and every print statement now begins in the same way, with "n bottles of beer". Not only do you avoid the dreaded function call, but you can now print the "n bottles of beer" refrain on the fly, without needing to store it in a variable. There is a price to pay however. Instead of looping 99 times, you must now loop three times longer, 297 times. In turns out in Python that this is a bargain, as demonstrated by hallvabo's winning entry.

Dissecting Hallvabo's 182 Stroke Python Solution

With the key tactical and strategic ideas explained, I hope you'll find hallvabo's winning Python entry easier to follow:

```i=298
while~-i:print i/3or 99,'bottle'+'s of beer on the wall.\n\n'[2<i<6:9+
+i%3*12]+'..\n\nGToa kteo  otnhee  dsotwonr ea nadn dp absusy  isto ma
+er omuonrde,,'[(i>3)+i%3*68::2],;i-=1

To generate the required numeric beer bottle sequence, notice that hallvabo employed a while loop, very common in Python golf, counting down from 298 to 2, as illustrated in the table below:

ii%3i/3Part of song
298199bottles of beer on the wall,
297099bottles of beer. Take one down and pass it around,
296298bottles of beer on the wall.
295198bottles of beer on the wall,
294098bottles of beer. Take one down and pass it around,
293297bottles of beer on the wall.
............
............
............
712bottles of beer on the wall,
602bottles of beer. Take one down and pass it around,
521bottle of beer on the wall.
411bottle of beer on the wall,
301bottle of beer. Go to the store and buy some more,
220 => 99bottles of beer on the wall.

As you can see, his 2<i<6 boolean expression is used as the starting offset in a "s of beer..." string slice thus ensuring "bottle" rather than "bottles" is displayed when i has the values 3, 4 and 5 (corresponding to one bottle). The 9+i%3*12 ending offset concisely trims the "s of beer on the wall.\n\n" string to the required length.

The odd-looking ~-i while loop expression is just the Inchworm-On-A-Stick "secret operator", first employed by Perl golfer Ton Hospel in 2002, and nowadays routine in code golf across all languages. It's effectively the same as i-1 but with different precedence. Here it's employed simply to avoid a space after the while keyword. By the way, the converse inchwormy -~i secret operator for i+1 is routinely played in Python and Ruby golf ... but not Perl because it does not work for positive numbers -- for example, -~1 produces 2 in Ruby and Python, but -4,294,967,294 in Perl.

The hardest part of hallvabo's masterwork to understand is probably the odd-looking string slice at the end:

```'..\n\nGToa kteo  otnhee  dsotwonr ea nadn dp absusy  isto maer omuonr
+de,,'[(i>3)+i%3*68::2]
This complex "slice and dice" serves a dual purpose:
• To switch from "Take one down and pass it around" to "Go to the store and buy some more" at the end of the song.
• To deal with the (fiddly) song punctuation. Note, by the way, that the (quirky) Python print statement thoughtfully does exactly what we wish for: a space is obligingly inserted after each comma, even the trailing one, yet is suppressed if what is printed already ends in a newline (as our i%3==2 case does).
Instructively, notice that hallvabo's earlier (longer) submissions used a number of different strings; he found that reducing the number of strings lowered his golf score. To illustrate, here is his earlier 187-stroke entry:
```i=298
while~-i:print i/3or 99,'bottle'+'s of beer on the wall'[2<i<6:9+i%3*1
+4]+('.\n'+'GToa kteo  otnhee  dsotwonr ea nadn dp absusy  isto maer o
+muonrde,,'[i>3::2],',','.\n\n')[i%3],;i-=1

I have to give due credit here to "Logan", a remarkable golfing "beginner". Logan turned up on the codegolf IRC channel one day and the very experienced hallvabo gave him quite a bit of help to get him started. Within a few days, and much to hallvabo's surprise and chagrin, the pupil overtook the master, even stealing the outright Python lead from "uli"! To repay hallvabo, Logan gave him a slight hint to "stop being line oriented". As I well remember from the early Perl golfing days, giving even the slightest of hints to an expert golfer is fatal and so it proved here. Hallvabo fought back and eventually overtook his pupil Logan to win the game by a single stroke.

Reducing Hallvabo's 182 Stroke Python Solution

Of course, I tried to reduce hallvabo's winning entry further. When I first sighted his solution, I pulled a face the instant I caught sight of the ugly parentheses in (i>3)+i%3*68. Surely something can be done to eliminate them! Much to my surprise, I trimmed a stroke at my first attempt:

```i=298
while~-i:print i/3or 99,'bottle'+'s of beer on the wall.\n\n'[2<i<6:9+
+i%3*12]+'.X\n.G\noT atkoe  tohnee  sdtoowrne  aanndd  pbausys  siotm
+ea rmoourned,,'[3%i+i%3*68::2],;i-=1
Notice that replacing (i>3) with 3%i saves two strokes, while costing only one, namely the wasted X above in the string being sliced and diced.

Alas, I couldn't shave any more, even after running some brute force search programs over hallvabo's string slice magic formulae. I uncovered some interesting new variations though. For example, 2<i<6 can equivalently be replaced by 5/i%2 or 5/i%i ... which is essential when translating to Ruby because, unlike Python, Ruby does not allow booleans in numeric expressions.

Update: It is just possible that changing hallvabo's 298..2 range to 297..1 or 299..3 or 296..0 or some such might produce a shorter solution. For example, here is a 184-stroker using 297..1:

```i=297
while i:print-~i/3or 99,'bottle'+'s of beer on the wall.\n\n'[1<i<5:i%
+3*14^21]+'..\n\nGToa kteo  otnhee  dsotwonr ea nadn dp absusy  isto m
+aer omuonrde,,'[i%3-2^-72|2%i::2],;i-=1
Having said that, hallvabo's 298..2 does seem to be the most "natural" and I'd be surprised if a different range produced a shorter solution. Writing and running a program to exhaustively search all possible string slice magic formulae for a variety of ranges should settle this issue.

A Perl Translation

I didn't see much hope of adapting this approach to Perl due to the length of Perl's dreaded substr function, 191 strokes being the best I could find:

```print~\$_/3|0||99," bottle",substr("s of beer on the wall.

X",6/\$_%2,-4**(\$_%3)),(", ",\$_<-4?".
Take one down and pass it around, ":".
Go to the store and buy some more, ")[\$_%3-3]for-299..-3
Because substr takes a length parameter, rather than a Python slice index, I was forced to concoct a different (negative) magic formula (-4**(\$_%3)) to count from the end of the string, which explains the wasted X above. Nasty.

Replacing substr with an array slice didn't help:

```print-\$_/3|0||99," bottle",("s"," of beer"," on the wall",".

")[5/\$_%2..-\$_%3+1],(\$_<-3?".
Take one down and pass it around, ":".
Go to the store and buy some more, ",", ")[-\$_%3]for-298..-2

A Ruby Translation

I also wrote a couple of quick Ruby translations, a 183-stroke:

```298.downto(2){|i|\$><<i/3%-99+99<<" bottle"+"s of beer on the wall.

"[5/i%i..8+i%3*12]<<[i>3?".
Take one down and pass it around, ":".
Go to the store and buy some more, ",", "][i%3]}
and a 184-stroke:
```298.downto(2){|i|\$><<i/3%-99+99<<" bottle"+"s of beer on the wall.

"[5/i%i..8+i%3*12]<<".
Go to the store and buy some more, .
Take one down and pass it around, "[3%i*25/2+i%3*34,37]}
Though these two can surely be further reduced, 173 strokes looks out of reach.

Ruby Update

Much later, I was surprised to learn that emiltin and J-_-L had both independently concocted an eval approach that never occurred to me. Emiltin's original 180-stroke solution was:

```eval"\$><<%{#{a=b='#{n} bottl#{"es"[0,n]} of beer',' on the wall'}, #{b
+}.
\#{0<(n-=1)?'Take one down and pass it around':(n=99;'Go to the store

};"*n=99
while J-_-L's original 182-stroker was:
```eval %{puts"#{a='#{n} bottle#{n>1?:s:p} of beer on the wall'}, #{a[0,3
+0]}.
\#{(n-=1)<1?(n=99;'Go to the store and buy some more'):'Take one down
+and pass it around'}, #{a}.

"
}*n=99

So Ruby wins the TMTOWTDI prize in this game given that three completely different approaches all yield sub-180 solutions.

Regex (173)

```\$_="Take one down and pass it around, #{~/s/;c=4-\$.-=1," bottle#\$& of
+beer"," on the wall"}.

#{c}, %s%s.
#\$_"%c until/, 99\D+/;puts\$'+"Go to the store and buy some more"+\$&

Map (177)

```"Go to the store and buy some more"+(-99..-1).map{|n|", #{b=-n," bottl
+es"[0,6-n]+" of beer"," on the wall"}.

#{b}, %s%s.
"%b}*"Take one down and pass it around"=~/

/;puts\$'+\$`

Eval (178)

```# Based on emiltin.
eval"\$><<%{#{a=b='#{n} bottl#{"es"[0,n]} of beer',' on the wall'}, #{b
+}.
\#{0<(n-=1)?'Take one down and pass it around':'Go to the store and bu
+y some more'%n=99}, #{a}.

};"*n=99

```# Based on J-_-L.
eval"\$><<%{#{a=b='#{n} bottle#{n>1?:s:p} of beer',' on the wall'}, #{b
+}.
\#{(n-=1)<1?'Go to the store and buy some more'%n=99:'Take one down an
+d pass it around'}, #{a}.

}
"*n=99

Shortest Perl, Ruby and Python Solutions

To sum up, as at June 2011, the shortest known solutions to this game are:

Perl (161 strokes):

```/s/until@c=(@b=(++\$n,bottle.\$&,of,beer),on,the,wall),s/^/Take one down
+ and pass it around, @c.

@c, @b.
/,/, 99\D+/;print\$'."Go to the store and buy some more\$&"

Ruby (173 strokes):

```\$_="Take one down and pass it around, #{~/s/;c=4-\$.-=1," bottle#\$& of
+beer"," on the wall"}.

#{c}, %s%s.
#\$_"%c until/, 99\D+/;puts\$'+"Go to the store and buy some more"+\$&

Python (181 strokes):

```i=298
while~-i:print i/3or 99,'bottle'+'s of beer on the wall.\n\n'[5/i%i:i%
+3*28^9]+'.X\n.G\noT atkoe  tohnee  sdtoowrne  aanndd  pbausys  siotm
+ea rmoourned,,'[i%3*69^3%i::2],;i-=1

Given that over a thousand golfers have hacked on this game for more than five years now, further reductions won't come easy, though they're certainly possible. So if you can further reduce any of these solutions ... well ... kudos. And please post them here. :)

Acknowledgement: I'd like to thank hallvabo for his help in preparing this node. Update: I'd like to thank emiltin and J-_-L for their help in preparing the Ruby update.

Re: Drunk on golf: 99 Bottles of Beer
by eyepopslikeamosquito (Chancellor) on Feb 16, 2012 at 12:09 UTC

Perl Update

I contacted experienced Polish golfer 0xF mentioning my article and asking if he'd like to share his original 165-stroke solution -- which led this competition for over a year in its early stages.

Instead of sharing, however, he wanted to keep on competing! Divulging nothing, he snatched the lead once again by posting a 160-stroker.

What on earth was 0xF up to? Had he shortened his original 165-stroker? Or my 161-stroker? Or found a completely new approach? I had no way of knowing yet could hardly ignore this provocation.

Exploring All Possible Variations

I'd been quite lazy with my 161-stroker in that I had neglected to explore all possible variations. Laziness may be one of the three virtues of the Perl programmer but definitely not of the Perl golfer. No, you have to work hard, exploring every possible variation, just in case one of them allows a surprising tactical trick.

So I started by reorganizing my 161-stroke solution like so:

```@c=(@b=(++\$n,bottle.\$&,of,beer),on,the,wall),s/^/Take one down and pas
+s it around, @c.

@c, @b.
/,/s/until/, 99\D+/;print\$'."Go to the store and buy some more\$&"
This is nothing more than a simple rearrangement. However, on seeing it written that way I immediately noticed that the /, 99\D+/ regex was false all the time within the loop, becoming true only after loop termination ... which means that the default regex (i.e. //) is not affected within the loop because that very short // notation represents the last successful match.

Hmmm. That means if I can eliminate the annoying /s/, I can shorten s/^// by one stroke to s///. Yet if I eliminate the /s/ I must also delete the ridiculously short \$&. That is like losing an old friend. And what are the chances of finding a short enough replacement? Looks impossible, but I have to try at least.

Without the /s/, all we have left to distinguish the first time through the loop from subsequent iterations is the s/// expression. What changes after this expression is executed for the first time? Well, as far as I can tell only \$_ and the regex "side-effect" variables \$&, \$', \$`, @+, @-. So we need to find a short expression using one of those six. Since \$_, \$&, \$' and \$` all look hopeless, that only leaves @+ and @-.

ySas' Device

I remember some very happy golfing moments with good ol' @-: I used it in my winning Roman to Decimal solution and fondly remember a marvellous stunt pulled by ySas where he used @- as a multiplier in s/(M)|D/4x@-x5/eg thus distinguishing a matching M from a matching D.

Can I mimic ySas here? Yes! You see, there are zero elements in @- before the first s/// and one element thereafter (corresponding to the offset of the start of the (always) successful match, there being no sub-patterns). So @-, somewhat flukily, has exactly the right values for a multiplier -- 's'x@- -- which shortens my solution by a single stroke:

```@c=(@b=(++\$n,bottle.'s'x@-,of,beer),on,the,wall),s//Take one down and
+pass it around, @c.

@c, @b.
/until/, 99\D+/;print\$'."Go to the store and buy some more\$&"
160 strokes!

What next? Well, I can't see anything more. However, if 0xF found a different improvement, and reads this node, we may finally see the magical 160-stroke barrier broken.

Update: The 160-stroke barrier was shattered down to 149 by utilising "pack u" compression, as detailed in this series of nodes.

Re: Drunk on golf: 99 Bottles of Beer
by primo (Beadle) on May 23, 2016 at 07:15 UTC

phpGolf seems to have reached the end of its life cycle. My 172 byte solution was the following:

```<?for(;100>\$a=1+\$a." bottle\$o[21] of beer";\$o="
Take one down and pass it around, \$b.

".\$g="\$b, \$a.\$o")\$b="\$a on the wall";echo"\$g
Go to the store and buy some more, \$b.";

Thanks for sharing your solution, and for reminding me of the good old days on the PHP golf course. After digging out my old notes, I can finally share my PHP solutions too.

I had many different 173 strokers, such as (without bothering to use the routine PHP bitwise ~ golfing trick to reduce the " on the wall" strings below by one char):

```<?for(;\$c=(\$b=++\$n." bottle\$s of beer")." on the wall",99^\$x="\$c, \$b.
\$z\$x";\$s=s)\$z="Take one down and pass it around, \$c.

";echo\$x."Go to the store and buy some more, \$c.";

<?for(;\$c=(\$b=++\$n." bottle\$z[20] of beer")." on the wall",99^\$x="\$c,
+\$b.
\$z\$x";)\$z="Take one down and pass it around, \$c.

";echo\$x."Go to the store and buy some more, \$c.";

<?for(;99^\$x=(\$c=(\$b=++\$n." bottle\$x[21] of beer")." on the wall").",
+\$b.
\$x";\$x="Take one down and pass it around, \$c.

\$x")?><?=\$x,"Go to the store and buy some more, \$c.";
I had a mental block and just could not get to 172!

After I had given up, ToastyX mercifully gave me a hint, and then I finally did get to 172 -- but did not submit either of these two below because I would never have thought of them without ToastyX's hint:

```<?for(;99^\$c=(\$b=++\$n." bottle\$x[21] of beer")." on the wall";\$x="
Take one down and pass it around, \$c.

\$c, \$b.\$x")?><?="\$c, \$b.\$x
Go to the store and buy some more, \$c.";

<?for(;99^\$c=(\$b=++\$n." bottle\$s of beer")." on the wall";\$s=s)\$x="
Take one down and pass it around, \$c.

\$c, \$b.\$x";echo"\$c, \$b.\$x
Go to the store and buy some more, \$c.";

Re: Drunk on golf: 99 Bottles of Beer
by Anonymous Monk on Jun 01, 2012 at 21:03 UTC
Ruby (168) Utilizing pack compression:
```eval ['u\x0f\x04\xfd\xd0\xbez\x88\xbb\xb2\xb8\xbb\x86\xcd+\xed\xea\xe1
+\xee\xd7\xb0\xc3\xb9\xb1\xed\xeb\xec\xca\xb8L\xec>5v"\xddD\xc0\xbb~\x
+ccq\xa6 \xf8\xd4a\x9a\xc3\xae\xec\x8f\xb7\xe2\x8a\xf0\x8c\x0b\xbb+\xe
+f\x19b\xefG\xa9\xa4.\x8e\x0f\x8dz3\xb1p\x17\x03\xbc\x0cO\xc2\x17^\xf2
+\xaf\x19\xa9=\x96N+\xcf\x0f\xf2\xdc\xb1\xc0A\xcb\x0b\xdb;\xc6\xce\xf1
+\x96.\xf0\xc6\xcb\xe2\xed\xea\xe1\xed\xfc\xb6\xef\x0b*\x8b\xba\xac\xb
+e#;\x08\xb1\x06'].pack('u69').tr'>-^','a-}
GT'

Create A New User
Node Status?
node history
Node Type: perlmeditation [id://903641]
Approved by ww
Front-paged by Corion
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (2)
As of 2018-03-19 03:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
When I think of a mole I think of:

Results (232 votes). Check out past polls.

Notices?