http://www.perlmonks.org?node_id=43619
Category: Fun Stuff
Author/Contact Info
Description: Some time ago, there was a thread on clpmisc on writing 99 Bottles of Beer on the Wall in Perl. After exploring elegant solutions, posters turned to shorter solutions. At the time, the shortest solution took up three lines. With some spare time and nothing better to do, I recently succeeded in squeezing this program to two lines of Perl (fewer than 80 characters per line). Enjoy!
$n=pop||99;sub b{"$n bottle@{[$n!=1&&s=>]} of beer"}print$b=b,$w=' on 
+the wall'
,", $b!\nTake one down, pass it around,\n",b($n--),"$w!\n\n"while$n
Replies are listed 'Best First'.
Re: 99 bottles, 2 lines
by jepri (Parson) on Nov 28, 2000 at 13:40 UTC
    You are a most remarkable programmer, chipmunk. I just spent four and a half hours working on this one instead of my essay and still didn't get anywhere. Here's my best:

    foreach(1..99){$b="\n$_ bottle@{[$_!=1&&s=>]} of beer";push@a,",\nTake + one down, pass it round,$d@{$d=$b.' on the wall'}\n",$d.$b};print re +verse@a;

    but the output isn't as nice as yours.

    I had this great idea using quines and self-modifying code, but I was beaten by s///. The idea was to find every number in the program and decrement it by one with s/\d{2}/$1--/g but $1 is read only so I couldn't (my lesson for today). Oh well. The following code actually works.
    Update: I don't know if it's just my browser but the second line isn't displaying correctly. It should be $b=99;$c=$b-1;. But it doesn't break to badly if $c gets mangled.

    seek DATA, 38,0; + $_=join("",<DATA>); + $b=99;$c=$b-1; + $b/$b; + print "\n\n $b on the wall, $b. Take one down, pass it around, $c on +the wall." ; + s/$b/$b-1/e; + s/ (\$.)/$1 bottles of beer/g; + eval;__DATA__

    ____________________
    Jeremy
    I didn't believe in evil until I dated it.

      s/\d{2}/$1--/g

      Can't you just use:

      s/\d{2}/$1-1/ge
      except that this will fail when you get down to 1 digit.

              - tye (but my friends call me "Tye")
      Hey, i'm new to posting on here, and am trying to work on loadsa things to get myself better at programming in perl... and this one i thought looked cool... so i gave it a try, and nicked a bit of code from chipmunk's code and made my own... it's only 1 line... but one hell of a line... only 1 semicolon in sight! :-) i thought the horrible lot of numbers i put in the qw() could be done a better way, but i was trying to get it done in just the one line, so i gave up trying to think of a way to do it. but this is what i have.
      map { print "$_ bottle@{[$_!=1&&s=>]} of beer on the wall, $_ bottle@{ +[$_!=1&&s=>]} of beer. Take 1 down, pass it around, ".($_-1)." bottl +e@{[$_-1!=1&&s=>]} of beer on the wall.\n" } reverse 1..99;
      Update: the long line has been decreased thanks to blakem! now it's one line that actually looks pretty sweet! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      i would slit my wrists for you
        How about:
        my @a = reverse 1..99;
        you can probably just inline reverse 1..99 since I don't see you actually using @a anywhere....

        -Blake

Re: 99 bottles, 2 lines
by mt2k (Hermit) on Oct 29, 2002 at 05:04 UTC
    Okay, I just cam across this and had to give it a shot. Mine turns out to be several characters longer than the original, but oh well :)

    sub _{"$n bottle@{[$n!=1&&s=>]} of beer".(@_?' on the wall':'!')}$n=po +p||99;print _(1).', '._."\nTake one down, pass it around,\n"._(--$n),"!\n\n"and sl +eep 1while$n;
99 bottles, 2 lines -Didnt login- hehe
by Extreme66 (Initiate) on Nov 10, 2002 at 04:25 UTC
    $a='on the wall';$b=99;$c="bottles of beer";do{print"$b $c $a, $b $c\nTake one down, pass it around\n$b $c $a!\n\n"}while(($b--)>0)
      got it even smaller (126 bytes)

      @a=(" bottles of beer",'on the wall ');die map{"$_@a$_$a[0]\nTake one down, pass it around\n".(--$_||No)."@a\n"}reverse(1..99)
        oh no... forgot to login too *g*
Re: 99 bottles, 2 lines
by lanval (Novice) on Apr 27, 2004 at 01:57 UTC
    The problem occurs when you must decide whether to write "bottle" or "bottles". Some replies above do not take this into account despite the original poster doing so. Just for fun, here is my solution (longer than the original though). It is 178 characters long:
    ($a,$b,$c,$n)=(" bottle"," of beer"," on the wall",99);sub u{$s=$n-1?" +s":();$e="$n$a$s$b"}while($n){u;print"$e$c, $e!\nTake one down, pass +it around,\n";$n--;u;print"$e$c!\n\n"}
Re: 99 bottles, 2 lines
by Adrade (Pilgrim) on Jun 03, 2005 at 14:53 UTC
    I came across this way late, and also felt that urge in the pit of my bowels (or it could be gas) to share my result. Homage to the original poster, as although this is two lines of 79 77 chars each, it really doesn't even come close to the superiority of the orig.

    # Bad code - left here just because $c=99;sub q{$w="bottle".(--$c?'s':'')." of beer";++$c;$q=$w.' on the w +all.'}do{ &q;print"$c $q $c $w.\nTake one down, pass it around,\n".--$c." $q\n\n +"}while$c # ######## # Good code, as in - it works $c=99;sub q{$c.' bottle'.($c!=1?'s':'').' of beer'}sub e{&q.' on the w +all'}do {print&e,'. ',&q,".\nTake one down, pass it around,\n",e(--$c),"\n\n"} +while$c

    Best,
      -Adam

    P.S. I wonder if anyone's ever gonna read this...
    P.P.S. I just realized the "0 bottle" error - oh, the dispair!
    P.P.P.S. Revised - shorter, and works correctly.

    --
    Impossible! The Remonster can only be killed by stabbing him in the heart with the ancient bone saber of Zumakalis!

Re: 99 bottles, 2 lines
by tmiklas (Hermit) on Mar 27, 2006 at 13:02 UTC
99 bottles, 1 Line 132 Characters.
by Anonymous Monk on Nov 10, 2002 at 04:23 UTC
    $a='on the wall';$b=99;$c="bottles of beer";do{print"$b $c $a, $b $c\nTake one down, pass it around\n$b $c $a!\n\n"}while(($b--)>0)