Skip to main content
GameDev.net gamedev.net
Using GameDev.net for your class this semester?
Learn more →
🔒 Locked

99 bottles Challenge thread 2

Started by dubplatecode Jul 4, 2015 at 4:24 AM 10 replies 7.4k views
Original Post
dubplatecode
dubplatecode
I noticed the 99 bottles challenge a few threads down and thought I would have a go for fun.

C++, 285 non-white space characters.

http://codepad.org/j8iAL9Mw

It outputs correct in GCC and VS.
I slimmed a few characters but found a difference in order of operations between VS and GCC and left those out.
The codepad site didn't compile C++11 so that added a few characters back on.

Previous thread.

(http://www.gamedev.net/topic/645151-99-bottles-of-beer-challenge-with-least-amount-of-characters/)

Interesting seeing how other languages do the same job in less.

From a scan the previous _correct_ output C++ attempt was 314 non-whitespace characters.

Any C++ people want to attempt improving on this? :-)
Endurion
Endurion

Nifty. Easy thing, make

#define p printf("%

Also, remove code formatting, out with the tabs, empty line and blanks in the for loop.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>
dubplatecode
dubplatecode

Nifty. Easy thing, make

#define p printf("%

Also, remove code formatting, out with the tabs, empty line and blanks in the for loop.

Cheers.

yeah I thought about printf("% - sadly VS and g++ error incomplete strings - oddly #define substitution is made after. see http://codepad.org/rDUemoAF

Code formatting, tabs, empty line, blanks don't reduce total non-whitespace characters.

these ASCII characters don't count towards the total:

case 32:

case 9:
case 0:
case 13:
case 10:

rip-off
rip-off
Decided to try C++, my current attempt clocks in at 281 291 non-whitespace characters (according to here here as the site in the earlier thread is no longer accessible):
#include <iostream>
#define L(i,n)  (i ? c << i : c << n << "o more") << " bottle" << (i - 1 ? "s" : "") << " of beer";
auto w = " on the wall";
int main() {
	auto &c = std::cout;
	for ( int i = 100 ; i-- ; ) {
		L(i, 'N');
		c << w << ", ";
		L(i, 'n');
		c << ".\n" << (i ? "Take one down and pass it around" : "Go to the store and buy some more") << ", ";
		L((i ? i - 1 : 99), 'n');
		c << w << ".\n\n";
	}
}
There is a trivial newline difference for the final line between our programs.
rip-off
rip-off
I also tried to create a new Ruby version from scratch, but eventually converged on a similar solution to last time - but managed to reduce it to 199 characters:

def b c, n=?n
	"#{c > 0 ? c : n + "o more"} bottle#{?s if c != 1} of beer"
end
W = " on the wall" 
99.downto(0) {
	|i|
	
	puts "%s, %s.
%s.

" % [
		b(i, ?N) + W, b(i), 
		(i > 0 ? "Take one down and pass it around, #{b i - 1}" : "Go to the store and buy some more, #{b 99}") + W
	]
}
Embedding actual newlines in the string literal is a little cheeky - I'm not sure it should count as they are significant to the program's output. Using newline escape codes instead that is still only 205 characters, which beats my previous attempt of 210.
dubplatecode
dubplatecode

very nice.

That new non-whitespace counting website totals mine 276 (274 for C++11 version). The difference is the site doesn't count the characters inside the #include brackets ie:

It reports:
"#include <>" as 10 non-white space characters.
"#include " as 8 non-white space characters.
"#include " as 8 non-white space characters.

C++11 version.


#include <cstdio>

int main()
{
auto b = "no more bottles of beer on the wall";
#define p printf(
#define w 8,b + 14+(i<2)
for( int i=99; p"%d %.6s%s, %d %.6s%.*s.\nTake one down and pass it around, ",
i, b +w, i, b+8, (i>1)+w), --i;)
p "%d %.6s%s.\n\n", i, b + w );
p"%s.\n\nN%s, %.23s.\nGo to the store and buy some more, 99%s.",b, b+1, b, b+7);
}
rip-off
rip-off

The difference is the site doesn't count the characters inside the #include brackets...

Curses! :] Was just the first online character counter I found, obviously I didn't bother to double check! Some light Googling finds that this one does seems to count such characters, hopefully it doesn't have any other quirks.

I've updated my earlier post, thanks. Now I'll have to try again...
dubplatecode
dubplatecode
I hope you don't mind a combined effort with your code, I saw some wins and was tempted, squeezed 41 characters out.

