97
\$\begingroup\$

Write a program that outputs the lyrics to 99 Bottles of Beer, in as few bytes as possible.

Lyrics:

99 bottles of beer on the wall, 99 bottles of beer.
Take one down and pass it around, 98 bottles of beer on the wall.

98 bottles of beer on the wall, 98 bottles of beer.
Take one down and pass it around, 97 bottles of beer on the wall.

97 bottles of beer on the wall, 97 bottles of beer.
Take one down and pass it around, 96 bottles of beer on the wall.

96 bottles of beer on the wall, 96 bottles of beer.
Take one down and pass it around, 95 bottles of beer on the wall.

95 bottles of beer on the wall, 95 bottles of beer.
Take one down and pass it around, 94 bottles of beer on the wall.

....

3 bottles of beer on the wall, 3 bottles of beer.
Take one down and pass it around, 2 bottles of beer on the wall.

2 bottles of beer on the wall, 2 bottles of beer.
Take one down and pass it around, 1 bottle of beer on the wall.

1 bottle of beer on the wall, 1 bottle of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.

Rules:

  • Your program must log to STDOUT or an acceptable alternative, or be returned from a function (with or without a trailing newline).
  • Your program must be a full, runnable program or function.
  • Languages specifically written to submit a 0-byte answer to this challenge are allowed, just not particularly interesting.

    Note that there must be an interpreter so the submission can be tested. It is allowed (and even encouraged) to write this interpreter yourself for a previously unimplemented language.

  • This is different from the output by HQ9+ or 99. Any answers written in these languages will be deleted.

As this is a catalog challenge, this is not about finding the language with the shortest solution for this (there are some where the empty program does the trick) - this is about finding the shortest solution in every language. Therefore, no answer will be marked as accepted.

Catalogue

The Stack Snippet at the bottom of this post generates the catalogue from the answers a) as a list of shortest solution per language and b) as an overall leaderboard.

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

## Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

## Ruby, <s>104</s> <s>101</s> 96 bytes

If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the last number in the header:

## Perl, 43 + 2 (-p flag) = 45 bytes

You can also make the language name a link which will then show up in the snippet:

## [><>](http://esolangs.org/wiki/Fish), 121 bytes

<style>body { text-align: left !important} #answer-list { padding: 10px; width: 290px; float: left; } #language-list { padding: 10px; width: 290px; float: left; } table thead { font-weight: bold; } table td { padding: 5px; }</style><script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="language-list"> <h2>Shortest Solution by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr> </thead> <tbody id="languages"> </tbody> </table> </div> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr> </thead> <tbody id="answers"> </tbody> </table> </div> <table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr> </tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr> </tbody> </table><script>var QUESTION_ID = 64198; var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe"; var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk"; var OVERRIDE_USER = 36670; var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page; function answersUrl(index) { return "//api.stackexchange.com/2.2/questions/" + QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER; } function commentUrl(index, answers) { return "//api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER; } function getAnswers() { jQuery.ajax({ url: answersUrl(answer_page++), method: "get", dataType: "jsonp", crossDomain: true, success: function (data) { answers.push.apply(answers, data.items); answers_hash = []; answer_ids = []; data.items.forEach(function(a) { a.comments = []; var id = +a.share_link.match(/\d+/); answer_ids.push(id); answers_hash[id] = a; }); if (!data.has_more) more_answers = false; comment_page = 1; getComments(); } }); } function getComments() { jQuery.ajax({ url: commentUrl(comment_page++, answer_ids), method: "get", dataType: "jsonp", crossDomain: true, success: function (data) { data.items.forEach(function(c) { if (c.owner.user_id === OVERRIDE_USER) answers_hash[c.post_id].comments.push(c); }); if (data.has_more) getComments(); else if (more_answers) getAnswers(); else process(); } }); } getAnswers(); var SCORE_REG = /<h\d>\s*([^\n,<]*(?:<(?:[^\n>]*>[^\n<]*<\/[^\n>]*>)[^\n,<]*)*),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/; var OVERRIDE_REG = /^Override\s*header:\s*/i; function getAuthorName(a) { return a.owner.display_name; } function process() { var valid = []; answers.forEach(function(a) { var body = a.body; a.comments.forEach(function(c) { if(OVERRIDE_REG.test(c.body)) body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>'; }); var match = body.match(SCORE_REG); if (match) valid.push({ user: getAuthorName(a), size: +match[2], language: match[1], link: a.share_link, }); else console.log(body); }); valid.sort(function (a, b) { var aB = a.size, bB = b.size; return aB - bB }); var languages = {}; var place = 1; var lastSize = null; var lastPlace = 1; valid.forEach(function (a) { if (a.size != lastSize) lastPlace = place; lastSize = a.size; ++place; var answer = jQuery("#answer-template").html(); answer = answer.replace("{{PLACE}}", lastPlace + ".") .replace("{{NAME}}", a.user) .replace("{{LANGUAGE}}", a.language) .replace("{{SIZE}}", a.size) .replace("{{LINK}}", a.link); answer = jQuery(answer); jQuery("#answers").append(answer); var lang = a.language; lang = jQuery('<a>'+lang+'</a>').text(); languages[lang] = languages[lang] || {lang: a.language, lang_raw: lang.toLowerCase(42), user: a.user, size: a.size, link: a.link}; }); var langs = []; for (var lang in languages) if (languages.hasOwnProperty(lang)) langs.push(languages[lang]); langs.sort(function (a, b) { if (a.lang_raw > b.lang_raw) return 1; if (a.lang_raw < b.lang_raw) return -1; return 0; }); for (var i = 0; i < langs.length; ++i) { var language = jQuery("#language-template").html(); var lang = langs[i]; language = language.replace("{{LANGUAGE}}", lang.lang) .replace("{{NAME}}", lang.user) .replace("{{SIZE}}", lang.size) .replace("{{LINK}}", lang.link); language = jQuery(language); jQuery("#languages").append(language); } }</script>

\$\endgroup\$
25
  • 17
    \$\begingroup\$ Whoever closevoted this, the other one is a popularity contest... \$\endgroup\$
    – TheDoctor
    Commented Nov 18, 2015 at 15:19
  • 26
    \$\begingroup\$ This is a subtask of the Create an HQ9+ Interpreter golf. \$\endgroup\$
    – Geobits
    Commented Nov 18, 2015 at 15:25
  • 15
    \$\begingroup\$ Note that quartata had already sandboxed a 99BB catalog several weeks ago and was planning to post it. \$\endgroup\$
    – Alex A.
    Commented Nov 18, 2015 at 17:07
  • 16
    \$\begingroup\$ @GamrCorps Please do not unnecessarily change the rules after the challenge has started. None of the characters in the output should be optional. \$\endgroup\$
    – feersum
    Commented Nov 18, 2015 at 18:42
  • 8
    \$\begingroup\$ To try and head off any newcomers who can't see deleted answers, if you're thinking of using a language with a 99 Bottles song built-in, double check the output matches the desired output of the question. There have already been half a dozen deleted HQ9+ answers, as well as other languages with incorrect outputs. \$\endgroup\$
    – Jo King
    Commented Oct 22, 2018 at 4:05

181 Answers 181

1
2 3 4 5
7
47
\$\begingroup\$

C#, 285 298 289 Bytes

(My first attempt at Code golfing ...)

class d{static void Main(){for(int b=99;b>0;)System.Console.Write("{0}{6}{1}{2}, {0}{6}{1} of beer. {3}, {4}{6}{5}{2}.{7}",b,b==1?"":"s"," of beer on the wall",b==1?"Go to the store and buy some more":"Take one down and pass it around",b==1?99:b-1,b==2?"":"s"," bottle",b--<2?"":"\n\n");}}

A little bit ungolfed:

class d{
    static void Main(){
        for(int b = 99; b > 0;){
            System.Console.Write("{0}{6}{1}{2}, {0}{6}{1} of beer.\n{3}, {4}{6}{5}{2}.{7}", b, b==1 ? "" : "s", " of beer on the wall", b == 1 ? "Go to the store and buy some more" : "Take one down and pass it around", b == 1 ? 99 : b-1, b== 2 ? "" : "s", " bottle", b--<2 ? "" : "\n\n");
        }
    }
}
\$\endgroup\$
14
  • 13
    \$\begingroup\$ tip - use var instead of string :) \$\endgroup\$
    – Belfield
    Commented Nov 18, 2015 at 16:48
  • 2
    \$\begingroup\$ 2 bytes from replacing " bottle" with a format argument though I'm sure there is a better way, having 3 instances of bottle hurts my eyes... \$\endgroup\$
    – Namaskar
    Commented Nov 18, 2015 at 18:21
  • 4
    \$\begingroup\$ b==1 can be replaced with b<2. \$\endgroup\$ Commented Nov 18, 2015 at 22:48
  • 2
    \$\begingroup\$ Your for loop could be written like this for(int b = 100; b--> 1;) \$\endgroup\$ Commented Nov 19, 2015 at 10:20
  • 2
    \$\begingroup\$ Then maybe we should wait for the challenge author to decide if a trailing newline is allowed or not. \$\endgroup\$ Commented Nov 28, 2015 at 13:24
36
\$\begingroup\$

Motorola MC14500B Machine Code, 46612 bytes

For length reasons, I can not post the program here. However, it can be found here in hexadecimal, and here in binary (padded with 0s).


This is the shortest possible program in Motorola MC14500B machine code. It consists of only 1000 and 1001 (8 and 9, respectively); one opcode for each bit of output.

It uses 93,224 half-byte opcodes, and outputs the song lyrics one bit at a time. This is the only possible output method.

For those interested, the output goes to pin #3 (of 16), the I/O pin.


Explanation

8    Store the register's value
9    Store the logical complement of the register's value

The register starts at 0.


Code Trivia

  • The hexadecimal is 93,224 8s and 9s long.

  • The binary is 745,792 1s and 0s long.

  • I used the Python 2 code below to generate the code. Input 0 for binary and 1 for hexadecimal.

    a,b=["8","9"]if input()else["00001000","00001001"]
    f="""99 Bottles of Beer lyrics"""
    print''.join(b if int(i)else a for i in''.join((8-len(bin(i)[2:]))*'0'+bin(i)[2:]for i in bytearray(f)))
