http://www.perlmonks.org?node_id=906633


in reply to Drunk on golf: 99 Bottles of Beer

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. :)

Replies are listed 'Best First'.
Re^2: Drunk on golf: 99 Bottles of Beer
by eyepopslikeamosquito (Archbishop) on May 29, 2011 at 21:16 UTC

    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"+$&

      Update: Note that dmd compressed my 173 stroke solution above to 168 by using Ruby compression ... and -- as indicated at Re^3: Compression in Golf: Part III -- it seems highly likely that Ruby golf maestro flagitious used Ruby compression in his 173 stroke solution! ... which, after years of painstaking effort, makes my uncompressed 173-stroker above my best ever Ruby golf performance.