99 Bottles Of Beer Challenge With Least Amount Of Characters ?

Started by
95 comments, last by rip-off 9 years, 2 months ago

In C89, it is legal. In C99 (and later), it is illegal.

In C99 it's still legal, it has tripped me many times before (well, not so bad as the compiler screams warnings like crazy so I catch it before I even get to try the code, but it's still easy to forget to declare a function).

Nope, it's not legal in C99. I actually was curious about this when I was doing my attempt so I asked about it on StackOverflow and I got a couple great responses that pointed out the following:

Rationale for International Standard — Programming Languages — C, section 6.5.2.2 (page 62, starting on line 23):
"A new feature of C99: The rule for implicit declaration of functions has been removed in C99. The effect is to guarantee the production of a diagnostic that will catch an additional category of programming errors. After issuing the diagnostic, an implementation may choose to assume an implicit declaration and continue translation in order to support existing programs that exploited this feature."


The section that allowed implicit function declaration in C89 was section 3.3.2.2 (paragraph 4). This section was moved to the 6.5.2.2 section in C99, and removed the paragraph that defined implicit function declaration (paragraph 4 in C89).
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
Advertisement

How about we go for the shortest version that will compile with GCC?

Did it in 1 character (including whitespace):

A
Compile with: gcc -DA='int printf(const char*, ...);int main(){int i;for (i = 99; i > 0; --i){printf("%d bottle%s of beer on the wall, %d bottle%s of beer.\nTake one down and pass it around, ",i, i > 1 ? "s" : "",i, i > 1 ? "s" : "");if (i > 1)printf("%d bottle%s of beer on the wall.\n\n",i - 1, i > 2 ? "s" : "");else printf("no more bottles of beer on the wall.\n\n");}printf("No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.");return 0;}' a.c -o beer
Run with: ./beer

(assuming a.c is the source file). Compiles with GCC (even with -Wall -Wextra -pedantic (and -std=c99 or -std=c89)). Booyah.

And yes, I'm being cheeky.

You're never going to beat smr.c =P

Don't pay much attention to "the hedgehog" in my nick, it's just because "Sik" was already taken =/ By the way, Sik is pronounced like seek, not like sick.

I totally cheated but here's a go with C gets it done in 187 characters

You have to pass in the correct strings to get it to work


#include<stdio.h>
int main(int c, char** a){
    for(c=99;c>0;--c)
        printf("%d %s %s, %d %s. %s, %d %s %s\n",c,(c==1)?a[4]:a[1],a[2],c,(c==1)?a[4]:a[1],a[3],c-1,((c-1)==1)?a[4]:a[1],a[2]);
    printf("%s",a[5]);
}

"bottles of beer" "on the wall" "Take one down pass it around" "bottle of beer" "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."

If cheating is allowed you could just pass the entire text in on the command line and do a puts().

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

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==')));?>

The executed code (can probably still be tweaked to take less space) is as follows:


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

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

Don't pay much attention to "the hedgehog" in my nick, it's just because "Sik" was already taken =/ By the way, Sik is pronounced like seek, not like sick.

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')))

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

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

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¶®Õ"));?>

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

Don't pay much attention to "the hedgehog" in my nick, it's just because "Sik" was already taken =/ By the way, Sik is pronounced like seek, not like sick.

This topic is closed to new replies.

Advertisement