\$\endgroup\$
4
  • 6
    \$\begingroup\$ Please tell me you didn't just go and write this all out without some sort of string generator... :c \$\endgroup\$ Commented Nov 20, 2015 at 8:16
  • 2
    \$\begingroup\$ See the new "Code Trivia" section :P @VoteToClose \$\endgroup\$
    – Zach Gates
    Commented Nov 23, 2015 at 5:24
  • \$\begingroup\$ The links are broken :( \$\endgroup\$ Commented Dec 23, 2015 at 15:58
  • 1
    \$\begingroup\$ I'll fix it when I get back home. Sorry about that ): @ETHproductions \$\endgroup\$
    – Zach Gates
    Commented Dec 23, 2015 at 16:37
32
\$\begingroup\$

Vitsy, 0 Bytes



Seriously ain't got nothin' on me. (@Mego I'm so sorry. ;))

Try it online! (Just hit "Run")

\$\endgroup\$
12
  • 7
    \$\begingroup\$ o_o I need something interesting for Simplex to do in zero bytes :P \$\endgroup\$ Commented Nov 18, 2015 at 19:09
  • 4
    \$\begingroup\$ @CᴏɴᴏʀO'Bʀɪᴇɴ I think you mean, "I need something useful for Simplex to do in zero bytes." \$\endgroup\$ Commented Nov 19, 2015 at 11:21
  • 4
    \$\begingroup\$ @VoteToClose - How does this work? I honestly don't know, I'm not a code golfer, but I enjoy coming here and seeing people and languages do it. But I can't comprehend this. +1 because it looks impressive! \$\endgroup\$
    – Jonnny
    Commented Nov 20, 2015 at 14:09
  • 1
    \$\begingroup\$ @Jonnny Click here to see the interpreter's file handler. The file handler will see that a file contains zero bytes, and, if so, print out the lyrics. c: \$\endgroup\$ Commented Nov 20, 2015 at 14:19
  • 1
    \$\begingroup\$ @Jonnny Yeah - it's a work in progress, one day, it'll be better than Seriously. But for now... We wait. If you want a good golfing language, see the Seriously answer, it's got some crazy stuff in it. \$\endgroup\$ Commented Nov 20, 2015 at 14:30
29
\$\begingroup\$

Seriously, 1 byte

N

If the stack is empty (which it is at the start), N pushes the lyrics. Then they're implicitly printed at EOF.

Thanks to @Mego for fixing the Seriously interpreter.

\$\endgroup\$
7
  • 26
    \$\begingroup\$ Martin said in the Hello World challenge, ">please don't downvote boring (but valid) answers in languages where there is not much to golf - these are still useful to this question as it tries to compile a catalogue as complete as possible. However, do primarily upvote answers in languages where the authors actually had to put effort into golfing the code." This answer is uninteresting, but it is a valid and the shortest solution. \$\endgroup\$
    – lirtosiast
    Commented Nov 18, 2015 at 17:17
  • 1
    \$\begingroup\$ When reading the question I couldn't wait to see you posting a Serious answer. But it looks like I don't even have to wait. :) \$\endgroup\$
    – Hexaholic
    Commented Nov 18, 2015 at 17:35
  • 10
    \$\begingroup\$ Seriusly???????? \$\endgroup\$
    – Vajura
    Commented Nov 19, 2015 at 10:59
  • 1
    \$\begingroup\$ I look forward to seeing your solution without the use of N :) \$\endgroup\$
    – user45941
    Commented Nov 19, 2015 at 14:34
  • 1
    \$\begingroup\$ Yeah - I have four down votes and my answer is valid. I concur with what is said in the top comment here. \$\endgroup\$ Commented Nov 19, 2015 at 16:06
21
\$\begingroup\$

JavaScript ES6, 230 218 198 196 192 188 185 bytes

for(x=99,z=(a=' on the wall')=>`${x||99} bottle${1-x?'s':''} of beer`+a;x;)alert(z()+', '+z`.
`+(--x?'Take one down and pass it around, ':'Go to the store and buy some more, ')+z()+'.')

Just just trimming off a few bytes while still keeping it looking clean and understandable.

3 most recent revisions:

for(x=99,z=a=>`${x||99} bottle${1-x?'s':''} of beer${a||' on the wall'}`;x;)alert(z()+', '+z(`.
`)+(--x?'Take one down and pass it around, ':'Go to the store and buy some more, ')+z()+'.')

for(x=99,z=a=>(x||99)+' bottle'+(1-x?'s':'')+' of beer',w=' on the wall';x;)alert(z()+w+', '+z()+(--x?`.
Take one down and pass it around, `:`.
Go to the store and buy some more, `)+z()+w+'.')

for(x=99,o=' bottle',q=b=o+'s',e=' of beer',w=e+" on the wall";x;)alert(x+b+w+', '+x+b+e+(--x?`.
Take one down and pass it around, `+x:`.
Go to the store and buy some more, 99`)+(b=1-x?q:o)+w+'.')
\$\endgroup\$
9
  • 1
    \$\begingroup\$ 2 bytes saved by putting the variables outside of the loop controls:x=99;w=" on the wall";e=" of beer";o=" bottle";b=o+"s";for(z="Go to the store and buy some more, "+x+b;0<x;)console.log(x+(2>x?o:b)+e+w+", "+x+(2>x?o:b)+e+".\n"+(1>--x?z:"Take one down and pass it around, "+x+(2>x?o:b))+e+w+".") \$\endgroup\$ Commented Nov 18, 2015 at 22:42
  • \$\begingroup\$ That's not what's saving those 2 bytes in your code. It's actually the removal of the parenthesis around (--x<1). For now I'll leave the variables inside the for statement for readability purposes to keep them all together. \$\endgroup\$
    – Adam Dally
    Commented Nov 18, 2015 at 22:57
  • 1
    \$\begingroup\$ @Stefnotch If you are wondering, I found this edit by examining my function calls...but I don't think this was your intent. Your advice is still relevant as a last resort, though. \$\endgroup\$
    – Adam Dally
    Commented Nov 22, 2015 at 16:49
  • 1
    \$\begingroup\$ @Paŭlo Ebermann It does execute alert for each verse, but you are free to change it to console.log to execute in the console, which would make it 194 bytes. Plus alerting the entire lyrics in one go doesn't work in Firefox, at least...it trims off a good 5-10 verses. \$\endgroup\$
    – Adam Dally
    Commented Nov 23, 2015 at 2:36
  • 1
    \$\begingroup\$ @Stefnotch. Well that 1-x is proving useful at the moment. \$\endgroup\$
    – Adam Dally
    Commented Nov 24, 2015 at 19:00
18
\$\begingroup\$

C, 197 196 bytes

main(i){for(i=299;i--/3;printf("%d bottle%s of beer%s%s",i/3?:99,"s"+5/i%2,i%3?" on the wall":i^3?".\nTake one down and pass it around":".\nGo to the store and buy some more",~i%3?", ":".\n\n"));}

I think I have reached the limit of this approach.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ "%d bottles of beer on the wallTake one down and pass it aroundGo to the store and buy some more,.\n"main(){for(;;)printf();} alone is 126 bytes, so that represents a hard lower bound unless someone finds a way to compress or reuse parts of the strings without significant overhead. I suspect you may have reached the limit of approaches in general, plus or minus a few bytes. \$\endgroup\$
    – Ray
    Commented Nov 19, 2015 at 23:31
18
\$\begingroup\$

JavaScript ES6, 328 318 307 305 bytes

Is an anonymous function. Add f= at the beginning to make function and f() to execute.

x=>eval('s=o=>v=(o?o:" no more")+" bottle"+(1==o?"":"s");for(o="",i=99;i>0;)o+=`${s(i)}@ on the wall, ${v}@.\nTake one down, pass it around, ${s(--i)}@ on the wall.\n`;o+`No more bottles@ on the wall, no more bottles@.\nGo to the store and buy some more, 99 bottles@ on the wall.`'.replace(/@/g," of beer"))
\$\endgroup\$
1
  • 3
    \$\begingroup\$ Pretty would be a lot more interesting if it was more than just one long string concatenation \$\endgroup\$
    – Sp3000
    Commented Nov 18, 2015 at 16:50
13
\$\begingroup\$

Java 304 301 300 295 Bytes

First time posting an answer. I heard we could use enum but could not find how.

interface A{static void main(String[]a){String b=" of beer",c=" on the wall",n=".\n",s;for(int i=100;i-->1;s=" bottle"+(i>1?"s":""),System.out.println(i+s+b+c+", "+i+s+b+n+(i<2?"Go to the store and buy some more, 99":"Take one down and pass it around, "+(i-1))+" bottle"+(i!=2?"s":"")+b+c+n));}}

Ungolfed

interface A {
    static void main(String[] a) {
        String b = " of beer", c = " on the wall", n = ".\n", s;
        for (int i = 100; i-- > 1; s = " bottle" + (i > 1 ? "s" : ""), System.out.println(i + s + b + c + ", " + i + s + b + n + (i < 2 ? "Go to the store and buy some more, 99" : "Take one down and pass it around, " + (i - 1)) + " bottle" + (i != 2 ? "s" : "") + b + c + n));
    }
}

Thanks to quartata, J Atkin and Benjamin Urquhart

\$\endgroup\$
15
  • \$\begingroup\$ You can save 2 bytes by using i<2 in place of i==1 and i>2 here: i!=2. \$\endgroup\$
    – J Atkin
    Commented Nov 21, 2015 at 19:14
  • 1
    \$\begingroup\$ As it turns out, this is good for java, but this doesn't work well for groovy (213 vs 245 bytes). \$\endgroup\$
    – J Atkin
    Commented Nov 21, 2015 at 19:37
  • 1
    \$\begingroup\$ Not really, groovy is one of the JVM languages. Fo most applications groovy code is shorter than the java code that does the same thing. goovy-lang.org \$\endgroup\$
    – J Atkin
    Commented Nov 21, 2015 at 20:47
  • 1
    \$\begingroup\$ @BenjaminUrquhart Great! Modified it ! \$\endgroup\$ Commented Mar 24, 2019 at 21:34
  • 1
    \$\begingroup\$ Building on @JeffreyH 285 bytes \$\endgroup\$
    – ceilingcat
    Commented Oct 21, 2023 at 16:52
12
\$\begingroup\$

Brainfuck, 743 bytes

++++++++++>>--->++++>------>-->>++>+>>+>->++[[>+++++++[>++>+>+<<<-]<-]+<+++]>>>>>--
>>-->>++>->+++[<]>[-<<+[<->-----]<---[<[<]>[->]<]+<[>-]>[-<++++++++++<->>>]-[<->---
--]<+++[<[<]>[+>]<]<->>>[>[[>]<<<<.<<<<---.>>>-.<<<++++.<.>>>.-.<<.<.>-.>>+.<+++.>-
.<<<.>---.>>.<<+++.<.>>>++.<<---.>----..<<.>>>>--.+++<<+.<<.>.>--.>-.<+++.->-.+<<++
+.<<.>.<<<<-<]>[[>]<<<-.<<<.<<<.>>.>.<<< . > > .<++++.---.<.>>-.+.>.<--.<.<.>----.>
>-.<<+++.<.>--.>+++.++++.<<.>>------.>+.--.<<+++.<.>>>.++.<-.++<.-<<.>.<<<<-<<<++++
+++++.>>>]<+>]<++[<<[<]>[.>]>>>>>>.>--.>>.<..->>.<<<+++.<<<<-[>>>>>.[<]]<[>]>+>>>.>
>>.<<+.<.>----.+++..->-.++[<<]<-[>>>>>.>>>.-.+<<<.>>.<++++.---.<.>>+++.---<----.+++
>>>..[<<]]<<[>]>-[>>>>++.--<.<<<+[>>>.<<<<]>[>]<-<]>>[>>.>.<<<<]>[<<++>]<[>]<-]>+>]

