Sign in to follow this  
RLS0812

99 Bottles Of Beer Challenge With Least Amount Of Characters ?

Recommended Posts

I think you're better off skipping the base64 part and escaping the few bytes you can't put as-is (PHP strings are purely byte-based after all, so no codepage shenanigans).

 

EDIT: also may want to take a look at gzinflate, that may or may not help (at least the function name is shorter!).

Edited by Sik_the_hedgehog

Share this post


Link to post
Share on other sites
swiftcoder    18426

274 characters PHP (no "cheating" in a sense of printing the contents of an URL or such)  smile.png

<?eval(gzuncompress(base64_decode('eJx9zsEKgkAQBuD7PMWPLFiwSh3N1GO3Tr3AmiNFuhO7KxHRu6fS0brMYfjmn78Vt1K2yLJc2XIzjiRZ04uUL6Z1sV1XcbyLfZwTny+CSFnUEkLHykNa1MwOYhEujIfpOo0FkNLJ3HhkDGMb3I33uAYYJ4NtNCI9ft3q6G9wShTl9K5KOgp6cfzVP1rYZZSCDoIgs/RhElOjenjCS8/zjUaW/QtP99UH7qth3w==')));?>

I just tried to apply this to dmatter's 207-character Python solution, and the damn thing grew 150 characters sad.png
import zlib, uu
exec(zlib.decompress('eJwljrFuwzAMRHd/xS0GZcgp5GwxoAxZunXqlmqQYRYRKkuJpcDo35dxOT2CxL27wCL6ZZo9kqVE\nI6hHWzDlWiML5G9MzCtyQr0xNh8joYVSoR2M6ZOmjCWvTN01WGtcDyr0wmF0XcMST29fiZogdDo1\n2y1ERsDZwowNZB5yuCj6kIDj6KBl6a7jYTg6zbIpes+oeZeXKiL4NGN6/qLkhf/V4vz0PywdGXPe\n0v5y96UgVPg1P9P8qoczjNudAQeLYcf7GlJVDy1Wzd0fdlNKWA==\n'.decode('base64')))
Edited by swiftcoder

Share this post


Link to post
Share on other sites

So far, I got the PHP version down to 259 characters, with gzinflate being the best available compressor of the 4 different ones I tried (the others are 4 or 8 bytes larger, respectively, because of checksums and headers added). Will try if I can replace base64 with something more compact.

 

207 characters are a challenge, though...

Share this post


Link to post
Share on other sites

186 characters! biggrin.png

 

Run php pack.php to generate beer.php from beer-src.php.

 

beer-src.php

