Followers 0

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

## 96 posts in this topic

Right now I am seeing if I can abuse Python 2.7 into submission, but I see it's going to be tough to get under 218

I finally brought my Python down to 250, but I'm running into entropy limits here - the majority of my overhead is in language keywords.

I'm probably going to have to go to a regexp to drop this any further...

Edit: down to 243, by dint of tuple-as-conditional tricks.

Edited by swiftcoder
1

##### Share on other sites

Wow - I'm only down to 284 with Python ... I need to learn more "magic" tricks. Ruby I am down to 243.

i = 99
m = ", "
n = "."
r = " of beer"
a = " on the wall"
b = " bottles" + r
c = b + a
d = b + n
e = "\n"
f = c + m
g = c + n
h = "Take one down and pass it around, "
o ="1 bottle" + r
k = ""
j = ""
p = "o more"
q = "n" + p
while i != 2:
j = str(i)
k = str(i-1)
print  j + f + j + d + e + h + k + g
i -=1
print k + f + k + d + e + h + o + n + e + o + a + m + o + n + e + h + q + g + e + "N" + p + f + q + d + e + "Go to the store and buy some more, 99" + g


Edited by Shippou
0

##### Share on other sites

Thought I would have another go, this time without any cheating. I have a Python3 solution down to 222 non-whitespace characters. If it were Python2 I could shave off another char since print wouldn't require brackets.

[source]B = lambda i,n='n': ', %s bottle%s of beer' % ((n+'o more',i%100)[i!=0], ('s','')[i==1])

n = '.\n'
w = ' on the wall'
for i in range(99,-1,-1):
print(B(i,'N')[2:]+w+B(i)+n+('Go to the store and buy some more', 'Take one down and pass it around')[i > 0]+B(i-1)+w+n)

[/source]

Edit: Looks like Swiftcoder and I are converging towards the same solution.

Edit2: I'm tempted to think that a clever use of a list comprehension or a forward-counting range (a descending range is quite verbose in Python) could shorten it even more. Also, I wonder whether buffering the string and doing some post-processing to fiddle the special cases could work.

Edited by dmatter
2

##### Share on other sites

180 non-whitespace, 212 incl. whitespace

n=:<'no more'
d=:,"1
b=:<'bottles of beer'
o=:<'on the wall'
t=:<'take one down, pass it around'
c=:b,"_1~;/>:i.99
(|.c d o d c d t d b,"_1~o,"_1~n 0};/i.99),o,~b,~n,b,o,n,b,'go to the store and buy some more';99

Edited by jperalta
2

##### Share on other sites

Probably at my limit here with 241 total, 210 without whitespace:

def b i,c=0;"#{i<1?"#{c<1??n:?N}o more":i} bottle#{?s if i!=1} of beer"end
w=" on the wall"
99.downto(0){|i|puts"#{b i,1}#{w}, #{b i}.\n#{i>0?"Take one down and pass it around, #{b i-1}#{w}":"Go to the store and buy some more, #{b 99}#{w}"}."}


0

##### Share on other sites

Here's my go with ruby: 219 with whitespace 202 without.

b,w,n=" bottles of beer"," on the wall","no more"
a=b+w
99.downto(1){|i|z=i.to_s;t=i-1;print z,a,", ",z,b,".\nTake one down pass it around, #{(t==0)?n:t}",a,"\n"}
print n,a,n,b,"\nGo to the store and buy some more 99",a

Obvious extra characters that I didn't notice at first

 z=i.to_s;

Eliminating those takes the count down to 210/193 respectively.

Edited by Aether_plus
0

##### Share on other sites

Here's my C++ attempt

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

int main()
{
for(int i=100;i-->1;)
std::cout n(i) ", "<< i a(i) ".\nTake one down and pass it around, " n(i-1) ".\n\n";

std::cout << "No more" a(0) " on the wall, no more" a(0) "\nGo to the store and buy some more, " n(99) ".";
}

Characters w/o spaces: 282

Characters: 366

Edit another tweak

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

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

Characters w/o spaces: 280

Characters: 369

0

##### Share on other sites
#include <iostream>

The [tt]#include <iostream>[/tt] is eating up a ton of characters.

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

0

##### Share on other sites

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) ".";
}
0

##### Share on other sites

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

0

##### Share on other sites

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

1

##### Share on other sites

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

1

##### Share on other sites

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

1

##### Share on other sites

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

1

##### Share on other sites

The [tt]#include <iostream>[/tt] is eating up a ton of characters.

I wonder if one could make an end run around this by implicitly defining [tt]printf()[/tt]? 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.

1

##### Share on other sites

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

##### Share on other sites

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
0

##### Share on other sites

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

##### Share on other sites

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

##### Share on other sites

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

0

##### Share on other sites

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
0

##### Share on other sites

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

0

##### Share on other sites

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

0