Try it online!

The above uses wrapping cells in a few places to save instructions. I've also made a non-wrapping version in 755 instructions.


Uncompressed

The following is a polyglot in Brainfuck Annotation Language.

; byte sequence
; \n _ _ _ _ c \n comma space d t o l T G
++++++++++>>
--->++++>------>-->>++>+>>+>->++
[[>+++++++[>++>+>+<<<-]<-]+<+++]
>>>>>-->>-->>++>->+++[<]

c = 0
n = 100

>
while(n)
[
  n = n minus 1
  -<<
  N = str(n)
  ; first time \n _ becomes 9 9
  +[<->-----]<---[<[<]>[->]<]
  +<[>-]>[-<++++++++++<->>>]
  -[<->-----]<+++[<[<]>[+>]<]

  <->>>
  if(c)
  [
    >
    if(n)
    [
      'Take one down and'
      [>]<<<<.<<<<---.>>>-.<<<++++.<.>>>.-.<<.<.>-.>>+.<+++.>-.<<<.>---.>>.<<+++.
      ' pass it around' comma space
      <.>>>++.<<---.>----..<<.>>>>--.+++<<+.<<.>.>--.>-.<+++.->-.+<<+++.<<.>.<<<<-<
    ]>
    else
    [
      'Go to the store and'
      [>]<<<-.<<<.<<<.>>.>.<<<.>>.<++++.---.<.>>-.+.>.<--.<.<.>----.>>-.<<+++.
      ' buy some more' comma space
      <.>--.>+++.++++.<<.>>------.>+.--.<<+++.<.>>>.++.<-.++<.-<<.>.<<<<-
      N = '9'
      N
      <<<+++++++++.>>>
    ]
    <+>
  ]

  c = c plus 2
  <++

  while(c)
  [
    N
    <<[<]>[.>]>>>
    ' bottle'
    >>>.>--.>>.<..->>.<<<+++.<<<<
    if(n minus 1) 's'
    -[>>>>>.[<]]<[>]>+
    ' of beer'
    >>>.>>>.<<+.<.>----.+++..->-.++

    [<<]<-
    if(c minus 1)
    [
      ' on the wall'
      >>>>>.>>>.-.+<<<.>>.<++++.---.<.>>+++.---<----.+++>>>..[<<]
    ]

    <<[>]>-
    if(c minus 2)
    [
      period newline
      >>>>++.--<.<<<+
      if(c minus 1) newline
      [>>>.<<<<]>[>]<-<
    ]>>
    else
    [
      comma space
      >>.>.<<<<
    ]

    if(not n) c = c minus 2
    >[<<++>]

    c = c minus 1
    <[>]<-
  ]

  c = 1
  >+>
]
\$\endgroup\$
11
\$\begingroup\$

Templates Considered Harmful, 667 bytes

Ap<Fun<Ap<Fun<Cat<Cat<Cat<Cat<Ap<A<1,1>,A<1>>,A<2,1>>,St<44,32>>,Ap<A<1,1>,A<1>>>,If<A<1>,Cat<Cat<Cat<Cat<St<46,10,84,97,107,101,32,111,110,101,32,100,111,119,110,32,97,110,100,32,112,97,115,115,32,105,116,32,97,114,111,117,110,100,44,32>,Ap<A<1,1>,Sub<A<1>,T>>>,A<2,1>>,St<46,10,10>>,Ap<A<0>,Sub<A<1>,T>>>,Cat<Cat<Cat<St<46,10,71,111,32,116,111,32,116,104,101,32,115,116,111,114,101,32,97,110,100,32,98,117,121,32,115,111,109,101,32,109,111,114,101,44,32>,Ap<A<1,1>,I<98>>>,A<2,1>>,St<46>>>>>,I<98>>>,Fun<Cat<Cat<Cat<Add<A<1>,T>,St<32,98,111,116,116,108,101>>,If<A<1>,St<'s'>,St<>>>,St<32,111,102,32,98,101,101,114>>>,St<32,111,110,32,116,104,101,32,119,97,108,108>>

Sort of expanded:

Ap<
    Fun<
        Ap<
            Fun<
                Cat<
                    Cat<Cat<Cat< Ap<A<1,1>,A<1>> , A<2,1> >, St<44,32> >, Ap<A<1,1>,A<1>> >,
                    If<A<1>,
                        Cat<Cat<Cat<Cat< St<46,10,84,97,107,101,32,111,110,101,32,100,111,119,110,32,97,110,100,32,112,97,115,115,32,105,116,32,97,114,111,117,110,100,44,32> , Ap<A<1,1>,Sub<A<1>,T>> >, A<2,1> >, St<46,10,10> >, Ap<A<0>,Sub<A<1>,T>> >,
                        Cat<Cat<Cat< St<46,10,71,111,32,116,111,32,116,104,101,32,115,116,111,114,101,32,97,110,100,32,98,117,121,32,115,111,109,101,32,109,111,114,101,44,32> , Ap<A<1,1>,I<98>> >, A<2,1> >, St<46> >
                    >
                >
            >,
            I<98>
        >
    >,
    Fun< Cat<Cat<Cat< Add<A<1>,T> , St<32,98,111,116,116,108,101> >, If<A<1>,St<'s'>,St<>>  >, St<32,111,102,32,98,101,101,114> > >,
    St<32,111,110,32,116,104,101,32,119,97,108,108>
>
\$\endgroup\$
0
11
\$\begingroup\$

Vim, 139 bytes

Saved 6 bytes due to xsot.

i, 99 bottles of beer on the wall.<ESC>YIGo to t<SO> store and buy some more<ESC>qa
3P2xgJX$12.+<CAN>YITake one down a<SO> pass it around<ESC>o<ESC>q98@adk?s
xn.n.ZZ

This is my first attempt at golfing Vim commands, although apparently it's quite popular. I've included the final ZZ in the byte count (write to file and exit) as it seems to be the accepted norm.

Side note: mission accomplished.


Explanation

Command                                    Effect
-------------------------------------------------------------------------------------------
i, 99 bottles of beer on the wall.<ESC>    insert text at cursor
Y                                          copy this line into buffer
IGo to t<SO> store and buy some more<ESC>  insert text at beginning of line
                                           auto-complete "the" (<Ctrl-N>, searches forward)
qa                                         begin recording macro into "a"
<LF>                                       move down one line (if present)
3P                                         paste 3 times before cursor
2x                                         delete 2 characters at cursor
gJ                                         join this line with next (without space between)
X                                          delete character before cursor
$                                          move to last non-whitespace character of line
12.                                        repeat the last edit command (X) 12 times
+                                          move to column 0 of next line
<CAN>                                      numeric decrement (<Ctrl-X>)
Y                                          copy this line into buffer
ITake one down a<SO> pass it around<ESC>   insert text at beginning of line
                                           auto-complete "and" (<Ctrl-N>, searches forward)
o<ESC>                                     insert text on new line
q                                          stop recording macro
98@a                                       repeat macro "a" 98 times
dk                                         delete upwards (this line and the one above it)
?s<LF>                                     move to previous /s/
x                                          delete character at cursor
n.n.                                       repeat last match and delete 2 times
ZZ                                         write to file and exit
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Slight improvement: i99 bottles of beer on the wall.<ESC>Yqa3P$r,J5wDr.+<CAN>YITake one down and pass it around, <ESC>o<ESCjq98@aiGo to the store and buy some more, <ESC>kdk?s<LF>xnxnxZZ \$\endgroup\$
    – xsot
    Commented Feb 23, 2016 at 3:29
  • \$\begingroup\$ @xsot thanks for that. I somehow completely overlooked / and ?. \$\endgroup\$
    – primo
    Commented Feb 23, 2016 at 6:06
  • \$\begingroup\$ btw it's possible to reach 153 on anagol with this improvement \$\endgroup\$
    – xsot
    Commented Feb 23, 2016 at 6:17
  • \$\begingroup\$ @xsot got it ;) \$\endgroup\$
    – primo
    Commented Feb 23, 2016 at 6:53
11
\$\begingroup\$

///, 341 bytes