#include <iostream>
int main() 
{            
    #define c std::cout <<    
    #define L(n) (i? c (i<0?99:i) : c n"o more") << " bottle" << "s of beer"+!(i-1) << " on the wall"
    for ( int i = 99; i+1 ;     
        L("N") ", ",        
        L("n") ".\nTake one down and pass it around, \0.\nGo to the store and buy some more, "+12+!i*37,        
        i--,
        L("n") ".\n\n");    
}

It's now 250 non-ws characters :-) the new character counting website is good!

The most interesting change is iterating from 99 to -1, creating a third state of 'i' for (99/#/"no more"). Two other major differences to reduce logic is combining string literals and string pointer manipulation, the rest are minor changes.

(I noticed the new line at the end can be fixed adding 3 characters, by moving "\n\n" outside the for).

rip-off
rip-off
I don't mind at all, very nice! Using pointer arithmetic to skip portions of a string occurred to me at one stage, but not using the advanced printf formatting, I think it turned out to cost more characters than it bought me without that.

I was trying to come up with completely different approaches, here is a regex based Ruby version - at 239 characters it isn't the smallest but I think the variations are interesting too:
b = "0 bottles of beer"
w = b + " on the wall"

s = "#{w}, #{b}.
Go to the store and buy some more, #{w}.

"
99.downto(0) {
	|n|
	m = 0
	puts s.gsub(/(\d+|es|G[^,]+)/) { 
		|d| 
		m += 1
		c = m > 4 ? n - 1 : n
		d == 'es' ? c == 1 ? 'e' : d : m == 5 ? n > 0 ? "Take one down and pass it around" : d : c < 0 ? 99 : c > 0 ? c : "#{m > 1 ? ?n : ?N}o more"
	}
}
boogyman19946
boogyman19946

My first attempt was in Python with 254 characters:


for i in range(99,-1,-1):
    a="bottle"
    s=lambda k,n: (n+"o more"if k<1 else str(k))+" "+(a+""if k==1 else a+"s")
    o="of beer"
    e=o+" on the wall"
    print s(i,"N"),e+",",s(i,"n"),o+".\n"+("Take one down and pass it around, "+s(i-1,"n")if i>0 else "Go to the store and get some more, "+s(99,"")),e+".\n"

It's alright. I like how the lambda helped wrap some of the switching into one (kind of) concise function, but I kind of wish it used less characters. I also wish Python had a ? operator. Damn you Python for trying to be expressive!

I thought then I'd have a hand at the challenge in a functional language. Enter Haskell:


z=concat
a=" bottle"
e=a++"s"
y="o more"
b 0="n"++y++e
b 1="1"++a
b n=show n++e
c=" of beer"
d=c++" on the wall"
p=".\n"
q n=z[d,", ",b n,c,p]
f 0=z["N",y,e,q 0,"Go to the store and buy some more, ",b 99,d,p]
f n=z[b n,q n,"Take one down and pass it around, ",b $ n-1,d,p,"\n",f(n-1)]
main = putStrLn(f 99)

with 253 non-ws characters. I suck at Haskell biggrin.png It too me forever just to set up the main function.

I started writing another version in Java but I reached 200 characters just setting up a bare bones program. I'd probably go well into the 300s with it.

EDIT: I actually think I might have stolen that Haskell version from someone on the old thread a while ago and not realized it. My version uses less characters though :D

Yo dawg, don't even trip.
RLS0812
RLS0812

Did anyone ever set up some sort of unofficial 'world's record' for this challenge in each language ?

I cannot remember the books I've read any more than the meals I have eaten; even so, they have made me. ~ Ralph Waldo Emerson
Don Carnage
Don Carnage
Shortest I could manage in Powershell ph34r.png (251 chars):
function n($n, $c) {
    $s = 's'
    $( switch ($n) {
        -1 { '99' }
        0  { $c + 'o more' }
        1  { $s = ''
             "$n" }
        default { "$n" }         
    }) + " bottle$($s) of beer"
}
$w = ' on the wall'
99..0 | % { 
    "$(n $_ 'N')$w, $(n $_ 'n')."
    $( if ($_ -eq 0) { 
        'Go to the store and buy some more' 
    } else { 
        'Take one down and pass it around' 
    }) + ", $(n($_-1)'n')$w.`n" 
}
It is I, the spectaculous Don Karnage! My bloodthirsty horde is on an intercept course with you. We will be shooting you and looting you in precisely... Ten minutes. Felicitations!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.