91
\$\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
  • 15
    \$\begingroup\$ Whoever closevoted this, the other one is a popularity contest... \$\endgroup\$
    – TheDoctor
    Nov 18 '15 at 15:19
  • 24
    \$\begingroup\$ This is a subtask of the Create an HQ9+ Interpreter golf. \$\endgroup\$
    – Geobits
    Nov 18 '15 at 15:25
  • 13
    \$\begingroup\$ Note that quartata had already sandboxed a 99BB catalog several weeks ago and was planning to post it. \$\endgroup\$
    – Alex A.
    Nov 18 '15 at 17:07
  • 14
    \$\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
    Nov 18 '15 at 18:42
  • 6
    \$\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
    Oct 22 '18 at 4:05

164 Answers 164

1
\$\begingroup\$

Unix TMG, 231 byte

o:parse(v)[n<143?]\o;v:b l b={3< on the wall, >3<.>*2 1< on the wall.>**};b:decimal(n)([n>1?]={<s>}|={})={2< bottle>1< of beer>};l:[--n?]={<Take one down and pass it around, >}|[n=143]={<Go to the store and buy some more, >};n:143;

Expanded:

o: parse(v) [n<143?]\o;
v: b l b = {3 < on the wall, > 3 <.> * 2 1 < on the wall.> * * };
b: decimal(n) ([n>1?]={<s>}|={}) = {2 < bottle> 1 < of beer>};
l: [--n?] = {<Take one down and pass it around, >}
 | [n=143] = {<Go to the store and buy some more, >};
n: 143;

The fact that this 1972 language uses octal instead of decimal doesn't help in this challenge 😂

\$\endgroup\$
3
  • 1
    \$\begingroup\$ If it can't be written without the newlines then the newlines should be counted. \$\endgroup\$
    – S.S. Anne
    Feb 2 '20 at 22:21
  • \$\begingroup\$ This seems to be 235 bytes, not 231 \$\endgroup\$
    – Jo King
    Feb 3 '20 at 1:30
  • \$\begingroup\$ @JoKing, deleted the newlines. Thanks, it works without them. \$\endgroup\$ Feb 3 '20 at 3:57
1
\$\begingroup\$

Python, 357 339 310 bytes

After shaving off the fat to meet the expected output it didn't save as many bytes as I had expected:

def B(n):A='bottle';return A if n==1 else A+'s'
A=99
while A>=1:F='of';D=F+' beer';E='more';C=D+' on the wall';G='no '+E;H=f"Take one down and pass it around, {A-1 if A>1 else G} {B(A-1)} {C}\n"if A!=1 else f"Go to the store and buy some {E}, 99 {B(2)} {C}.";print(f"{A} {B(A)} {C}, {A} {B(A)} {D}.\n"+H);A=A-1

The following code is for code-golf output:

This is the lowest I can hit so far

def B(n):A='bottle';return A if n==1 else A+'s'
A=99
while A>=0:G='of';D=G+' beer';E='more';C=D+' on the wall';F='no '+E;print(f"{A} {B(A)} {C}, {A} {B(A)} {D}.\nTake one down and pass it around, {A-1 if A>1 else F} {B(A-1)} {C}.\n"if A!=0 else f"No {E} {B(2)} {C}, {F} {B(2)} {D}.\nGo to the store and buy some {E}, 99 {B(2)} {C}.");A=A-1

Here's the sort of bigger version:

def get_bottles(num_bottle):
    p = "bottle"

    return p if num_bottle == 1 else p + "s"


bottleNo = 99

