71
\$\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\$
  • 12
    \$\begingroup\$ Whoever closevoted this, the other one is a popularity contest... \$\endgroup\$ – TheDoctor Nov 18 '15 at 15:19
  • 19
    \$\begingroup\$ This is a subtask of the Create an HQ9+ Interpreter golf. \$\endgroup\$ – Geobits Nov 18 '15 at 15:25
  • 4
    \$\begingroup\$ @CᴏɴᴏʀO'Bʀɪᴇɴ I haven't VTCd it yet, still deciding how I feel about that. Either way, I think some answers (or snippets from them) from the other can be directly copy/pasted while remaining competitive, which is a usual test for dupe-ness. \$\endgroup\$ – Geobits Nov 18 '15 at 15:54
  • 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
  • 13
    \$\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

139 Answers 139

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

Python, 172 bytes

a="\n%s bottles of beer on the wall"
t="\n\nTGaok et oo nteh ed oswtno raen da npda sbsu yi ts oamreo umnodr e"
d=99
while d:print(a%d*2)[:-12]+t[d==1::2]+a%(d-1or 99);d-=1

Try it online!

Explanation:

a="\n%s bottles of beer on the wall"

Stores the first line of the lyrics with a formatted argument.

t="\n\nTGaok et oo nteh ed oswtno raen da npda sbsu yi ts oamreo umnodr e"

Stores the third line. The characters at even indices make up Take one down and pass it around, and the characters at odd indices make up Go to the store and buy some more.

d=99

Counter variable for the current number of bottles, initialized to 99.

while d:                                           d-=1

In Python (and most other languages), a non-zero integer is truthy, while 0 is falsey. This while loop (although kind of hacky) repeats until d is 0, subtracting 1 from d every time.

        print             +          +            ;

I used only one print statement to save bytes, and just added multiple strings together.

             (a%d*2)[:-12]

Formats the first line with the number of bottles, repeats it, and chops off the on the wall part from the first line to make the second line.

                           t[d==1::2]

Extended slicing. Takes every other character, starting from the first character if d is not 1, but starting from the second character is d is 1. In Python, booleans can be implicitly converted to integers, so true would turn into 1, and false would turn into 0.

                                      a%(d-1or 99)

Just the first line again, except this time with one less bottle. Again, anything except 0 is truthy, so if d-1 is 0, it will give 99 instead.

\$\endgroup\$
  • 1
    \$\begingroup\$ Appears not to handle plural for n=1 (1 bottle of beer on the wall, 1 bottle of beer.) properly. \$\endgroup\$ – jq170727 Oct 22 '17 at 19:51
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\$
0
\$\begingroup\$

T-SQL, 334 bytes

