• Create Account

## 99 Bottles Of Beer Challenge With Least Amount Of Characters ?

101 replies to this topic

Posted 19 July 2013 - 04:53 PM

After some more tweaking I brought it down to 274 could be 272 if you aren't required to have to line breaks after each round.

#include <iostream>
#define a(i) << " bottle" << (i!=1?"s":"") << " of beer" << (i>-1?" on the wall":".\n") <<

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

Edited by adam4813, 19 July 2013 - 04:57 PM.

Posted 19 July 2013 - 05:38 PM

Last one, had an issue with 1 bottle

#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(0) w ", no more" a(0) ".\nGo to the store and buy some more, 99" a(9) w ".";
}

Characters w/o spaces: 277

Characters: 366

### #63Sik_the_hedgehog  Members

Posted 19 July 2013 - 08:50 PM

I wonder if one could make an end run around this by implicitly defining printf()? That's sort of legal C, right?

C doesn't require function declarations, yeah (though I think they were planning to change that in the latest revision).

Though now you got me wondering if there are any variants to printf (there's puts, but that one only allows printing strings as-is).

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.

Posted 20 July 2013 - 10:17 AM

#define a(i) << " bottle" << (i!=1?"s":"") << " of beer" <<

#define a(i) << " bottle" << (i-1?"s":"") << " of beer" <<

saves 1 character ;)

EDIT - do you actually need the brackets around the ternary operator? << has really low operator precedence?

EDIT:

I'm pretty sure you could change the for loop to for(int i = 99; --i; ) adjust the a(i) macro to test i instead, and use i+1 and i instead of i and i-1 in the loop too?

Not got a compiler to hand though...

EDIT2: You could also get rid of the std::cout outside the loop by doing << --i ? "" : /*output from outside the loop*/; at the end of the loop output line as well, also doing the loop decrementing on that line too, saves a few characters.

Edited by Paradigm Shifter, 20 July 2013 - 12:44 PM.

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

Posted 20 July 2013 - 09:57 PM

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

Edited by adam4813, 20 July 2013 - 10:13 PM.

### #66Sik_the_hedgehog  Members

Posted 21 July 2013 - 06:09 AM

EDIT - do you actually need the brackets around the ternary operator? << has really low operator precedence?

The ternary operator is right above assignment (= and variants) in terms of precedence. It's really low, much lower than << (makes sense, since it's supposed to have less precedence than conditions).

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.

### #67Cornstalks  Members

Posted 21 July 2013 - 03:02 PM

The #include <iostream> is eating up a ton of characters.

I wonder if one could make an end run around this by implicitly defining printf()? That's sort of legal C, right?

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

But if you use C89, you must put return 0;. If you use C99 (and later), you can omit return 0;. Also, if you use C99 (and later), then that for loop is fine; if you use C89, then i would have to be declared before it.

[ 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 ]

### #68swiftcoder  Senior Moderators

Posted 21 July 2013 - 04:30 PM

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

But if you use C89, you must put return 0;. If you use C99 (and later), you can omit return 0;. Also, if you use C99 (and later), then that for loop is fine; if you use C89, then i would have to be declared before it.

This is C/C++ we are talking about, though... the least standards-compliant languages of all time.

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

Tristam MacDonald - Software Engineer @ Amazon - [swiftcoding] [GitHub]

### #69Sik_the_hedgehog  Members

Posted 21 July 2013 - 09:54 PM

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

The main catch (and I think this is true in C89 too) is that the function prototype becomes whatever types you used in the first function call. This means that if you use the same function twice with different parameter types (implicit casting can completely screw you up here) you will end up with a compiling error (if I recall correctly) as the compiler now won't be able to tell which prototype is correct.

Edited by Sik_the_hedgehog, 21 July 2013 - 09:55 PM.

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.

### #70Cornstalks  Members

Posted 21 July 2013 - 09:59 PM

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

### #71Cornstalks  Members

Posted 21 July 2013 - 10:12 PM

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).
[ 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 ]

### #72Sik_the_hedgehog  Members

Posted 21 July 2013 - 10:53 PM

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.

### #73Aether_plus  Members

Posted 23 July 2013 - 03:38 PM

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

Edited by Aether_plus, 23 July 2013 - 03:46 PM.

Posted 23 July 2013 - 05:56 PM

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

### #75samoth  Members

Posted 24 July 2013 - 10:20 AM

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

<?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.<?  ### #76Sik_the_hedgehog Members Posted 24 July 2013 - 11:44 AM 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, 24 July 2013 - 11:47 AM. 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. ### #77swiftcoder Senior Moderators Posted 24 July 2013 - 01:43 PM 274 characters PHP (no "cheating" in a sense of printing the contents of an URL or such) <?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 import zlib, uu exec(zlib.decompress('eJwljrFuwzAMRHd/xS0GZcgp5GwxoAxZunXqlmqQYRYRKkuJpcDo35dxOT2CxL27wCL6ZZo9kqVE\nI6hHWzDlWiML5G9MzCtyQr0xNh8joYVSoR2M6ZOmjCWvTN01WGtcDyr0wmF0XcMST29fiZogdDo1\n2y1ERsDZwowNZB5yuCj6kIDj6KBl6a7jYTg6zbIpes+oeZeXKiL4NGN6/qLkhf/V4vz0PywdGXPe\n0v5y96UgVPg1P9P8qoczjNudAQeLYcf7GlJVDy1Wzd0fdlNKWA==\n'.decode('base64'))) Edited by swiftcoder, 24 July 2013 - 01:45 PM. Tristam MacDonald - Software Engineer @ Amazon - [swiftcoding] [GitHub] ### #78samoth Members Posted 24 July 2013 - 01:48 PM 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... ### #79samoth Members Posted 24 July 2013 - 02:34 PM 186 characters! 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¶®Õ"));?>
`

### #80Sik_the_hedgehog  Members

Posted 24 July 2013 - 09:45 PM

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.