while bottleNo >= 0:
    of = "of"
    beer = of + " beer"
    more = "more"
    botw = beer + " on the wall"
    noMore = "no " + more

    print(f"{bottleNo} {get_bottles(bottleNo)} {botw}, {bottleNo} {get_bottles(bottleNo)} {beer}.\nTake one down and "
          f"pass it around, {bottleNo - 1 if bottleNo > 1 else noMore} {get_bottles(bottleNo - 1)} {botw}.\n" if
          bottleNo != 0
          else f"No {more} {get_bottles(2)} {botw}, {noMore} {get_bottles(2)} {beer}.\nGo to the store "
               f"and buy some {more}, 99 {get_bottles(2)} {botw}.")

    bottleNo = bottleNo - 1
\$\endgroup\$
2
  • 1
    \$\begingroup\$ You went through the trouble of making all your variables into one character, but forgot num_bottle. If you do that there as well, you could shave off a few bytes \$\endgroup\$
    – GamrCorps
    May 31 '20 at 14:21
  • \$\begingroup\$ Good catch, that saved me 18 chars. Thanks! \$\endgroup\$
    – SZT
    May 31 '20 at 14:26
1
\$\begingroup\$

C#, 205 bytes

()=>{for(int i=299;i-->2;)System.Console.Write(@$"{i/3:0;;99} bottl{i/3^1:es;;e} of beer{i%3-3/i: on the wall;\.
Go to the store and buy some more;\.
Take one down and pass it around}{~i%3:;\, ;\.

;}");};

Try it online!

As an anonymous lambda. A full program scores 227.

Putting custom numeric formats to good use. I'm particularly satisfied with i%3-3/i to select between Take one down, Go to the store, and on the wall.

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

Plain TeX (237 characters)

\input tikz\let~\def~\1#1{ bottle#1 of beer}~\7{~ on the wall}~\9#1#2{\def~{ #1\1#2}Take one down and pass it around,\7.\bigskip\par\7,~.\par}~~{ 99\1s}\7,~.\par\foreach\2in{98,...,2}{\9\2s}{\91 }Go to the store and buy some more,\7.\bye

Try the Code on Overleaf


Any Comments Appreciated

Please help me golf this code to an unhealthy extent.

\$\endgroup\$
1
  • \$\begingroup\$ @AdHocGarfHunter Would you want to accept a challenge? Do you want to find out whether you can minify this further down? \$\endgroup\$
    – Joe85AC
    Jun 5 '20 at 14:53
1
\$\begingroup\$

AWK, 198 bytes

a=100{d=" on the wall";e=" of beer";for(f=" bottle";a--;$0=g)g=g (a?(c=a f (a-1?"s":b)e)d", "c".\nTake one down and pass it around, "c d".\n\n":"Go to the store and buy some more, 99"f"s"e d".\n")}1

Try it online!

I didn't see AWK on the last yet, so here's one example.

This code will print the whole "99 bottles..." dialogue for every line of input fed into the code. I'm not sure how best to break this apart, but maybe this helps?

a=100{ ... }

Something truthy to trigger the code block, also sets the loop variable a to 100.

d=" on the wall";e=" of beer";

Store some re-used strings in variables.

for(f=" bottle";a--;$0=g)

The loop control, first set f in the loop init to save a ;. Then stop/go based on a after decrementing. At the end of the each iteration, set $0 to the accumulated output in g.

g=g ( ... )

Append the text for the next number of bottes to the accumulating output. Sadly the space is needed to avoid AWK parsing g( as a function call.

a?

Ternary for "is there more bottles?"

(c=a f (a-1?"s":b)e)

When there is more than one bottle... Generate "NN bottle of beer" or "NN bottles of beer" to be appended to g and also store that string in c. Using b in the ternary instead of "" saves a character and works since using an uninitialized variables as a string in AWK are treated like empty strings.

d", "c".\nTake one down and pass it around, "c d".\n\n"

Also append the rest of the text we need, making use of c set previously

:"Go to the store and buy some more, 99"f e d".\n"

When at zero bottles, append the last bit of text.

1

A truthy value with no code block causes the default action, which is to print the value of $0

<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\$
1
\$\begingroup\$

M4, 224 bytes

define(b,`$1 bottle`'ifelse($1,1,,s) of beer')define(w,`b($1) on the wall')define(f,`w($1), b($1).
ifelse($1,1,`Go to the store and buy some more, w(99).',`Take one down and pass it around, w(decr($1)).

f(decr($1))')')f(99)

If I learn GNU extensions, perhaps I would shorten this code.

Try it online!

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

Vyxal Hmj, 128 bytes

ƛ‛ḋ¶øP«lT…|«"Ṅ£¥:«∧*JEp
'«\,+"Ṅ$"Ṅ‛.
+n‹[`¬Ȧ λḭ ∧ċ λ¬ ∆¶ it ⟑Ṡ`|«¢ṁĖ↲Ǐ¶QṪD£y∩i› kḭS√⁰«¡]‛, ++n‹[n‹|99]‛ḋ¶øP«∪ṠEȧ₆›λ*ĖC9«"Ṅ\.++;Ṙ

I was going to put this in a comment on @Wasif's answer, but the link was too long, so here's my Vyxal answer, with a -17 byte golf.

Try it Online!

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

Knight, 170 169 bytes

;=r 99WrO++++++""r+C=sB=bS" bottles of beer"7?1r""=e" on the wall"+", "r+bI=r-rT+".
Take one down and pass it around, "r".
Go to the store and buy some more, 99"Cs+e".
"

Try it online!

  • 1 byte: inline CALL

Ungolfed but still barely understandable

# set our counter to 99 (r)
; = counter 99
# We call this inline in the golfed code
# getbottle(s):
# returns pluralized " bottle(s) of beer" depending
# on counter's value, also storing it in beer
; = getbottles BLOCK {
    : = beer 
      : SUBSTITUTE (
        : " bottles of beer"
        : 7
        # when counter == 1, remove the s
        : ? 1 counter 
        # replace with empty string
        : ""
      : )
: }
# Loop while counter != 0
: WHILE counter {
    # basically concatenate everything
    # still better than StringBuilder
    : OUTPUT 
     : ++++++
       : ""
       : counter
        : + (CALL getbottles)
          : (= wall " on the wall")
         : + ", "
           : counter
          : + beer
            : IF (= counter - counter 1) {
            :   # note: \n doesn't actually work, it is just for clarity
            :   + ".\nTake one down and pass it around, " counter
            : } {
            :   ".\nGo to the store and buy some more, 99"
            : }
           : + (CALL getbottles)
             : wall
            : ".\n"
: }
\$\endgroup\$
1
\$\begingroup\$

Japt, 116 bytes

Needs more golfing or, perhaps, a completely different approach. Borrows a couple of tricks from ETH' original version.

Includes 2 trailing newlines.

´Lõ Ô˱` Þ­¤{´LÎçs}  Þ8`".

{=D+`  e Ø!`}, {D}.
{LÎg`Go ‘ e ÐJe „d ¿y Ñ  Ú
Take e ܵ „d p†s Š ÂИ`·}, "iUìé~H

Test it

´Lõ Ô˱`...{´LÎçs}...`"...{=D+`...`}...{D}...{LÎg`...`·}..."iUìé~H
´L                                                                      :Prefix decrement L (initially 100)
  õ                                                                     :Range [1,L]
    Ô                                                                   :Reverse
     Ë                                                                  :Map each D
      ±                                                                 :  Append
       `                                                                :  Compressed string
        ...                                                             :    " bottle"
           {                                                            :    Interpolate
            ´LÎ                                                         :      Prefix decrement L and get its sign
               çs                                                       :      Repeat "s" that many times
                 }                                                      :    End interpolate
                  ...                                                   :    " of beer"
                     `                                                  :  End compressed string
                      "...                                              :  Literal string (the return value)
                          {                                             :    Interpolate
                           =                                            :      Assign to variable U
                            D+`...`                                     :      D & the compressed string " on the wall"
                                   }                                    :    End interpolate
                                    ...                                 :    Literals
                                       {D}                              :    Interpolate D
                                          ...                           :    Literals
                                             {                          :    Interpolate
                                              LÎg                       :      Get the sign of L and index (0-based) into
                                                 `...`                  :        Compressed string "Go to the store and buy some more\nTake one down and pass it around"
                                                      ·                 :        Split on newlines
                                                       }                :    End interpolate
                                                        ..."            :  End of string
                                                            iU          :  Prepend U
                                                              Ã         :End map
                                                               ¬        :Join
                                                                é       :Rotate right by
                                                                 ~H     :  The bitwise NOT of 32 (i.e., -33)
\$\endgroup\$
1
\$\begingroup\$

Oracle SQL, 254 247 285 Bytes

Golfed:

SELECT REGEXP_REPLACE(n||b||w||', '||n||b||p||CHR(10)||DECODE(n,1,'Go to the store and buy some more, 99',t||(n-1))||b||w||p,'(^1| 1).*s','1 bottle') FROM(SELECT 100-LEVEL n,' bottles of beer'b,' on the wall'w,'Take one down and pass it around, 't,'.'p FROM DUAL CONNECT BY LEVEL<=99);

Ungolfed:

SELECT regexp_replace(n || b || w || ', ' || n || b || p || chr(10) || decode(n, 1, 'Go to the store and buy some more, 99', t || (n - 1)) || b || w || p,
                      '(^1| 1).*s',
                      '1 bottle')
FROM (SELECT 100 - LEVEL n,
            ' bottles of beer' b,
            ' on the wall' w,
            'Take one down and pass it around, ' t,
            '.' p
      FROM dual
      CONNECT BY LEVEL <= 99);

Basically, I get the row number via the hierarchical query and build a small library in the inner query. Then I put it all together in the outer query.

Edit 1: -7 Bytes: Used the "distributive" property on common string within the DECODE function. Edit 2: +38 bytes: Oops, missed the s on 1 bottle. Fixed with regular expression string replacement.

Try it out here: DBFiddle

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

Rattle, 201 200 bytes

99& bottles of beer& on the wall&Take one down and pass it around, &, &.&1 bottle of beer&Go to the store and buy some more, 99|IPg[bb1b2b4bb1b5B-sb3[1f0]bb1b2b5Bbb^B]0;b6b2b5Bbb^Bb6b2b4b6b5Bb7b1b2b5q

Try it Online!

This basically takes the lyrics chopped up then pieces them together. It's likely that this can be shortened a bit

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

R, 297 bytes

b='bottles of beer'
w='on the wall'
p=paste
g=gsub
s='$'
x='.'
d=p(g(s,',',b),w)
j=99
i=j:1
l=g(s,x,p(i,d,i,b))
l[j]=g('s','',l[j])
m=p('Take one down and pass it around,',i,d)
o=p(l,m,sep="\n")
o[j]=g('\n.*',g(s,x,p('\nGo to the store and buy some more,',j,d)),o[j])
write(o,"")

Ideone link to test

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

Go, 287

package main
import."fmt"
func main(){p,s,n:=Printf,"%[1]d bottle%[2]s of beer",`.
`
o:=s+" on the wall"
a,b,c,i,k:=o+`, `+s+n,`Take one down and pass it around, `+o+n+`
`,`Go to the store and buy some more, `+o+n,99,"s"
for 1<i{p(a,i,k)
if i--;i<2{k=""}
p(b,i,k)}
p(a,i,k)
p(c,99,"s")}

There is probably room for further optimization

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

Dart, 218 bytes

int i=99;b(i)=>'$i bottle${i<2?'':'s'} of beer';w(i)=>b(i)+' on the wall';main(){while(i>0){print(w(i)+', ${b(i)}.\n${--i>0?'Take one down and pass it around, '+w(i):'Go to the store and buy some more, '+w(99)}.\n');}}
\$\endgroup\$
0
\$\begingroup\$

Python3, 258 237 232 bytes

Being strict about spaces and newlines.

i=98;b="bottle";w="on the wall";o="of beer"
while i+1:y=bool(i);s="s"*y;print(i+1,b+s,o,w+",",i+1,b+s,o+".\n"+("Go to the store and buy some more,","Take one down and pass it around,")[y],i or 99,b+"s"*bool(i-1),o,w+"."+"\n"*y);i-=1

Readable (sort of):

i=98
b="bottle"
w="on the wall"
o="of beer"
while i + 1:
    y = bool(i)
    s = "s" * y
    print(
        i + 1,
        b + s,
        o,
        w + ",",
        i + 1,
        b + s,
        o + ".\n" 
        + (
            "Go to the store and buy some more,",
            "Take one down and pass it around,"
        )[y],
        i or 99,
        b + "s" * bool(i - 1),
        o,
        w + "." 
        + "\n" * y
    )
    i -= 1

Default unspecified arguments for print(): sep=' ' and end='\n'.

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

Scala, 313 298 271 268 bytes

I think I may have reached the limit on this without resorting to string compression algorithms.

object m extends App{val(f,c)=((x:Int)=>s"$x bottle${if(x>1)"s" else ""} of beer"," on the wall");99 to 1 by -1 map(a=>println(s"${f(a)}$c, ${f(a)}.\n${if(a>1)"Take one down and pass it around" else "Go to the store and buy some more"}, ${f(if(a>1)a-1 else 99)}$c."))}

(Semi-)readable version:

object m extends App{
  val(f,c)=((x:Int)=>s"$x bottle${if(x>1)"s" else ""} of beer"," on the wall");
  99 to 1 by -1 map(a=>println(s"${f(a)}$c, ${f(a)}.\n${if(a>1)"Take one down and pass it around" else "Go to the store and buy some more"}, ${f(if(a>1)a-1 else 99)}$c."))
}
\$\endgroup\$
0
\$\begingroup\$

CJam, 257 229 bytes

229 Bytes

99:A;"bottles of beer":B;{A" "B" on the wall, "A" "B"."NA(:A;"Take one down and pass it around, "A" "B" on the wall."NN}98*"1 bottle of beer on the wall, 1 bottle of beer."N"Go to the store and buy some more, 99 "B" on the wall."

257 Bytes

99:A;{A" bottles of beer on the wall, "A" bottles of beer."NA(:A;"Take one down and pass it around, "A" bottles of beer on the wall."NN}98*"1 bottle of beer on the wall, 1 bottle of beer."N"Go to the store and buy some more, 99 bottles of beer on the wall."
\$\endgroup\$
0
\$\begingroup\$

Loader, 515 bytes

Run from a module named m.

~I:set I,B =99
set P =B
decr P
~P:printf "1 bottle of beer on the wall, 1 bottle of beer."
~P:printf "You go to the store and you buy some more, 99 bottles of beer on the wall."
~P:exit
P:printf "%n bottles of beer on the wall, %n bottles of beer." B,B
~P:printf "1 bottle of beer on the wall!, 1 bottle of beer."
decr P
decr B
P:printf "You take one down and you pass it around, %n bottles of beer on the wall." B
~P:printf "You take one down and you pass it around, 1 bottle of beer on the wall."
printf ""
load m
\$\endgroup\$
0
\$\begingroup\$

C++, 335 bytes

Golfed:

#include <stdio.h>
int main(){for (int c = 99; c >= 2; c--){printf("%i bottles of beer on the wall, %i bottles of beer.\nTake one down and pass it around, %i bottles of beer on the wall.", c, c, c-1);}printf("1 bottle of beer on the wall, 1 bottle of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.");return 0;}

Ungolfed:

#include <stdio.h>

int main()
{
    for (int c = 99; c >= 2; c--) {
        printf("%i bottles of beer on the wall, %i bottles of beer.\nTake one down and pass it around, %i bottles of beer on the wall.", c, c, c-1);
    }
    printf("1 bottle of beer on the wall, 1 bottle of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.");

    return 0;

} 
\$\endgroup\$
4
  • \$\begingroup\$ This does not have valid output for the last line. \$\endgroup\$ Nov 18 '15 at 18:22
  • \$\begingroup\$ Welcome to PPCG! I've done a bit of formatting, hope you don't mind. Unfortunately though, as VoteToClose has kindly pointed out, the last line is incorrect (and also two other lines before that, which require 1 bottle of beer rather than bottles). \$\endgroup\$
    – Sp3000
    Nov 18 '15 at 18:24
  • \$\begingroup\$ Oh, thank you. I will fix as necessary. \$\endgroup\$ Nov 18 '15 at 18:25
  • \$\begingroup\$ This is still not valid. The last line is "Go to the store and buy some more, 99 bottles of beer on the wall.". \$\endgroup\$ Nov 18 '15 at 18:43
0
\$\begingroup\$

Python 3, 210 bytes

b=" of beer"
s="bottles"+b
t=s[:6]+b
q="on the wall."
p=print
x=99
while x>1:p(x,s,q,x,s+".\nTake one down and pass it around,",x-1,(s,t)[x>1],q);x-=1
p(1,t,q,1,t+".\nGo to the store and buy some more,",99,s,q)

Try it here: https://ideone.com/iX4byJ

\$\endgroup\$
1
  • \$\begingroup\$ This doesn't separate the verse by newlines, and it has a period instead of a comma after the wall on the first line \$\endgroup\$
    – Jo King
    Feb 28 '19 at 4:34
0
\$\begingroup\$

Python 3, 234 bytes

i=99
s='s'
b='%s bottle%s of beer'
o=' on the wall'
y=b%(i,s)
while i:print(y+o+', '+y+'.');i-=1;s=('',s)[i>1];y=b%(i,s);print(('Take one down, pass it around, '+y+o+'.\n','Go to the store and buy some more, 99'+b%(s,'s')+o+'.')[i<1])

with newlines for some more readability

i=99;
s='s';
b='%s bottle%s of beer';
o=' on the wall';
y=b%(i,s)
while i:
  print(y+o+', '+y+'.');
  i-=1;
  s=('',s)[i>1];
  y=b%(i,s);
  print(('Take one down, pass it around, '+y+o+'.\n','Go to the store and buy some more, 99'+b%(s,'s')+o+'.')[i<1])

makes use of a quirk of booleans to evaluate to zero or one; this allows them to be used as index in two value tuples or lists, and are shorter than the 'proper' equivalent. These pseudo ternaries are used to keep all the loop code on one line.

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

F#, 210 201 263 241 bytes

let B n=sprintf"%d bottle%s of beer"n (if n>1 then"s"else"")
for n=99 downto 1 do printfn"%s on the wall, %s.\n%s on the wall.\n"(B n)(B n)(if n>1 then"Take one down and pass it around, "+B(n-1)else"Go to the store and buy some more, "+B 99)

Missed the "Go to the store and buy some more" part ..

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

C(GCC), 389 bytes

char*c="%1d %3$s of %4$s on the %5$s, %1d %3$s of %4$s.\n\0Take one down and pass it around, %2d %3$s of %4$s on the %5$s.\n\0Go to the store and buy some more, %1d %3$s of %4$s on the %5$s.\n";main(){int k=99;while(k!=0){printf(&c[0],k,k,k==1?"bottle":"bottles","beer","wall");if(1){printf(&c[49],k,k,"bottles","beer","wall");k--;}else{k=99;printf(&c[114],k,k,"bottles","beer","wall");}}}

Used some things I never thought I'd use. I actually don't know if it is supposed to loop after the end.

Ungolfed version:

char* c = "%1d %3$s of %4$s on the %5$s, %1d %3$s of %4$s.\n\0Take one down and pass it around, %2d %3$s of %4$s on the %5$s.\n\0Go to the store and buy some more, %1d %3$s of %4$s on the %5$s.\n";
main() {
    int k = 99;
    while (1) {
        printf(&c[0], k, k, k == 1 ? "bottle" : "bottles", "beer", "wall");
        if (k != 1) {
            printf(&c[49], k, k, "bottles", "beer", "wall");
            k--;
        } else {
            k=99;
            printf(&c[114], k, k, "bottles", "beer", "wall");
        }
    }
}

This can be still golfed more.

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

TLDCode, 235 bytes

='1'#99#p${e# bottle#PG(#s#P)v# of beer on the wall, #Pe# bottle#PG(#s#P)v# of beer.#Pn-(#Take one down and pass it around, #Pe# bottles of beer on the wall.#Pnn)[#Go to the store and buy some more, 99 bottles of beer on the wall.#P]}=
  1. we first clear the stack of the implicit input
  2. We start by pushing a 1 onto the stack, then pushing 99, since that is the first line.
  3. Then we define a repeatable code block that will repeat the amount of times equal to the value of the top of the stack (99)
  4. The first thing that is done on each repeat is printing the top of the stack.
  5. Followed by pushing and printing" bottle" and then if the top of the stack(99) is greater than the next in the stack(1) push and print an "s". Then we remove the top of the stack(the result of the comparison)
  6. Push and print " of beer on the wall, " followed by the printing the top of the stack(99).
  7. then we do step 4 again
  8. then we push and print " of beer." followed by printing a new line
  9. we then decrement the top of the stack (98)
  10. we then define a block that only executes if the top of the stack is true, or an integer greater than 0
  11. this just pushes and prints the second line
  12. then we define a block that only executes if the top of the stack is false or not greater than 0
  13. this pushes the last line
  14. we clear the stack to avoid the implicit printing
\$\endgroup\$
0
\$\begingroup\$

tcl, 243

proc B {} {set x " bottle[expr $::i>1?{s}:{}] of beer"}
set i 99
time {puts "$i[B][set w " on the wall"], $i[B].
Take one down and pass it around, [incr i -1][B]$w."} 98
puts "1[B]$w, 1[B].
Go to the store and buy some more, [incr i 98][B]$w."

demo


tcl, 255

proc B i {set x " bottle[expr $i>1?{s}:{}] of beer"}
set w " on the wall"
set i 99
while \$i>1 {puts "$i[B $i]$w, $i[B $i].\nTake one down and pass it around, [incr i -1][B $i]$w."}
puts "1[B $i]$w, 1[B $i].\nGo to the store and buy some more, 99[B 9]$w."

demo

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

Julia 0.6.0 (256 bytes)

b=" bottle";d=" of beer";w=" on the wall, ";t="Take one down and pass it around,";i=99;k=println;while i>0 (i>1)&&(k(i,b*"s",d,w,i,b*"s",d);k(t,i,b*"s",d,w));(i==1)&&(k(i,b,d,w,i,b,d));i-=1 end;k("Go to the store and buy some more, ",99,b*"s",d,w[1:end-2])

I know there is already a Julia answer, but I wanted to tackle it anyway! I only have a few bytes more then the other Julia so maybe I can find a way to chop some here and there!

Try it online!

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

Jq 1.5, 232 bytes

def B:" bottle\(if.>1 then"s"else""end) of beer";def W:" on the wall";def T:"Take one down and pass it around";99-range(99)|"\(.)\(B+W), \(.)\(B).
\(T), \(.-1)\(B+W).
"|gsub(0|T+", 0"+B+W;"Go to the store and buy some more, 99"+B+W)

Expanded

def B:" bottle\(if.>1 then"s"else""end) of beer";
def W:" on the wall";
def T:"Take one down and pass it around";

  99-range(99)
| "\(.)\(B+W), \(.)\(B).
\(T), \(.-1)\(B+W).
"
|gsub(0|T+", 0"+B+W;"Go to the store and buy some more, 99"+B+W)

Try it online!

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

Funky, 290 bytes

for(i=99;i>0;i--)print("%i %s on the wall, %i %s.%sTake one down and pass it around %i %s on the wall."::format(i,c=(b="bottle%s of beer")%(i>1)?"s":"",i,c,"\n",i,c))print("0 %s on the wall, 0 %s.%sGo to the store and buy some more, 99 bottles of beer on the wall."::format(c=b%"s",c,"\n"))

Try it online!

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

17, 1180 bytes

0 {
2 #
1 -
:
2 @
3 <
0 @
1f : : : : : : : : : : : : : : : : : : : : : :
2 # $$
$ 5d $ 69 $ 6e $ 6e $ 66 $ 5g $ 6d $ $ 69 $ 60 $ $ 5d $ 5g $ 5g $ 6c $ $ 69 $ 68 $ $ 6e $ 62 $ 5g $ $ 70 $ 5c $ 66 $ 66 $ 2a $ $
2 # $$
$ 5d $ 69 $ 6e $ 6e $ 66 $ 5g $ 6d $ $ 69 $ 60 $ $ 5d $ 5g $ 5g $ 6c $ 2c $ a $
4g $ 5c $ 65 $ 5g $ $ 69 $ 68 $ 5g $ $ 5f $ 69 $ 70 $ 68 $ $ 5c $ 68 $ 5f $ $ 6a $ 5c $ 6d $ 6d $ $ 63 $ 6e $ $ 5c $ 6c $ 69 $ 6f $ 68 $ 5f $ 2a $ $
2 # 1 - $$
$ 5d $ 69 $ 6e $ 6e $ 66 $ 5g $ 6d $ $ 69 $ 60 $ $ 5d $ 5g $ 5g $ 6c $ $ 69 $ 68 $ $ 6e $ 62 $ 5g $ $ 70 $ 5c $ 66 $ 66 $ 2c $ a $ a $
}
1 {
1f : : : : : : : : : : : : : : : : : : : : : : :
2f $ $ 5d $ 69 $ 6e $ 6e $ 66 $ 5g $ $ 69 $ 60 $ $ 5d $ 5g $ 5g $ 6c $ $ 69 $ 68 $ $ 6e $ 62 $ 5g $ $ 70 $ 5c $ 66 $ 66 $ 2a $ $ 2f $ $ 5d $ 69 $ 6e $ 6e $ 66 $ 5g $ $ 69 $ 60 $ $ 5d $ 5g $ 5g $ 6c $ 2c $ a $
43 $ 69 $ $ 6e $ 69 $ $ 6e $ 62 $ 5g $ $ 6d $ 6e $ 69 $ 6c $ 5g $ $ 5c $ 68 $ 5f $ $ 5d $ 6f $ 72 $ $ 6d $ 69 $ 67 $ 5g $ $ 67 $ 69 $ 6c $ 5g $ 2a $ $ 36 $ 36 $ $ 5d $ 69 $ 6e $ 6e $ 66 $ 5g $ 6d $ $ 69 $ 60 $ $ 5d $ 5g $ 5g $ 6c $ $ 69 $ 68 $ $ 6e $ 62 $ 5g $ $ 70 $ 5c $ 66 $ 66 $ 2c $ a $
0 @
}
777 {
5f 2 @
0 1 @
0 0 @
}
\$\endgroup\$
0
\$\begingroup\$

Gema, 210 206 characters

\A=@set{b;99}@repeat{99;@w{}, @b{}.\n@cmpn{$b;1;;Go to the store and buy some more@set{b;99};Take one down and pass it around@decr{b}}, @w{}.\n\n}@end
b:=$b bottle@cmpn{$b;1;;;s} of beer
w:=@b{} on the wall

Sample run:

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.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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