99 Bottles Of Beer Challenge With Least Amount Of Characters ?

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

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.

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

Advertisement

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







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

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.

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

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

Came back to tinker and got it down to a cool 207 non-whitespace lines:

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

e = '.\n'
i = 99
while i >= 0:
q = B('N')[2:] + B()[:-12]+e + ('Go to the store and buy some more', 'Take one down and pass it around')[i > 0]
i -= 1

print(q+B()+e)[/source]

There might yet be a sneaky way to move the e variable into the B lambda that results in fewer chars but I'm just not seeing it.


243 with Clojure. It's hard because every kind of operator call requires parens. tongue.png


((fn f [i]
     (let [b " bottle" o " of beer" w " on the wall" p println s str
           t "\nTake one down and pass it around, " m "o more" d \.
           j (dec i) q (= 2 i) a (s b \s o) l "\n" h ", "]
       (p (s i a w h i a d
          t j b (if q "" \s) o w d l))
       (if q
         (p (s 1 b o w h 1 b o d
            t \n m a w d
            l l "N" m a w h \n m a d
            l "Go to the store and buy some more, 99" a w d))
         (f j)))) 99)

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.

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


#include <iostream>

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? :)

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

This topic is closed to new replies.

Advertisement