WITH n AS(SELECT 99c UNION ALL SELECT c-1FROM n WHERE c>2),s
AS(SELECT' bottles of beer'b,' on the wall'w,'.
Take one down and pass it around, 't)SELECT
CONCAT(c,b,w,', ',c,b,t,c-1,IIF(c=2,STUFF(b,8,1,''),b),w,'.')FROM n,s
UNION ALL SELECT REPLACE(CONCAT(1,b,w,', ',1,b),'s','')+'.
Go to the store and buy some more, 99'+b+w+'.'FROM s

Inspired by but different than both other T-SQL answers. Note that both these answers have a bug on the 2nd to last verse, they output 1 bottles instead of 1 bottle. If I allow that bug in my code, too, I can get down to 309 bytes by removing IIF(c=2,STUFF(b,8,1,''),b).

In my case I'm joining together a table of numbers and a table of strings, and using the CONCAT() function to assemble each verse.

I then construct the very last verse separately using UNION ALL. REPLACE() is used to make both of the bottle singular.

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

Perl 6, 226 bytes

sub b(\a,$b?){a~' bottle'~('s'if a-1)~' of beer'~(' on the wall'if $b)}
for 99…1 ->\a{say b(a,1)~", "~b(a)~'.
'~(if a-1 {'Take one down and pass it around, '~b a,1;}else{'Go to the store and buy some more, '~b 99,1;})~'.
';}

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Some quick golfing for 207 bytes. There's more bytes to be saved though \$\endgroup\$ – Jo King Oct 23 '18 at 21:34
0
\$\begingroup\$

CJam, 107 bytes

    99:B;" bottles of beer":A;B{BX-A" on the wall"NBX-AN"take one down pass it around"NBX-W+A" on the wall"N}fX

this answer is pretty boring but I think it's the simplest.

\$\endgroup\$
  • \$\begingroup\$ Welcome to PPCG! Your output doesn't match the output from the challenge spec, which differs in punctuation, whitespace, and the Go to the store and buy some more part at the end. \$\endgroup\$ – Dennis Jan 23 at 3:53
  • \$\begingroup\$ @Dennis thank you for letting me know! I'll make sure to fix it soon \$\endgroup\$ – Jackson Jan 29 at 6:09
0
\$\begingroup\$

Python 3, 288 266 253 (credit: Jo King) 251 242 bytes

b=lambda x:"%s bottle%s of beer"%(x,"s"*(x>1));o="on the wall"
for i in range(99,0,-1):print("\n%s %s, %s.\n%s"%(b(i),o,b(i),["Take one down and pass it around, %s %s."%(b(i-1),o),"Go to the store and buy some more, %s %s."%(b(99),o)][i==1]))
\$\endgroup\$
0
\$\begingroup\$

ES7, 275 bytes

for(x=99,a=``;x;)a+=x+` bottles of beer on the wall, ${x} bottles of beer,
Take one down and pass it around, ${x--} bottle${x-1?"s":""} of beer on the wall.
`;a+=`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.`

Feel free to find bugs and to give ideas on how to optimize the code.

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

ink, 192 bytes

-(t)->c->v->
, ->c->
-(k){k<99:
Take one down and pass it around, ->c->v->
.
\ 
->t
}Go to the store and buy some more, ->c->v->
.
=c
{99-k%99} bottle{k-98:s} of beer->->
=v
 on the wall<>->->

Try it online!

Not too bad for a non-esoteric language.

Explained

-(t)                                               // A gather point, with the label t. We can divert here, and t can be read as a view counter.
->c->v->                                           // Go to c, then v, then return here
, ->c->                                            // Print a comma and a space, then go to c and return here
-(k)                                               // Another labelled gather. Having the read counter be here is useful, because it means we handle the increment in the right spot.
{k<99:                                             // The first 98 times:
Take one down and pass it around, ->c->v->         // Take one down and pass it around. Also, go to c and v.
.                                                  // Print a period
\                                                  // Ink is a bit weird with whitespace, but this lets us force a newline. Note that there is one space after the backslash in the original.
->t                                                // Back to the top
}Go to the store and buy some more, ->c->v->       // We only get here when k>=99
.                                                  // Print a period, then halt because we're out of content.
=c                                                 // In this stitch, we print how many bottles of beer we have. We use the k counter to keep track.
{99-k%99} bottle{k-98:s} of beer->->               // The modulo is to reset to 99 when we get back from the store. We also almost always print the s after bottle - but not when k is 98.
=v                                                 // "on the wall"
 on the wall<>->->                                 // <> means don't print a newline after this string. You need to specify that sometimes.
\$\endgroup\$
0
\$\begingroup\$

Javascript ES6, 247 237 bytes

m=" bottles of beer",j=m.replace("s",""),k=" on the wall",a="";for(i=99;i>1;)a+=i+m+k+`, ${i+m}.
Take one down and pass it around, ${(--i)+(i-1?m:j)+k}.

`;a+=`1${j+k}, 1${j}. Go to the store and buy some more, 99${m+k}.`;console.log(a);

-10 bytes thanks to Jo King.

\$\endgroup\$
  • \$\begingroup\$ This doesn't print any newlines between lines/verses \$\endgroup\$ – Jo King Mar 24 at 2:26
  • \$\begingroup\$ You can get [237 bytes]tio.run/##HY7BboMwEETv@YqVxQFkg8SRWrTH/kA/…) with correct newlines by removing the let and moving the t part into the loop \$\endgroup\$ – Jo King Mar 24 at 2:35
0
\$\begingroup\$

Keg

c&(c|&:.& bottle&:&1=[|s] of beer on the wall\, ^(,)&:.& bottle&:&1=[|s] of beer\.\
^(,)Take one down\, pass it around\, ^(,)&1-:&[&:.&|no more] bottle&:&1=[|s] of beer on the wall\.\
^(,))

First, the program saves 99 to the accumulator. Then, a for loop iterating 99 times will be executed:

  • The accumulator will be printed
  • The rest of the line will be pushed and printed, with singular/plural detection
  • The code is similar to the verses between until the last verse.
  • Decrement the accumulator by 1 and print it (if the accumulator is 0, print "no more")
  • Push the rest of the verse and print it
\$\endgroup\$
  • \$\begingroup\$ Consider adding a short explanation to your answer. Code-only answers may be automatically flagged as low-quality. See other answers for examples. \$\endgroup\$ – mbomb007 Jun 6 at 19:16

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.