/-/\/\///+/ bottle-)/\/&\/<\/
-(/\/\/?\/ ->/+s of beer-^/> on the wall-!/^,-$/>.
-@/$Take one down and pass it around,-#/^.
-*/?1@?0#<0!?0@-%/99!?9@?8#<8!?8@?7#<7!?7@?6#<6!?6@?5#<5!?5@?4#<4!?4@?3#<3!?3@?2#<2!?2@?1#<1!-&/?9#
%*-</
9(9/%*/</
8(8)7(7)6(6)5(5)4(4)3(3)2(2)1(1)0(0-
0/
- 0/ /#/1+s/1+/
% 01$Go to the store and buy some more, 099^.

It would need 99 years to write a proper explanation of this code.

I would probably just include the result of every stage...

Basically, this compresses the lyrics repeatedly (as is every answer in ///).

Try it online!

Each step of decompression

Since replacements followed by replacements will have the string //, it will appear often.

It appears often enough that I decided to compress // into -.

When this is decompressed, the result is as follows:

/+/ bottle//)/\/&\/<\/
//(/\/\/?\/ //>/+s of beer//^/> on the wall//!/^,//$/>.
//@/$Take one down and pass it around,//#/^.
//*/?1@?0#<0!?0@//%/99!?9@?8#<8!?8@?7#<7!?7@?6#<6!?6@?5#<5!?5@?4#<4!?4@?3#<3!?3@?2#<2!?2@?1#<1!//&/?9#
%*//</
9(9/%*/</
8(8)7(7)6(6)5(5)4(4)3(3)2(2)1(1)0(0//
0/
// 0/ /#/1+s/1+/
% 01$Go to the store and buy some more, 099^.

The string bottle only appeared three times, but I compressed it to + anyways:

/)/\/&\/<\/
//(/\/\/?\/ //>/ bottles of beer//^/> on the wall//!/^,//$/>.
//@/$Take one down and pass it around,//#/^.
//*/?1@?0#<0!?0@//%/99!?9@?8#<8!?8@?7#<7!?7@?6#<6!?6@?5#<5!?5@?4#<4!?4@?3#<3!?3@?2#<2!?2@?1#<1!//&/?9#
%*//</
9(9/%*/</
8(8)7(7)6(6)5(5)4(4)3(3)2(2)1(1)0(0//
0/
// 0/ /#/1 bottles/1 bottle/
% 01$Go to the store and buy some more, 099^.

Then, ) corresponds to /&/</ followed by a newline, and ( corresponds to //?/ , which are patterns that will be often used later:

/>/ bottles of beer//^/> on the wall//!/^,//$/>.
//@/$Take one down and pass it around,//#/^.
//*/?1@?0#<0!?0@//%/99!?9@?8#<8!?8@?7#<7!?7@?6#<6!?6@?5#<5!?5@?4#<4!?4@?3#<3!?3@?2#<2!?2@?1#<1!//&/?9#
%*//</
9//?/ 9/%*/</
8//?/ 8/&/</
7//?/ 7/&/</
6//?/ 6/&/</
5//?/ 5/&/</
4//?/ 4/&/</
3//?/ 3/&/</
2//?/ 2/&/</
1//?/ 1/&/</
0//?/ 0//
0/
// 0/ /#/1 bottles/1 bottle/
% 01$Go to the store and buy some more, 099^.

Now, we would decompress some useful strings:

  • > decompresses to bottles of beer
  • ^ decompresses to bottles of beer on the wall
  • ! decompresses to ^,, where ^ is the one above.
  • $ decompresses to >.\n, where > is the first rule and \n is a newline.
  • @ decompresses to $ followed by Take one down and pass it around,, where $ is the rule above.

The decompressed code now becomes:

/*/?1 bottles of beer.
Take one down and pass it around,?0 bottles of beer on the wall.
<0 bottles of beer on the wall,?0 bottles of beer.
Take one down and pass it around,//%/99 bottles of beer on the wall,?9 bottles of beer.
Take one down and pass it around,?8 bottles of beer on the wall.
<8 bottles of beer on the wall,?8 bottles of beer.
Take one down and pass it around,?7 bottles of beer on the wall.
<7 bottles of beer on the wall,?7 bottles of beer.
Take one down and pass it around,?6 bottles of beer on the wall.
<6 bottles of beer on the wall,?6 bottles of beer.
Take one down and pass it around,?5 bottles of beer on the wall.
<5 bottles of beer on the wall,?5 bottles of beer.
Take one down and pass it around,?4 bottles of beer on the wall.
<4 bottles of beer on the wall,?4 bottles of beer.
Take one down and pass it around,?3 bottles of beer on the wall.
<3 bottles of beer on the wall,?3 bottles of beer.
Take one down and pass it around,?2 bottles of beer on the wall.
<2 bottles of beer on the wall,?2 bottles of beer.
Take one down and pass it around,?1 bottles of beer on the wall.
<1 bottles of beer on the wall,//&/?9 bottles of beer on the wall.

%*//</
9//?/ 9/%*/</
8//?/ 8/&/</
7//?/ 7/&/</
6//?/ 6/&/</
5//?/ 5/&/</
4//?/ 4/&/</
3//?/ 3/&/</
2//?/ 2/&/</
1//?/ 1/&/</
0//?/ 0//
0/
// 0/ / bottles of beer on the wall.
/1 bottles/1 bottle/
% 01 bottles of beer.
Go to the store and buy some more, 099 bottles of beer on the wall.
\$\endgroup\$
1
11
\$\begingroup\$

Haskell, 228 223 bytes

o=" of beer on the wall"
a n=shows n" bottle"++['s'|n>1]
b 1="Go to the store and buy some more, "++a 99
b n="Take one down and pass it around, "++a(n-1)
f=[99,98..1]>>= \n->[a n,o,", ",a n," of beer.\n",b n,o,".\n\n"]>>=id

Function f returns a string with the lyrics.

\$\endgroup\$
9
\$\begingroup\$

Python 2, 194 bytes

i=198
while i:s=`i/2or 99`+' bottle%s of beer'%'s'[1<i<4:];print['%s, '+s+'.','Take one down and pass it around, %s.\n',"Go to the store and buy some more, %s."][i%2+1/i]%(s+' on the wall');i-=1

Try it online!

Took the i/2 idea from Sp3000's answer.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ You seem to have accidentally counted a trailing newline, this is 194 bytes \$\endgroup\$
    – emanresu A
    Commented Aug 23 at 11:24
9
\$\begingroup\$

Template Qdeql, 1132 1124  1122 bytes

o:2-O:9\D{o::= -=}I:119=t{a:256_e\a::D o::=a:o_1*/a::=}x:98-s{e:10
t }O::==-n{e:111 t }/i{e:32 t }c{e:116 t }q{a:e+1 a::=z:o_e_2\z::=
\e::=a:o+1\--a::=a:o+3-\/\/a::=a:o_e+1/a::= //o::=o:o+1}e:0 q
N:108=E{a:e+1 a::=a:o_1\a::= \-o::=a:o+1-\/\/a::=z:o_e_2/=/z::=}h{e:101
t }-L{a:o_1 a::= -}S:104=H{f:e+1 f::= -f:207 f::L f:o_e_2 f::=}y{E
q H a:e+1 a::=o:o_1*a:o_a a::=}g{e:0 y e:1 E q H a:o_1==-a::=a:o_3*o:o_1
a::=}g p:114 b{i e:x t n c t e:N t h }v:115 k{i n e:102 t i e:x
t h t e:p t }u{e:97 t }r{b e:v t k }r d{e:46 t }m{e:110 t }l{i
n m i c e:S t h i e:I t u e:N t t }l w{e:44 t }w i g r d s j:100
R:117 T{e:84 t u e:107 t h i n m h i e:j t n e:I t m i u m e:j
t i e:112 t u e:v t t i e:105 t c i u e:p t n e:R t m e:j t w
i }T A:49==-=\===\/\/\===\/\/g r l d s s g r l w i g r d s T
==-==/a:O+1=o:4\a::==-=e:1 E ===/=-==/-o:2=-=\==\/\/a:3\a::=
-a::= \-o::= -\/\/a::= /o::=a:1/a::=e:0 y r l d s s e:0 y r l
w i e:0 y r d s T =-o:1=-e:A=/t b k l d s s e:A t b k l w i e:A
t b k d s e:71 t n i c n i c e:S t h i e:v t c n e:p t h i u
m e:j t i e:x t e:R t e:121 t i e:v t n e:109 t h i e:109 t n
e:p t h w i e:57 t t r l d

Template Qdeql is a programming language that compiles to Qdeql. All function calls are resolved at compile time. Thus, while the source code is quite short, the compiled output isn't -- the resulting Qdeql is nearly half a megabyte!

This is particularly special to me because, to my knowledge, nobody has written a Qdeql program for 99 Bottles of Beer before today!

This is the same general approach as this example, with a few changes:

  • Punctuation changes, such as comma placement, to match the spec for this challenge
  • Declarations were reordered to minimize the amount of whitespace required
  • I entirely removed some functions like assertNEquals, and inlined functions that were only called once
  • The end was rewritten to have the "Go to the store and buy some more" line
  • A lot more specialized putchar functions than just newline

Identifiers were abbreviated automatically using this script, but whitespace was manually contracted.

Edits:

  • -8 for replacing some computations with direct assignment when the result is a known one-digit number
  • -2 in whitespace reduction by moving a couple variable assignments
\$\endgroup\$
8
\$\begingroup\$

JavaScript ES6, 237 217 208 203 195 193 189 186 bytes

It is getting pretty hard to golf this...
Edit 1: Somebody totally outgolfed me, looks like I have to try harder if I want to have the best Javascript answer.
Edit 2: I honestly can't believe that I managed to golf it that much!

for(i=99,Y=" on the wall",o=k=>k+(i||99)+` bottle${i==1?'':'s'} of beer`;i;)alert(o``+Y+o`, `+o(--i?`.
Take one down and pass it around, `:`.
Go to the store and buy some more, `)+Y+`.`)

Did I mess up somewhere? I also apologize for using alert, if you want to test my code, replace it with console.log.

Currently, there is one other notable Javascript answer: "99 Bottles of Beer". Check it out! :D

\$\endgroup\$
4
  • \$\begingroup\$ I would re-examine your conditions and you should be able to trim off a couple bytes. Good effort keeping up, though! \$\endgroup\$
    – Adam Dally
    Commented Nov 22, 2015 at 16:56
  • \$\begingroup\$ @AdamDally Ok!! :D But I don't like copying other people's stuff...(I would feel guilty if I just copied your code...though it would be "acceptable", if I found some improvements) :D \$\endgroup\$
    – Stefnotch
    Commented Nov 23, 2015 at 17:01
  • \$\begingroup\$ @AdamDally Yay, I messed around with my functions and I saved quite a bunch of bytes! (The crossed out line is getting longer and longer..) \$\endgroup\$
    – Stefnotch
    Commented Nov 23, 2015 at 18:06
  • \$\begingroup\$ Excellent! Unless there is some alternate path I've completely overlooked I feel like we are both nearing the end. \$\endgroup\$
    – Adam Dally
    Commented Nov 24, 2015 at 2:15
7
\$\begingroup\$

JavaScript ES6, 210 209 205 199 198 196 bytes

s=""
for(i=299;--i>1;s+=`${i/3|0||99} bottle${5/i^1?"s":""} of beer`+(i%3?" on the wall":i^3?`.
Take one down and pass it around`:`.
Go to the store and buy some more`)+(~i%3?", ":`.

`));alert(s)

This is a crude translation of my C submission. I don't actually know javascript so there is definitely room for improvement.

Edit: Neat, I discovered backticks

\$\endgroup\$
5
  • \$\begingroup\$ you could replace the console.log with alert and you could use ` instead of the ". Then you can replace \n with a newline. (The ticks are used for template strings, those strings can have newlines...) Also, congrats for beating me! \$\endgroup\$
    – Stefnotch
    Commented Nov 19, 2015 at 16:06
  • 1
    \$\begingroup\$ I think I'll leave the output alone unless someone else beats me as console.log is easier to test. Anyway, thanks for exposing me to backticks! \$\endgroup\$
    – xsot
    Commented Nov 19, 2015 at 16:14
  • \$\begingroup\$ Wohoo, outgolfed yours! Also, thanks for using || in your code, it sure came in handy... (Meh, you can change the console.log, and my victory will be reduced to nothing.. XD ) \$\endgroup\$
    – Stefnotch
    Commented Nov 19, 2015 at 16:37
  • 1
    \$\begingroup\$ You're proving challenging to keep up with! Alas, it would be interesting to see a breakdown of your code. \$\endgroup\$
    – Adam Dally
    Commented Nov 20, 2015 at 3:55
  • 1
    \$\begingroup\$ @AdamDally Basically, each verse is split into 3 parts with the following structure: %d bottle%s of beer%s%s. The index of each verse (number of bottles) is calculated as i/3|0 while the index of each substring is simply i%3. \$\endgroup\$
    – xsot
    Commented Nov 20, 2015 at 12:11
7
\$\begingroup\$

Brainfuck, 4028 bytes

This is quite hideous. Lots of duplication, and very inefficient, so it won't win any prizes. However, I started it, and was determined to finish it.

I may try and improve this, but probably wont, because frankly, my brain is fucked.

Golfed

>>+++[-<+++<+++>>]>>++++++[-<++++++++++<++++++++++>>]<---<--->>>+++++[-<++++++>]
<++>>++++++++++[-<++++++++++>]<-->>++++++++++[-<+++++++++++>]<+>>++++++++++[-<++
++++++++>]<+>>++++++++++[-<++++++++++>]<++>>++++++++++[-<+++++++++++>]<++++++>>+
+++++++++[-<++++++++++>]<++++>>++++++++++[-<+++++++++++>]<-->>++++++++++[-<+++++
++++++>]<++++>>++++++++++[-<+++++++++++>]<+++++>>++++++++++[-<+++++++++++>]>++++
++++++[-<+++++++++++>]<+++++++++>>++++++++++[-<++++++++++>]<--->>+++++[-<++++++>
]<++>>++++[-<++++++++++++>]<---->>++++[-<++++++++++++>]<-->++++++++++>>+++++++++
+[-<+++++++++++>]<--->>++++++++++[-<++++++++++>]>++++++++++[-<+++++++++++>]<++>>
++++++++++[-<++++++++++>]<+++++>>++++++++++[-<+++++++++++>]<+++++++<<<<<<<<<<<<<
<<<<<<<<<<<<[>[->.>.>.>.>.>>>..>>.<<<<.>>>>>>.<<<<<<<<<.>>.>>.<<<<.>.>>..>>>>>.<
<<<<<<<.>>.>>>>>>>>.>>>.<<<<<<<<.>.<<<.<<<.>>>>>>>>>>>.>.<<<<<..>>>>>>>.<.<<<<<<
<<<<<<<<<.>.->.>.>.>>>..>>.<<<<.>>>>>>.<<<<<<<<<.>>.>>.<<<<.>.>>..>>>>>.>>>>>>>.
>.<<<<<<<<<<<.>>>>>>>.>>>>>.<<<<<<<<<<<<<<.<<<.>>.>>>>>>>>.<<<<<<<.<<<.>>>>>>>>>
>>>>>>>>>.<<<<<<<<<<<<<<<<.>>>>>>>>>.<.>>>.<.<<.>>>>>>>>.<<<<<.>>>>>>.<<<<<<<.<<
<..>>>>.>>>>>>>.<<<<<<<<<<<<<<<.>>>>>>>>.<.<<<<.<<<<<<.>>>>>>>>>>>>>>>>>>>.<<<<<
<<<<<<.>>>>>>>>.<<<<.<.<<<<<<<<<<<<<<<.>.>.>.>.>>>..>>.<<<<.>>>>>>.<<<<<<<<<.>>.
>>.<<<<.>.>>..>>>>>.<<<<<<<<.>>.>>>>>>>>.>>>.<<<<<<<<.>.<<<.<<<.>>>>>>>>>>>.>.<<
<<<..>>>>>>>>.>..<<<<<<<<<<<<<<<<<<<]<->+++++++++>.>.>.>.>.>>>..>>.<<<<.>>>>>>.<
<<<<<<<<.>>.>>.<<<<.>.>>..>>>>>.<<<<<<<<.>>.>>>>>>>>.>>>.<<<<<<<<.>.<<<.<<<.>>>>
>>>>>>>.>.<<<<<..>>>>>>>.<.<<<<<<<<<<<<<<<.->.+++++++++>.>.>.>>>..>>.<<<<.>>>>>>
.<<<<<<<<<.>>.>>.<<<<.>.>>..>>>>>.>>>>>>>.>.<<<<<<<<<<<.>>>>>>>.>>>>>.<<<<<<<<<<
<<<<.<<<.>>.>>>>>>>>.<<<<<<<.<<<.>>>>>>>>>>>>>>>>>>.<<<<<<<<<<<<<<<<.>>>>>>>>>.<
.>>>.<.<<.>>>>>>>>.<<<<<.>>>>>>.<<<<<<<.<<<..>>>>.>>>>>>>.<<<<<<<<<<<<<<<.>>>>>>
>>.<.<<<<.<<<<<<.>>>>>>>>>>>>>>>>>>>.<<<<<<<<<<<.>>>>>>>>.<<<<.<.<<<<<<<<<<<<<<<
.>.>.>.>.>>>..>>.<<<<.>>>>>>.<<<<<<<<<.>>.>>.<<<<.>.>>..>>>>>.<<<<<<<<.>>.>>>>>>
>>.>>>.<<<<<<<<.>.<<<.<<<.>>>>>>>>>>>.>.<<<<<..>>>>>>>>.>..<<<<<<<<<<<<<<<<<<<<]
>--[->>.>.>.>.>>>..>>.<<<<.>>>>>>.<<<<<<<<<.>>.>>.<<<<.>.>>..>>>>>.<<<<<<<<.>>.>
>>>>>>>.>>>.<<<<<<<<.>.<<<.<<<.>>>>>>>>>>>.>.<<<<<..>>>>>>>.<.<<<<<<<<<<<<<<.->.
>.>.>>>..>>.<<<<.>>>>>>.<<<<<<<<<.>>.>>.<<<<.>.>>..>>>>>.>>>>>>>.>.<<<<<<<<<<<.>
>>>>>>.>>>>>.<<<<<<<<<<<<<<.<<<.>>.>>>>>>>>.<<<<<<<.<<<.>>>>>>>>>>>>>>>>>>.<<<<<
<<<<<<<<<<<.>>>>>>>>>.<.>>>.<.<<.>>>>>>>>.<<<<<.>>>>>>.<<<<<<<.<<<..>>>>.>>>>>>>
.<<<<<<<<<<<<<<<.>>>>>>>>.<.<<<<.<<<<<<.>>>>>>>>>>>>>>>>>>>.<<<<<<<<<<<.>>>>>>>>
.<<<<.<.<<<<<<<<<<<<<<.>.>.>.>>>..>>.<<<<.>>>>>>.<<<<<<<<<.>>.>>.<<<<.>.>>..>>>>
>.<<<<<<<<.>>.>>>>>>>>.>>>.<<<<<<<<.>.<<<.<<<.>>>>>>>>>>>.>.<<<<<..>>>>>>>>.>..<
<<<<<<<<<<<<<<<<<<]>>.>.>.>.>>>..>>.<<<<.>>>>>>.<<<<<<<<<.>>.>>.<<<<.>.>>..>>>>>
.<<<<<<<<.>>.>>>>>>>>.>>>.<<<<<<<<.>.<<<.<<<.>>>>>>>>>>>.>.<<<<<..>>>>>>>.<.<<<<
<<<<<<<<<<.->.>.>.>>>..>>.<<<<.>>>>>>.<<<<<<<<<.>>.>>.<<<<.>.>>..>>>>>.>>>>>>>.>
.<<<<<<<<<<<.>>>>>>>.>>>>>.<<<<<<<<<<<<<<.<<<.>>.>>>>>>>>.<<<<<<<.<<<.>>>>>>>>>>
>>>>>>>>.<<<<<<<<<<<<<<<<.>>>>>>>>>.<.>>>.<.<<.>>>>>>>>.<<<<<.>>>>>>.<<<<<<<.<<<
..>>>>.>>>>>>>.<<<<<<<<<<<<<<<.>>>>>>>>.<.<<<<.<<<<<<.>>>>>>>>>>>>>>>>>>>.<<<<<<
<<<<<.>>>>>>>>.<<<<.<.<<<<<<<<<<<<<<.>.>.>.>>>..>>.<<<<.<<<.>>.>>.<<<<.>.>>..>>>
>>.<<<<<<<<.>>.>>>>>>>>.>>>.<<<<<<<<.>.<<<.<<<.>>>>>>>>>>>.>.<<<<<..>>>>>>>>.>..
<<<<<<<<<<<<<<<<<.>.>.>.>>>..>>.<<<<.<<<.>>.>>.<<<<.>.>>..>>>>>.<<<<<<<<.>>.>>>>
>>>>.>>>.<<<<<<<<.>.<<<.<<<.>>>>>>>>>>>.>.<<<<<..>>>>>>>.<.<<<<<<<<<<<<<<.++++++
++>.>.>.>>>..>>.<<<<.<<<.>>.>>.<<<<.>.>>..>>>>>.>>>>>>>.>.>---->>+++++++++>++++<
<<.<<<<<<<<<<<<<<<.<<.>>>>>.<<<.<<.>>>>>.>.<<<.<<<.>>>>>>>>>.<<<<.<<<.>>>>>>.<<<
<<.<<<.>>>>>>>>>>>>.<<.>>>>>>>>.<<<<<.<<<<<<<<<<<<.>>>>>>>>>>>>>>>>>>>>.<<.<<<<<
<.<<<<.<<<<<<<.>>>>>>>>>>>>>>>>>>.<<<<<<<<<<<<<<<<<.>>>>>>>>>>.>>>>>>>.<<<<<<<<<
<<<<<<<<<.>>>>>>.<<<<<.>>>>>>>>>>>.<.<<<<<<<<<<<<<<..>.>.>.>>>..>>.<<<<.>>>>>>.<
<<<<<<<<.>>.>>.<<<<.>.>>..>>>>>.<<<<<<<<.>>.>>>>>>>>.>>>.<<<<<<<<.>.<<<.<<<.>>>>
>>>>>>>.>.<<<<<..>>>>>>>>.>.

Ungolfed

# SETUP COUNTERS
>>+++[-<+++<+++>>]
>>++++++[-<++++++++++<++++++++++>>]<---<--->>

# SETUP CONSTANTS
>+++++[-<++++++>]<++>
>++++++++++[-<++++++++++>]<-->        # B
>++++++++++[-<+++++++++++>]<+>        # O
>++++++++++[-<++++++++++>]<+>         # E
>++++++++++[-<++++++++++>]<++>        # F
>++++++++++[-<+++++++++++>]<++++++>   # T
>++++++++++[-<++++++++++>]<++++>      # H
>++++++++++[-<+++++++++++>]<-->       # L
>++++++++++[-<+++++++++++>]<++++>     # R
>++++++++++[-<+++++++++++>]<+++++>    # S
>++++++++++[-<+++++++++++>]           # N
>++++++++++[-<+++++++++++>]<+++++++++># W
>++++++++++[-<++++++++++>]<--->       # A
>+++++[-<++++++>]<++>                 # SPACE
>++++[-<++++++++++++>]<---->          # Comma
>++++[-<++++++++++++>]<-->            # Stop
++++++++++>                           # Newline
>++++++++++[-<+++++++++++>]<--->      # K
>++++++++++[-<++++++++++>]            # D
>++++++++++[-<+++++++++++>]<++>       # P
>++++++++++[-<++++++++++>]<+++++>     # I
>++++++++++[-<+++++++++++>]<+++++++   # U

# BACK TO START
<<<<<<<<<<<<<<<<<<<<<<<<<
[>
    [
        -> # Dec x0 counter
        .> # Print 0x char
        .> # Print x0 char
        .>
        .>.>>>..>>.<<<<.>>>>>>. # Bottles
        <<<<<<<<<.
        >>.>>.       # Of
        <<<<.
        >.>>..>>>>>. # Beer
        <<<<<<<<.
        >>.>>>>>>>>. # On
        >>>.
        <<<<<<<<.>.<<<. # The
        <<<.
        >>>>>>>>>>>.>.<<<<<.. # Wall
        >>>>>>>.     # Comma
        <.
        <<<<<<<<<<<<<<<.>.- # Counter with decrement
        >.
        >.>.>>>..>>.<<<<.>>>>>>. # Bottles
        <<<<<<<<<.
        >>.>>.       # Of
        <<<<.
        >.>>..>>>>>. # Beer
        >>>>>>>.     # Stop
        >.           # Newline
        <<<<<<<<<<<.>>>>>>>.>>>>>.<<<<<<<<<<<<<<. # Take
        <<<.
        >>.>>>>>>>>.<<<<<<<. # One
        <<<.
        >>>>>>>>>>>>>>>>>>.<<<<<<<<<<<<<<<<.>>>>>>>>>.<. # Down
        >>>. 
        <.<<.>>>>>>>>.  # And
        <<<<<.
        >>>>>>.<<<<<<<.<<<..    # Pass
        >>>>.
        >>>>>>>.<<<<<<<<<<<<<<<. # It
        >>>>>>>>.
        <.<<<<.<<<<<<.>>>>>>>>>>>>>>>>>>>.<<<<<<<<<<<.>>>>>>>>. # Around
        <<<<. # Comma
        <.
        <<<<<<<<<<<<<<<.>. # 0x and x0
        >.
        >.>.>>>..>>.<<<<.>>>>>>. # Bottles
        <<<<<<<<<.
        >>.>>.  # Of
        <<<<.
        >.>>..>>>>>. # Beer
        <<<<<<<<.
        >>.>>>>>>>>. # On
        >>>.
        <<<<<<<<.>.<<<. # The
        <<<.
        >>>>>>>>>>>.>.<<<<<.. # Wall
        >>>>>>>>.    # Stop
        >..   # Newline x2
        <<<<<<<<<<<<<<<<<<<      # Reset loop
    ]
    <-
    >+++++++++
    >.>.
    >.
    >.>.>>>..>>.<<<<.>>>>>>. # Bottles
    <<<<<<<<<.
    >>.>>.       # Of
    <<<<.
    >.>>..>>>>>. # Beer
    <<<<<<<<.
    >>.>>>>>>>>. # On
    >>>.
    <<<<<<<<.>.<<<. # The
    <<<.
    >>>>>>>>>>>.>.<<<<<.. # Wall
    >>>>>>>.     # Comma
    <.
    <<<<<<<<<<<<<<<.- # 0x with decrement
    >.+++++++++ # x0 with increment
    >.
    >.>.>>>..>>.<<<<.>>>>>>. # Bottles
    <<<<<<<<<.
    >>.>>.       # Of
    <<<<.
    >.>>..>>>>>. # Beer
    >>>>>>>.     # Stop
    >.           # Newline
    <<<<<<<<<<<.>>>>>>>.>>>>>.<<<<<<<<<<<<<<. # Take
    <<<.
    >>.>>>>>>>>.<<<<<<<. # One
    <<<.
    >>>>>>>>>>>>>>>>>>.<<<<<<<<<<<<<<<<.>>>>>>>>>.<. # Down
    >>>. 
    <.<<.>>>>>>>>.  # And
    <<<<<.
    >>>>>>.<<<<<<<.<<<..    # Pass
    >>>>.
    >>>>>>>.<<<<<<<<<<<<<<<. # It
    >>>>>>>>.
    <.<<<<.<<<<<<.>>>>>>>>>>>>>>>>>>>.<<<<<<<<<<<.>>>>>>>>. # Around
    <<<<. # Comma
    <.
    <<<<<<<<<<<<<<<.>. # Counter
    >.
    >.>.>>>..>>.<<<<.>>>>>>. # Bottles
    <<<<<<<<<.
    >>.>>.  # Of
    <<<<.
    >.>>..>>>>>. # Beer
    <<<<<<<<.
    >>.>>>>>>>>. # On
    >>>.
    <<<<<<<<.>.<<<. # The
    <<<.
    >>>>>>>>>>>.>.<<<<<.. # Wall
    >>>>>>>>.    # Stop
    >..   # Newline x2
    <<<<<<<<<<<<<<<<<<<<      # Reset outer loop
]
>-- # Decrement counter to only count from 7
# Last 8 loop
[
    -> # Dec counter
    >. # Print x0 char    
    >.
    >.>.>>>..>>.<<<<.>>>>>>. # Bottles
    <<<<<<<<<.
    >>.>>.       # Of
    <<<<.
    >.>>..>>>>>. # Beer
    <<<<<<<<.
    >>.>>>>>>>>. # On
    >>>.
    <<<<<<<<.>.<<<. # The
    <<<.
    >>>>>>>>>>>.>.<<<<<.. # Wall
    >>>>>>>.     # Comma
    <.
    <<<<<<<<<<<<<<.- # x with decrement
    >.
    >.>.>>>..>>.<<<<.>>>>>>. # Bottles
    <<<<<<<<<.
    >>.>>.       # Of
    <<<<.
    >.>>..>>>>>. # Beer
    >>>>>>>.     # Stop
    >.           # Newline
    <<<<<<<<<<<.>>>>>>>.>>>>>.<<<<<<<<<<<<<<. # Take
    <<<.
    >>.>>>>>>>>.<<<<<<<. # One
    <<<.
    >>>>>>>>>>>>>>>>>>.<<<<<<<<<<<<<<<<.>>>>>>>>>.<. # Down
    >>>. 
    <.<<.>>>>>>>>.  # And
    <<<<<.
    >>>>>>.<<<<<<<.<<<..    # Pass
    >>>>.
    >>>>>>>.<<<<<<<<<<<<<<<. # It
    >>>>>>>>.
    <.<<<<.<<<<<<.>>>>>>>>>>>>>>>>>>>.<<<<<<<<<<<.>>>>>>>>. # Around
    <<<<. # Comma
    <.
    <<<<<<<<<<<<<<. # Count
    >.
    >.>.>>>..>>.<<<<.>>>>>>. # Bottles
    <<<<<<<<<.
    >>.>>.  # Of
    <<<<.
    >.>>..>>>>>. # Beer
    <<<<<<<<.
    >>.>>>>>>>>. # On
    >>>.
    <<<<<<<<.>.<<<. # The
    <<<.
    >>>>>>>>>>>.>.<<<<<.. # Wall
    >>>>>>>>.    # Stop
    >..   # Newline x2
    <<<<<<<<<<<<<<<<<<<     # Reset loop
]
# Last but 1 exception
>>. # Counter
>.
>.>.>>>..>>.<<<<.>>>>>>. # Bottles
<<<<<<<<<.
>>.>>.       # Of
<<<<.
>.>>..>>>>>. # Beer
<<<<<<<<.
>>.>>>>>>>>. # On
>>>.
<<<<<<<<.>.<<<. # The
<<<.
>>>>>>>>>>>.>.<<<<<.. # Wall
>>>>>>>.     # Comma
<.
<<<<<<<<<<<<<<.- # x with decrement
>.
>.>.>>>..>>.<<<<.>>>>>>. # Bottles
<<<<<<<<<.
>>.>>.       # Of
<<<<.
>.>>..>>>>>. # Beer
>>>>>>>.     # Stop
>.           # Newline
<<<<<<<<<<<.>>>>>>>.>>>>>.<<<<<<<<<<<<<<. # Take
<<<.
>>.>>>>>>>>.<<<<<<<. # One
<<<.
>>>>>>>>>>>>>>>>>>.<<<<<<<<<<<<<<<<.>>>>>>>>>.<. # Down
>>>. 
<.<<.>>>>>>>>.  # And
<<<<<.
>>>>>>.<<<<<<<.<<<..    # Pass
>>>>.
>>>>>>>.<<<<<<<<<<<<<<<. # It
>>>>>>>>.
<.<<<<.<<<<<<.>>>>>>>>>>>>>>>>>>>.<<<<<<<<<<<.>>>>>>>>. # Around
<<<<. # Comma
<.
<<<<<<<<<<<<<<. # Count
>.
>.>.>>>..>>.<<<<. # Bottle
<<<.
>>.>>.  # Of
<<<<.
>.>>..>>>>>. # Beer
<<<<<<<<.
>>.>>>>>>>>. # On
>>>.
<<<<<<<<.>.<<<. # The
<<<.
>>>>>>>>>>>.>.<<<<<.. # Wall
>>>>>>>>.    # Stop
>..   # Newline x2
# Last 1 exception
<<<<<<<<<<<<<<<<<. # Counter
>.
>.>.>>>..>>.<<<<. # Bottle
<<<.
>>.>>.       # Of
<<<<.
>.>>..>>>>>. # Beer
<<<<<<<<.
>>.>>>>>>>>. # On
>>>.
<<<<<<<<.>.<<<. # The
<<<.
>>>>>>>>>>>.>.<<<<<.. # Wall
>>>>>>>.     # Comma
<.
<<<<<<<<<<<<<<.++++++++ # x with reset to 99
>.
>.>.>>>..>>.<<<<. # Bottle
<<<.
>>.>>.       # Of
<<<<.
>.>>..>>>>>. # Beer
>>>>>>>.     # Stop
>.           # Newline
>----        # Change K to G
>>+++++++++  # Change P to Y
>++++        # Change I to M
<<<.<<<<<<<<<<<<<<<. # Go
<<.
>>>>>.<<<.           # To
<<.
>>>>>.>.<<<.         # The
<<<.
>>>>>>>>>.<<<<.<<<.>>>>>>.<<<<<. # Store
<<<.
>>>>>>>>>>>>.<<.>>>>>>>>.       # And
<<<<<.
<<<<<<<<<<<<.>>>>>>>>>>>>>>>>>>>>.<<. # Buy
<<<<<<.
<<<<.<<<<<<<.>>>>>>>>>>>>>>>>>>.<<<<<<<<<<<<<<<<<. # Some
>>>>>>>>>>.
>>>>>>>.<<<<<<<<<<<<<<<<<<.>>>>>>.<<<<<. # More
>>>>>>>>>>>.
<.
<<<<<<<<<<<<<<..  # 99
>.
>.>.>>>..>>.<<<<.>>>>>>. # Bottles
<<<<<<<<<.
>>.>>.  # Of
<<<<.
>.>>..>>>>>. # Beer
<<<<<<<<.
>>.>>>>>>>>. # On
>>>.
<<<<<<<<.>.<<<. # The
<<<.
>>>>>>>>>>>.>.<<<<<.. # Wall
>>>>>>>>.    # Stop
>.   # Newline x2

Output:

Try it yourself here!
OK, so it seems the URL is too long to include here, so you will need to copy/paste to try it yourself.

I tested it using this interpreter.

\$\endgroup\$
6
\$\begingroup\$

Labyrinth, 1195 1190 932 bytes

"{"9"
^ }
 ""
 <
 713.101.801..:611.111.89.23}!:({.23.44.001.011.711.111.411.79.23.611.501.23..:511.79.211.23.001.011.79.23.011.911.111.001.23.101.(.:111.23.101.701.79.48\.411..:101.89.23.201.111.23.511.101.801..:611.111.89.23}!:{.23.44..:801.79.911.23.101.401.611.23.(.:111.23.411..:101.89.23.201.111.23.511.101.801..:611.111.89.23}!:{
 _
 3`<
 _ ( 
""""
"
{(32.111.102.32.98.101:..114.32.111:.(.32.116.104.101.32.119.97.108:..46.\\49.32.98.111.116:..108.101.32.111.102.32.98.101:..114.32.111:.(.32.116.104.101.32.119.97.108:..44.32.49.32.98.111.116:..108.101.32.111.102.32.98.101:..114.46.\71.111.32.116.111.32.116.104.101.32.115:.).111.114.101.32.97.110.100.32.98.117.121.32.115.111.109.101.32.109.111.114.101.44.32.9!9!32.98.111.116:..108.101.115.32.111.102.32.98.101:..114.32.111:.(.32.116.104.101.32.119.97.108:..46.@
 )
 }
 <
 87\\.64..:801.79.911.23.101.401.611.23.(.:111.23.411..:101.89.23.201.111.23.511
 _
 3`<
 _ ( 
v"""

This is a bit excessive...

While Labyrinth isn't particularly good at printing strings (because you need to push all the character codes), I think it should be possible to do better than this by using more but shorter long lines and getting even crazier with the grid rotation.

As I think any golfing improvements will substantially change the structure of this code, I'll wait with an explanation until I'm out of ideas how to golf it further.

\$\endgroup\$
0
6
\$\begingroup\$

Julia, 227 215 213 bytes

w=" on the wall"
b=" bottles"
o=" of beer"
k=b*o
for n=99:-1:1
println("$n$k$w, $n$k.
$(n>1?"Take one down and pass it around":"Go to the store and buy some more"), $(n>1?"$(n-1)$(k=b*"\b"^(n<3)*o)":"99$b"o)$w.
")end

This uses string interpolation ("$variable") and ternaries to construct the output and print it to STDOUT.

Saved 14 bytes thanks to Glen O!

\$\endgroup\$
9
  • 1
    \$\begingroup\$ Rather than (n>1?" bottles":" bottle")" of beer", use " bottle""s"^(n>1)*" of beer" - note that the * is necessary after (n<1) because otherwise it tries to apply (n>1)" of beer" as the power. Also, is there any benefit to using while n>0 over for n=99:-1:1 (which allows the condition at the end to be simpler, and avoids the separate need for n=99)? \$\endgroup\$
    – Glen O
    Commented Nov 18, 2015 at 18:07
  • \$\begingroup\$ Also use actual newlines in place of \n and switch the middle part to interpolation (rather than ",n>1?...",", use $(n>1?...")) to save a character, and move the , inside the conditional to before the next part, so it only needs to be written once. \$\endgroup\$
    – Glen O
    Commented Nov 18, 2015 at 18:21
  • \$\begingroup\$ Actually, strike the suggestion of while over for - I just realised that you'd have to subtract one when doing the last number in each verse, so there's no net benefit. \$\endgroup\$
    – Glen O
    Commented Nov 18, 2015 at 18:27
  • \$\begingroup\$ @GlenO Thanks as always for the great suggestions! \$\endgroup\$
    – Alex A.
    Commented Nov 18, 2015 at 22:18
  • 1
    \$\begingroup\$ I was hoping to be able to just suggest a change - it's a bit silly that it doesn't permit that option if you've got enough rep to make an edit without the original answerer's acceptance. I do apologise if I did in any way step on toes for doing it. I just moved the evaluation of the "bottle<s> of beer" part to the end, so it only needs to be done once, and initialised it. I also used a backspace instead of a conditional "s" to save a bit. \$\endgroup\$
    – Glen O
    Commented Nov 19, 2015 at 6:36
6
\$\begingroup\$

Windows Batch, 376 bytes

Very very long and ugly:

@echo off
setlocal enabledelayedexpansion
set B=bottles
set C=on the wall
set D=of beer
for /l %%* in (99,-1,1) do (
set A=%%*
if !A! EQU 1 set B=bottle
echo !A! !B! !D! !C!, !A! !B! !D!.
set /a A=!A!-1
if !A! EQU 1 set B=bottle
if !A! EQU 0 (
echo Go to the store and buy some more, 99 bottles !D! !C!.
) else (
echo Take one down and pass it around, !A! !B! !D! !C!.
echo.
))
\$\endgroup\$
0
6
\$\begingroup\$

GolfScript, 143 bytes

[99.{[', '\.' bottle''s of beer'@(:i!>' on the wall''.
'n].1>~;5$4<\'Take one down and pass it around'i}**'Go to the store and buy some more'](

May still be room for improvement. Getting close to the final revision, I think.

\$\endgroup\$
1
6
\$\begingroup\$

Bash, 167 bytes

Saved 2 bytes due to Sisyphus.

eval a={1..99}'" bottle$s of beer"
b="$a on the wall";f=$b,\ $a.$o;o="
Take one down and pass it around, $b.

$f";s=s';echo "$f
Go to the store and buy some more, $b."

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ 'a="' can become a=\" for a byte saved. \$\endgroup\$
    – Sisyphus
    Commented Jan 8, 2022 at 10:45
  • 1
    \$\begingroup\$ Actually, even better you can just replace the whole construction with eval a={1..99}'" bottle$s of beer" \$\endgroup\$
    – Sisyphus
    Commented Jan 8, 2022 at 10:48
5
\$\begingroup\$

Python, 254 bytes

b,o,s,t="bottles of beer","on the wall","bottle of beer",".\nTake one down and pass it around,"
i=99;exec'print i,b,o+",",i,b+t,i-1,b,o+".\\n";i-=1;'*97
print"2",b,o+", 2",b+t+" 1",s,o+".\n\n1",s,o+", 1",s+".\nGo to the store, buy some more, 99",b,o+"."

Pretty straightforward, assign some of the most common phrases, print each bit from 99 to 3, then print the last lines by adding together the variables and some strings.

\$\endgroup\$
0
5
\$\begingroup\$

Python 2, 204 bytes

n=198
while n:s="bottle%s of beer"%"s"[:n^2>1];print n%2*"GToa kteo  otnhee  dsotwonr ea nadn dp absusy  isto maer omuonrde,,  "[n>1::2]+`n/2or 99`,s,"on the wall"+[", %d %s."%(n/2,s),".\n"[:n]][n%2];n-=1

The spec is quite underspecified in terms of whitespace, so here I'm assuming that the last line needs to have a single trailing newline. If the spec clarifies otherwise I'll update this answer.

I'm pretty happy with this, but looking at anarchy golf I feel like this can be golfed still, possibly with a different approach.

\$\endgroup\$
0
5
\$\begingroup\$

JavaScript ES6, 214 bytes

Edit: Deleted all previous code, view edits if you want to see the older code.

Limited popups:

p='.';o=" of beer";e=o+" on the wall";i=99;u=m=>i+" bottle"+(i==1?'':'s');while(i>0){alert(u()+e+", "+u()+o+p+(--i>0?"Take one down and pass it around, "+u()+e:"Go to the store and buy some more, 99 bottles"+e)+p)}

Expanded:

p='.';
o=" of beer";
e=o+" on the wall";
i=99;
u=m=>i+" bottle"+(i==1?'':'s');
while(i>0){
    alert(u()+e+", "+u()+o+p+(--i>0?"Take one down and pass it around, "+u()+e:"Go to the store and buy some more, 99 bottles"+e)+p)
}

@commenters: Thanks for the idea of arrow functions, saved 15 bytes

For infinite beer just use this code here, 212 bytes

p='.';o=" of beer";e=o+" on the wall";i=99;u=m=>i+" bottle"+(i==1?'':'s');while(i>0){alert(u()+e+", "+u()+o+p+(--i>0?"Take one down and pass it around, "+u()+e:"Go to the store and buy some more, "+u(i=99)+e)+p)}
\$\endgroup\$
4
  • 1
    \$\begingroup\$ I can't get the code to run, what browser/environment are you using? "SyntaxError: missing ; before statement" Also, have a look at arrow functions! \$\endgroup\$
    – Stefnotch
    Commented Nov 18, 2015 at 19:03
  • \$\begingroup\$ Took me a moment to find the syntax error +o' as it were then changed to +o+'. Also saw opportunity for changing the loop and answer. Will be checking out arrow functions now :) \$\endgroup\$
    – ŽaMan
    Commented Nov 18, 2015 at 19:45
  • 1
    \$\begingroup\$ 232 bytes for the last solution: b=a=>a+" bottle"+(1<a?"s":"");for(i=100;100>--i;)l="\n",p="."+l,o=" of beer",e=o+" on the wall",alert(l+b(i)+e+", "+b(i)+o+p+(1<i?"Take one down and pass it around, "+b(i-1)+e:"Go to the store and buy some more, "+b((i=100)-1)+e)+p) \$\endgroup\$ Commented Nov 18, 2015 at 22:48
  • \$\begingroup\$ After some playing around, I'm sticking to my while loop and I'll soon now post the resulting code. Thank you for the code review! :) \$\endgroup\$
    – ŽaMan
    Commented Nov 19, 2015 at 4:21
5
\$\begingroup\$

CJam, 149 148 146 144 138 137 134 bytes

00000000: 39 39 7b 5b 22 2c 2e 22 22 01 bd 8f 2d b4 49 b5 f5  99{[",.""...-.I..
00000011: 9d bd 21 e8 f2 72 27 df 4d 4f 22 7b 32 36 39 62 32  ..!..r'.MO"{269b2
00000022: 35 62 27 61 66 2b 27 6a 53 65 72 28 65 75 5c 2b 2a  5b'af+'jSer(eu\+*
00000033: 7d 3a 44 7e 4e 4e 32 24 32 3e 29 34 24 4a 3c 5c 4e  }:D~NN2$2>)4$J<\N
00000044: 5d 73 27 78 2f 39 39 40 2d 73 2a 7d 2f 27 73 2d 5d  ]s'x/99@-s*}/'s-]
00000055: 22 07 9c 4b a2 4e 15 d7 df d5 82 88 c9 d9 a7 ad 37  "..K.N..........7
00000066: 16 7e 76 22 44 33 35 2f 28 5d 22 41 90 1d b1 f3 69  .~v"D35/(]"A....i
00000077: ba 3d 05 45 81 50 af 07 e4 1b 38 f7 19 22 44        .=.E.P....8.."D

The above hexdump can be reversed with xxd -r. Try it online in the CJam interpreter.

At the cost of 9 extra bytes, for a total of 143 bytes, we can avoid unprintable characters:

99{[", X bottles of beer on the wall."NN2$2>)4$J<\N]s'X/99@-s*}/'s-]"Take one down and pass it around"*35/("Go to the store and buy some more"\

How it works

99{         e# For each I in [0 ... 98]:
  [         e# 
    ",."    e#     Push that string.
    "…"     e#     Push a string.
    {       e#     Define a decoder function:
      269b  e#       Convert the string from base 269 to integer.
      25b   e#       Convert from integer to base 25.
      'af+  e#       Add 'a' to each base-25 digit.
      'jSer e#       Replace j's with spaces.
      (     e#       Shift the first character from the resulting string.
      eu    e#       Convert it to uppercase.
      \+    e#       Prepend it to the remaining string.
      *     e#       Join the string/array on the stack, using the 
            e#       generated string as delimiter.
    }:D~    e#     Name the function D and execute it.
            e#     This pushes ", x bottles of beer on the wall.".
    NN      e#     Push two linefeeds.
    2$      e#     Push a copy of the generated string.
    2>)     e#     Discard the first two characters and pop the dot.
    4$      e#     Push another copy of the generated string.
    J<      e#     Discard all but the first 19 characters.
            e#     This pushes ", x bottles of beer on the wall".
    \N      e#     Swap the string with the dot and push a linefeed.
  ]s        e#   Collect in an array and cast to string.
  'x/       e#   Split at occurrences of 'x'.
  99@-      e#   Rotate I on top of 99 and compute their difference.
  s*        e#   Cast to string and and join.
            e#   This replaces x's with 99-I.
}/          e#
's-         e# Remove all occurrences of 's' for the last generated string.
]           e# Wrap the entire stack in an array.
"…"D        e# Join the array with separator "Take one down and pass it around".
35/(        e# Split into chunks of length 35 and shift out the first.
            e# This shifts out ", 99 bottles of beer on the wall.\n\n".
]           e# Wrap the modified array and shifted out chunk in an array.
"…"D        e# Join the array with separator "Go to the store and buy some more".
\$\endgroup\$
4
  • \$\begingroup\$ Base 259? Interesting. \$\endgroup\$
    – lirtosiast
    Commented Nov 22, 2015 at 21:42
  • \$\begingroup\$ Base 256 had carriage returns, which do not work with the online interpreter. Luckily, base 259 produces no characters outside the ISO 8559-1 range. \$\endgroup\$
    – Dennis
    Commented Nov 22, 2015 at 21:44
  • \$\begingroup\$ I assumed CJam would be at least 2 bytes shorter than GolfScript - almost trivially. Wasn't expecting 137 though! \$\endgroup\$
    – primo
    Commented Nov 23, 2015 at 5:00
  • 1
    \$\begingroup\$ @primo To be fair, most of the savings are from base conversion. Sadly, using base twice already adds 8 bytes in GolfScript... \$\endgroup\$
    – Dennis
    Commented Nov 23, 2015 at 5:30
5
\$\begingroup\$

C, 303 299 297 bytes

#define B"%d bottle%s of beer"    
#define O" on the wall"
#define P printf(
#define V(n,m,S)q(n);P O);P", ");q(n);P S);q(m);P".\n");
*s[]={"","s"};q(n){P B,n,s[n>1]);}main(){for(int i=99;--i;){V(i+1,i,".\nTake one down and pass it around, ")P"\n");}V(1,99,".\nGo to the store and buy some more, ");}

Compile with gcc -std=c99 -w.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Golf down to 300 bytes: ...for(int i=99;--i;){V(i+1,i,".... \$\endgroup\$ Commented Nov 21, 2015 at 21:51
  • \$\begingroup\$ @GlennRanders-Pehrson Thanks. I also removed the linebreak before main(). \$\endgroup\$ Commented Nov 23, 2015 at 9:00
5
\$\begingroup\$

Mathematica, 238 226 222 224 bytes

Saved several bytes thanks to Martin Büttner.

a={ToString@#," bottle",If[#<2,"","s"]," of beer"}&;b=a@#<>" on the wall"&;Echo[{b@n,", ",a@n,".
"}<>If[n<2,"Go to the store and buy some more, "<>b@99<>".","Take one down and pass it around, "<>b[n-1]<>".
"]]~Do~{n,99,1,-1}
\$\endgroup\$
0
5
\$\begingroup\$

x86 MS-DOS .COM file, 176 bytes

Advantages:

  • bitwise manipulation allows efficient encoding (However, in the end I settled on a relatively unpacked encoding which is pretty readable, just using the 8th bit of each byte to store spaces. I tried denser encodings that got the data to under 70 bytes, but the program size went up just as much.)
  • .COM files are widely supported from MS-DOS 1 through the present (I'm running in dosemu, sticking with 8086 commands only)

Disadvantages:

  • conditional jumps can get real obfuscated real quickly
  • some simple tasks are hard; it takes ~20 bytes to print the number of bottles

Hex dump (pass this into xxd -r to regenerate the 176-byte file):

0100: be a8 01 bd 63 00 40 75 06 4d 74 f7 be a4 01 8a  [email protected].....
0110: 0c 46 8a 1c 46 80 fb 89 75 18 89 e8 b7 0a f6 f7  .F..F...u.......
0120: b7 01 05 30 30 3c 30 92 b4 02 74 02 cd 21 88 f2  ...00<0...t..!..
0130: cd 21 38 2f 79 04 b2 20 cd 21 b2 7f 22 17 4d 75  .!8/y.. .!..".Mu
0140: 05 80 fb 8f 74 02 cd 21 45 43 e2 c9 81 fe ae 01  ....t..!EC......
0150: 76 b5 c3 54 61 6b 65 ef 6e 65 e4 6f 77 6e e1 6e  v..Take.ne.own.n
0160: 64 f0 61 73 73 e9 74 e1 72 6f 75 6e 64 47 6f f4  d.ass.t.roundGo.
0170: 6f f4 68 65 f3 74 6f 72 65 e1 6e 64 e2 75 79 f3  o.he.tore.nd.uy.
0180: 6f 6d 65 ed 6f 72 65 2c 20 e2 6f 74 74 6c 65 73  ome.ore, .ottles
0190: ef 66 e2 65 65 72 ef 6e f4 68 65 f7 61 6c 6c 2e  .f.eer.n.he.all.
01a0: 0d 0a 0d 0a 1a 53 1d 87 16 89 0f 87 03 9f 33 6d  .....S........3m

Explanations:

Bytes 0100 through 0152 (83 bytes) are commands, unassembled using debug:

0100 BEA801   MOV SI,01A8     ; point to 3rd substring
0103 BD6300   MOV BP,0063     ; begin with 99 bottles
0106 40       INC AX          ; only used to unset zero flag after last bottle taken
0107 7506     JNZ 010F        ; {when referred from 0150...if finished 5th substring:
0109 4D       DEC BP          ;    take down a bottle
010A 74F7     JZ 0103         ;    took last bottle, reset 99 bottles (and proceed to 6th)
010C BEA401   MOV SI,01A4     ;    or if not last bottle, point to 1st substring}
010F 8A0C     MOV CL,[SI]     ; load counter for substring
0111 46       INC SI
0112 8A1C     MOV BL,[SI]     ; load start pointer for substring
0114 46       INC SI
0115 80FB89   CMP BL,89       ; {  {check location to print # of bottles,
0118 7518     JNZ 0132        ;        if so...
011A 89E8     MOV AX,BP
011C B70A     MOV BH,0A
011E F6F7     DIV BH          ;        divide by 10
0120 B701     MOV BH,01       ;  (leave BH=1 for rest of program so [BX] points correctly)
0122 053030   ADD AX,3030     ;        convert to ascii numerals    
0125 3C30     CMP AL,30       ;        {if tens digit > 0,
0127 92       XCHG AX,DX
0128 B402     MOV AH,02       ;  (leave AH=2 for rest of program to print to stdout)
012A 7402     JZ 012E         
012C CD21     INT 21          ;           print tens digit}
012E 88F2     MOV DL,DH
0130 CD21     INT 21          ;        print ones digit}
0132 382F     CMP [BX],CH     ;    {check if character's 8th bit is set
0134 7904     JNS 013A        ;       if so...
0136 B220     MOV DL,20
0138 CD21     INT 21          ;       print " "}
013A B27F     MOV DL,7F
013C 2217     AND DL,[BX]     ;    load character without 8th bit
013E 4D       DEC BP          ;    {temporarily check if --bottle count = 0
013F 7505     JNZ 0146
0141 80FB8F   CMP BL,8F       ;       if so, check if at location of "s" to skip
0144 7402     JZ 0148
0146 CD21     INT 21          ;       print (unless skipping "s")
0148 45       INC BP          ;       undo temporary check}
0149 43       INC BX
014A E2C9     LOOP 0115       ;    proceed to next encoded character of substring}

014C 81FEAE01 CMP SI,01AE     ; check if we just finished the 5th of the 6 substrings
0150 76B5     JBE 0107        ; if the 5th or less, triage further at line 0107
0152 C3       RET             ; end after finishing 6th substring

Bytes 0153 through 01a3 (81 bytes) are the pretty readable encoded text

Bytes 01a4 through 01af (12 bytes) are (length,start) pairs pointing to substrings
    "Take...around"
    ", #bottles...wall.CRLFCRLF"
    "#bottles...wall"
    ", #bottles...beer"
    ".CRLF"
    "Go...wall.CRLF"
\$\endgroup\$
1
2 3 4 5
7

Not the answer you're looking for? Browse other questions tagged or ask your own question.