for($n=99;$n>0;$n--){$s=$n==1?:'s';echo"$n bottle$s of beer on the wall, $n bottle$s of beer.
Take one and pass it around, ",$n-1," bottle$s of beer on the wall.

";}?>
No more bottles of beer on the wall, no more bottles of beer. 
Go to the store and buy some more, 99 bottles of beer on the wall.<?

pack.php

<?
function encode($in)
{
	$out = '';
	foreach(str_split($in) as $c)
	{
			switch($c)
			{
				case '\0'  : $c = '\0'; break;
				case '"'  : $c = '\"'; break;
				case '\''  : $c = '\''; break;
				case '\n'  : $c = '\n'; break;
				case '\$'  : $c = '\$'; break;
				case '\t'  : $c = '\t'; break;
				case '\\'  : $c = '\\'; break;
			}
		$out .= $c;
	}

	return $out;
}

$src    = file_get_contents("beer-src.php");
$src_gz = encode(gzdeflate($src));

$output=<<<xxx
<?eval(gzinflate("$src_gz"));?>
xxx;

echo strlen($output)." characters\n\n";
echo $output;

$f = fopen("beer.php", "w");
fwrite($f, $output);
fclose($f);

beer.php (186 bytes)

<?eval(gzinflate("}α‚0à½Oñ‡4A“ÒȈŒnN¾@‘#¡gÚcŒï.Gd¹áòÝËn#m‘e¹´ånI²}K_Œ»\"­ö±sº\9’5‡Ð‘ôà5‘[„+áiºNahq6wÁØã=nÆñ`…HßR­k!¢üS•âÄèÙÑÿ)a—‘†82ÏÒ‡IL…êáÏ=Í7
Y¶®Õ"));?>

Share this post


Link to post
Share on other sites

Why are you passing Perl to gzinflate? *runs*

 

Serious though, this is why I suggested trying to encode the strings directly instead of using base64, because base64 is a massive overhead: three bytes get encoded as four characters, and code like this doesn't compress that well, so that most likely ends up countering the compression. Besides, if we're aiming for the smallest code then anything that can shrink the size should be attempted, right? =P

Share this post


Link to post
Share on other sites

Yup, that was a great suggestion, thank you.

 

Modifying the raw source as follows, I managed to bring it down to 181 characters:

for($r=99;$r;--$r){$s=$r==1?:"s";echo "$r bottle$s of beer on the wall, $r bottle$s of beer.
Take one and pass it around, ",$r-1," bottle$s of beer on the wall.

";}echo "
No more bottles of beer on the wall, no more bottles of beer. 
Go to the store and buy some more, 99 bottles of beer on the wall.";

Basically, this tries to give the dictionary compressor a few more opportunities to match. That's harder to get right (and less intuitive, longer text sometimes compresses to smaller output!) than it sounds. Not only is the compression result a bit hard to predict from the editor, but also better compression may be larger in the end due to escaping.

Share this post


Link to post
Share on other sites

Well, you don't need to escape all those characters (you can probably store tabs as-is, and \" shouldn't need to be escaped since you're using the other kind of quote). Also remember gzdeflate can take a level parameter which determines how much it will try to compress (you may want to push it to the maximum, which is 9).

Share this post


Link to post
Share on other sites

The level parameter won't change anything, the to-be-compressed string is far too short for that to have any effect (not that I didn't initially try a brute-force packer that chose the smallest of every possible level anyway, but that turned out a complete waste of time rolleyes.gif ).

 

As for not escaping all those characters, this was my first thought, too. Actually I thought that escaping \0 as well as single and double quotation marks should be enough. Then it occurred to me that backslash probably needed to be escaped, too. Turned out that still isn't enough, gzinflate will choke on tab and $ as well.

Further, there is indeed at least one character that I'm not escaping although I should to be "formally correct" (I didn't bother to find out which, as the result was longer than the best match anyway -- probably it's the backspace character or some other weird control code?).

 

I discovered this when trying to rename the loop variable to something that gives more matches than "$n". My first idea was "$e", seeing how e is the most frequent character in English. That was too naive and didn't work out (first, in this particular text, "o" is the most common character, and second it doesn't suffice to be frequent, you also need surrounding characters to match -- which made "r" being the most frequent end-of-word character the best candidate), But what's worst, it broke the decompressor.

 

Now "r" saved 2 bytes, which is nice, so I stuck with that. And incidentially, it works fine with the small subset of escaped characters, too.

Share this post


Link to post
Share on other sites
RobTheBloke    2553

The brackets are need around the ternary operator since it's in a macro.

#include <iostream>
#define a(i) << " bottle" << (i-1?"s":"") << " of beer" << 
#define w " on the wall" <<

int main()
{   
    for(int i=100;i-->1;)
      std::cout << i a(i) w ", " << i a(i) ".\nTake one down and pass it around, " << i-1 a(i-1) w ".\n\n";
    std::cout << "No more" a() w ", no more" a() ".\nGo to the store and buy some more, 99" a() w ".";
}

After some tweaking 273 now

 

Sadly, it fails for 1 bottle of beer.

Share this post


Link to post
Share on other sites
Paragon123    620

C# 230 characters

 
class B
{
static void Main()
{
for(int i=100;i-->1;)
System.Console.WriteLine("{0} {6}{1} {2} {5}, {0} {6}{1} {2}.\nTake 1 down, pass it around {3} {6}{4} {2} {5}.",i,i>1?"s":"","of beer",i==1?"no more":(i-1).ToString(),i==2?"":"s","on the wall","bottle");
}
}

 

 

Share this post


Link to post
Share on other sites
Cornstalks    7030

 

C# 230 characters

 
class B
{
static void Main()
{
for(int i=100;i-->1;)
System.Console.WriteLine("{0} {6}{1} {2} {5}, {0} {6}{1} {2}.\nTake 1 down, pass it around {3} {6}{4} {2} {5}.",i,i>1?"s":"","of beer",i==1?"no more":(i-1).ToString(),i==2?"":"s","on the wall","bottle");
}
}

You missed the last verse, where you have to go to the store and buy some more.

Share this post


Link to post
Share on other sites
slicer4ever    6760
I just discovered this: http://esolangs.org/wiki/Var%27aq

klingon programming language with 99 bears implemented:

~ bottles { 
  latlh 1 rap'a' "" tam 
    { woD "s" } ghobe'chugh 
  " bottle" tam tlheghrar tam woD 
  " of beer" tlheghrar 
} pong

~ print-verse { 
  latlh latlh bottles tlheghrar " on the wall" tlheghrar cha'
  latlh latlh bottles tlheghrar cha'
  "Take one down and pass it around" cha'
  wa'boqHa' latlh latlh  { "No" } ghobe'chugh latlh bottles tlheghrar " on the wall" tlheghrar cha' 
  "" cha' 
  latlh { print-verse } HIja'chugh
} pong

99 print-verse

Share this post


Link to post
Share on other sites
rip-off    10976


klingon programming language with 99 [b]bears[/b] implemented:

Fixed for you:

~ bottles { 
  latlh 1 rap'a' "" tam 
    { woD "s" } ghobe'chugh 
  " bottle" tam tlheghrar tam woD 
  " of bear" tlheghrar 
} pong
 
~ print-verse { 
  latlh latlh bottles tlheghrar " on the wall" tlheghrar cha'
  latlh latlh bottles tlheghrar cha'
  "Take one down and pass it around" cha'
  wa'boqHa' latlh latlh  { "No" } ghobe'chugh latlh bottles tlheghrar " on the wall" tlheghrar cha' 
  "" cha' 
  latlh { print-verse } HIja'chugh
} pong
 
99 print-verse

Share this post


Link to post
Share on other sites
boogyman19946    1487

Nobody said we had to use a real language. Therefore, zero characters, using the newly created "bottles of beer" language..


The specification of the "bottles of beer" language states that:

 

An empty source file shall produce a program which prints out the lyrics of the "99 bottles of beer" song. The behaviour of non-empty source files is unspecified.

 

 

Thank you.

 

Someone has already kinda-sorta beat you to the punch biggrin.png

 

I'm not sure if anyone has mentioned this in the thread, but... introducing HQ9+

9

99 Bottles of Beer in 1 character.

 

EDIT: Ehh, what the heck, I thought I'd join the fun. My weapon of choice is C:

#define z(s,t) h(s,t," bottle%s of beer"," on the wall",i:,"o more",i==1?"":"s")
#define h(a,q,b,c,d,e,f) printf(a b c", "a b".\n%s, "q b c".\n\n",i?d"N"e,f,i!=0?d"n"e,f,i?"Take one down and pass it around":"Go to the store and buy some more",i==0?99:i!=1?i-1:"n"e,i==2?"":"s")
main(){int i=99;for(;i>=0;i--)i==0?z("%s","%i"):i==1?z("%i","%s"):z("%i","%i");}

Also, I got it on codepad to show that it in fact executes correctly: http://codepad.org/CIeL7PZm

 

It is 358 characters I think. I compiled it using GCC with both -std=99 and -std=89 and the results are the same. It compiles with many warnings but it runs nonetheless. 

 

Fun fact, I ran GCC -E when I was testing the macros for correctness, and they expand to over 1000 characters of code XD

Edited by boogyman19946

Share this post


Link to post
Share on other sites
Ravyne    14300
#include <stdio.h>

int main (void)
{
#define P(A)printf(A,i,i,i)
#define B(A,P)#A" bottle"#P" of beer on the wall"
#define V(P)B(%d,P)", %d bottle"#P" of beer.\nTake one down and pass it around, "

    int i=99;
    P(V(s));

#define R B(%d,s)".\n\n"V(s)

    while(--i>1)
        P(R);

#define R B(1,\?\b)".\n\n"V(\?\b)

    P(R B(no more,s)".\n\n"B(No more,s)", no more bottles of beer.\nGo to the store and buy some more, "B(99,s)".\n");
}

378 characters including significant whitespace, 396 with the #include . Output is perfect including caps, punctuation, newlines and final verses. I could probably hoist out a few #defines, or #define the #defines and save another 20-30 chars, but I'm weary of this exercise for the moment smile.png Gotta love code that only reads top to bottom!

Edited by Ravyne

Share this post


Link to post
Share on other sites
boogyman19946    1487
#include <stdio.h>

int main (void)
{
#define P(A)printf(A,i,i,i)
#define B(A,P)#A" bottle"#P" of beer on the wall"
#define V(P)B(%d,P)", %d bottle"#P" of beer.\nTake one down and pass it around, "

    int i=99;
    P(V(s));

#define R B(%d,s)".\n\n"V(s)

    while(--i>1)
        P(R);

#define R B(1,\?\b)".\n\n"V(\?\b)

    P(R B(no more,s)".\n\n"B(No more,s)", no more bottles of beer.\nGo to the store and buy some more, "B(99,s)".\n");
}

378 characters including significant whitespace, 396 with the #include . Output is perfect including caps, punctuation, newlines and final verses. I could probably hoist out a few #defines, or #define the #defines and save another 20-30 chars, but I'm weary of this exercise for the moment smile.png Gotta love code that only reads top to bottom!

 

Codepad seems to be messing up your output. At the 1 bottle of beer line, it prints bottle? instead of bottle, although my console seems to get it right.

Edited by boogyman19946

Share this post


Link to post
Share on other sites
Ravyne    14300


Codepad seems to be messing up your output. At the 1 bottle of beer line, it prints bottle? instead of bottle, although my console seems to get it right.

 

It must not support the escape sequence for backspace then. I have to feed one of my macros, and I do so with a \?\b (question mark, backspace) sequence to keep it happy. I suppose I could have just used an \a (alert/bell) sequence and saved 4 characters, but I felt like that was cheating.

 

Cleaning up, hoisting " on the wall", and using \a, now I've got:

#include <stdio.h>

int main()
{
#define P(M)printf(M,i,i,i) //27:27
#define W " on the wall" //24:51
#define B(A,S)#A" bottle"#S" of beer" //37:88
#define V(S)B(%d,S)W", "B(%d,S)".\nTake one down and pass it around, " //70:158

	int i = 99; //11:169
	P(V(s)); //8:177

#define R(S)B(%d,S)W".\n\n"V(S) //31:208

	while (--i>1) //13:221
		P(R(s)); //8: 229

	P(R(\a)B(no more, s)W".\n\n"B(No more, s)W", "B(no more, s)".\nGo to the store and buy some more, "B(99, s)W"."); //109:338
} //+18 (#include) +12 (main) = 370 characters

Which is 338 characters for the body, and 370 in total (#include, main, body), including significant whitespace. And its actually fairly reasonable to follow.

Share this post


Link to post
Share on other sites
Sutayh    173

Just throwing my hat in the ring, though it's not the shortest:

#include<iostream>
#include<sstream>
using namespace std;
string m="o more",v=" bottle",t=" of beer",s=" on the wall";
string a(int n,int c=0)
{
stringstream b;
b << n;
return (n?b.str():(c?"N":"n")+m)+(n==1?v:v+"s");
}
int main()
{
for(int l=99;l>-1;--l)
{
cout << a(l,1)+t+s+", "+a(l)+t+".\n"+(l?"Take one down and pass it around, ":"Go to the store and buy some more, ")+(a(l?l-1:99))+t+s+".\n\n";
}
} 

370 characters, 332 without "any" whitespace.

Edited by Sutayh

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this