Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Challenge

Write a program that generates the song "There Was A Stream", detailed below.

Description

The song "There Was a Stream" is a camping song. It takes N parameters and generates a song of length O(N2) lines. A sample song (first 3 verses) is given here.

Rules

  • Your entry must take a list of strings and output a valid song. It may be a function (that takes an array of strings) or a program (that takes strings from ARGV or STDIN). Output may be a return value or output to STDOUT or STDERR.
  • It must run within 1/2 second on my machine (1.66GHz Intel Atom, 1GB RAM, Ubuntu 12.04) for all invocations with less than 15 parameters.
  • Verses must be separated by a blank line.
  • No inbuilt compression function (e.g. gzip), whether from the core or from libraries. Things like rot13, md5, base64 etc. are okay though.
  • You may include a data file (that is placed in the same directory and named whatever you wish), but its score will be added to the total for the program.

Scoring

Count the number of characters (if you use ASCII) or raw bytes (if you use something else).
Command-line flags (without the hyphens) are included, but not the interpreter name, for example #!/usr/bin/perl -n adds 1 to the character count. All whitespace is included.
As with all code-golf, the entry with the lowest character count wins.
Deadline: 14 December 2012

Example

INPUT: bank house
OUTPUT: (given above)

Reference implementation (ungolfed, very ugly code): http://pastebin.com/VeR4Qttn

share|improve this question
1  
That third verse looks suspicious. –  Peter Taylor Dec 3 '12 at 10:19
    
I've edited it. Tell me if anything else looks weird. –  o_o Dec 3 '12 at 12:34
    
Any restrictions on pre-existing compression libraries and/or character encoding? –  primo Dec 3 '12 at 14:00
    
No compression libraries, any character encoding you wish (but count bytes). More details above. –  o_o Dec 3 '12 at 14:26
    
Kind of a duplicate: codegolf.stackexchange.com/questions/6043/… –  mob Dec 5 '12 at 22:07

3 Answers 3

up vote 4 down vote accepted

Perl 239 + 2 = 241 bytes

This is a mostly binary solution, so as usual, this is a program to generate it:

generator.pl

use MIME::Base64;

$data = <<EOD;
JF89bGMgcGFjayB1NjAsJ8MqbtCBITBInQmKJcpWt4c2oWhLBPwjAkyBIiUwjBI3Ql9c9GoWtJZbuTd5
ZbuWhPwjAkyBIyQjDBFXQlLpGtKJWhP2t4c2r7mhFQjAqdM2t4eTjjk2aJcpWtKJWrb77ms6Kbpc2qKZ
6E1rmtKJWo7JYcmorNZWhM6+U1LpGobLGt4c2osqZ6NGobpGp4eTk0wiTBIXQlLpGr7mtKIdGhPwjBIT
nQkyBISUwjBFXQtKJWhPxAjBLHR7KdNLJWh5r8ms9MpYbTIFQyc7eS8zLTovCkFGSUpUVyAvO2V2YWw=
EOD

print decode_base64($data);

Accepts input from STDIN, space separated, two extra bytes for the -na option. Sample usage:

$ perl generator.pl > out.pl

$ stat -c %s out.pl
239

$ echo bank house | perl -na out.pl
There was a stream
(There was a stream)
Just a teeny-weeny stream
(Just a teeny-weeny stream)
And the stream was on its way...
Where the moon shines high
In the clear blue sky
And all was bright and gay.

And on that stream
(And on that stream)
There was a little bank
(There was a little bank)
Just a teeny-weeny bank
(Just a teeny-weeny bank)
And the bank was on the stream
And the stream was on its way...
Where the moon shines high
In the clear blue sky
And all was bright and gay.

And on that bank
(And on that bank)
There was a little house
(There was a little house)
Just a teeny-weeny house
(Just a teeny-weeny house)
And the house was on the bank
And the bank was on the stream
And the stream was on its way...
Where the moon shines high
In the clear blue sky
And all was bright and gay.

Method

Consider the following UU-Encoded string:

\PRINT($A,$B="8HERE:WAS:A:$L$_","3($B)3",$C="7UST:A:TEENY-WEENY:$_","3($C)",,$5="
\4ND:THE:$_:WAS:ON:$5","ITS:WAY...39HERE:THE:MOON:SHINES:HIGH36N:THE:CLEAR:BLUE:$
\SKY34ND:ALL:WAS:BRIGHT:AND:GAY.33"),$A="4ND:ON:THAT:$_",$A.="3($A)3",$5="THE:$_$
5",$L='LITTLE:'FOR:STREAM,@5#

After applying a lc,y/3-:/\nAFIJTW / it becomes this:

\print($a,$b="There was a $l$_","
($b)
",$c="Just a teeny-weeny $_","
($c)",,$F="
\And the $_ was on $F","its way...
Where the moon shines high
In the clear blue $
\sky
And all was bright and gay.

"),$a="And on that $_",$a.="
($a)
",$F="the $_$
F",$l='little 'for stream,@F#

Which is basically the 269 byte solution below.

There's a few problems with this method, though. UU-Encoded strings are limited to characters 33-96, which excludes space, newline, and { | } ~, as well as all lower-case letters. The solution I chose, is to apply lc after the pack u, and then translate 8 characters: space, newline, and the 6 upper-cased I needed. This leaves an 18 byte footprint, which is fairly excessive, but it produces the desired result.

The other problem is that each line needs to begin with the same character (here I chose \ corresponding to a decoded length of 60 (92 - 32), which is an encoded length of 80), except for the last line, which needs to begin with the character reflecting its length. Here I ended up with 21 (padding with a # to be evenly divisible by 3), corresponding to 5. No problem, I'm replacing 5 anyway, so I chose it as one of my variables. Perl seems to be incredibly lenient about where you can place backslashes. This program even begins with one.

It is possible to instruct perl to use a other characters to begin each line, such as M (the default value), but none seem quite as flexible as a backslash. As an aside, this method should be equally as effective in Ruby. If I had any skill in the language, I might be tempted to try it.

For reference, my previous solutions remain below.


Perl 267 + 2 = 269 bytes

(print$a,$b="There was a $l$_","
($b)
",$c="Just a teeny-weeny $_","
($c)",$d="
And the $_ was on $d",'its way...
Where the moon shines high
In the clear blue sky
And all was bright and gay.

'),$a="And on that $_",$a.="
($a)
",$d="the $_$d",$l='little 'for stream,@F

Accepts input from STDIN, space separated, two extra bytes for the -na option. Sample usage:

$ echo bank house | perl -na stream-song.pl


PHP 286 bytes

No real attempt at compression, just output reusage.

<?for($w=stream;$w;$a="And on that $w",$a.="
($a)
",$l='little ',$d="the $w$d",$w=next($argv))echo$a,$b="There was a $l$w","
($b)
",$c="Just a teeny-weeny $w","
($c)",$d="
And the $w was on $d",'its way...
Where the moon shines high
In the clear blue sky
And all was bright and gay.

';

Accepts input as command line arguments. Sample usage:

$ php stream-song.php bank house
share|improve this answer

Haskell, 366 characters

t="stream"
b o="And the "++o++" was on "
p s=[s,'(':s++")"]
a(o:q@(p:_))=(b o++"a "++p):a q
a[o]=[b o++"its way..."]
v l@(o:q)=w q++p("There was a "++if o==t then o else"little "++o)++p("Just a teeny-weeny "++o)++a l++["Where the moon shines high","In the clear blue sky","And all was bright and gay.",""]
w m@(y:_)=v m++p("And on that "++y)
w[]=[]
s=v.reverse.(t:)

As permitted by the problem statement, this is a function s :: [String] -> String, where the input is the objects and the return value is a list of lines of the song.

This is nowhere near the current leader in this challenge, but it's as far as I got and I thought someone might like to see if it can be improved. I think its main failing is trying too hard to capture all of the structure of the song in the structure of the program. It also might be interesting to rewrite it to use lists of words (replace ++ with , and fewer spaces), or \ns rather than a list of lines.

Fluffy source:

stream="stream"
andthe o="And the "++o++" was on "
p s=[s,'(':s++")"]

ander :: [String] -> [String]
ander(o:os@(p:_))=(andthe o++"a "++p):ander os
ander[o]=[andthe o++"its way..."]

outerVerse :: [String] -> [String]
outerVerse l@(o:os)=recurse os++p("There was a "++if o==stream then o else"little "++o)++p("Just a teeny-weeny "++o)++ander l++["Where the moon shines high","In the clear blue sky","And all was bright and gay.",""]

recurse :: [String] -> [String]
recurse m@(y:_)=outerVerse m++p("And on that "++y)
recurse[]=[]

song=outerVerse.reverse.(stream:)
go xs = putStr $ unlines $ song xs

Defluffifier (in Perl):

#!/usr/bin/perl -wp

s/ ?\+\+ ?/++/g;
s/ander/a/g;
s/andthe/b/g;
s/iverse/i/g;
s/song/s/g;
s/stream(?!")/t/g;
s/\bos\b/q/g;
s/outerVerse/v/g;
s/recurse/w/g;
s/ends/z/g;

s/^go .*//s;
s/--.*//s;
s/^\s\Z//s;
s/^.*::.*\Z//s;
share|improve this answer

Python 2.7 352 Bytes

import urllib as u;import re,sys;v=sys.argv;f=lambda l,o,n:[re.sub(o,n,i) for i in l];n='\n';d=-1;m=re.findall('i\d.+>(.+)</d',u.urlopen('http://goo.gl/48fMV').read());a=m[:8]+[n];z=range;s='stream'
for t in z(len(v)+d):a+=f(m,s,v[t])[9:11]+f(m,s,'little '+v[t+1])[:4]+['And the '+v[i+1]+' was on a '+v[i] for i in z(t,d,d)]+m[4:8]+[n]
print n.join(a)

Example usage:

python stream bank house

Output:

There was a stream
(There was a stream)
Just a teeny-weeny stream
(Just a teeny-weeny stream)
And the stream was on its way...
Where the moon shines high
In the clear blue sky
And all was bright and gay.


And on that stream
(And on that stream)
There was a little bank
(There was a little bank)
Just a teeny-weeny little bank
(Just a teeny-weeny little bank)
And the bank was on a stream
And the stream was on its way...
Where the moon shines high
In the clear blue sky
And all was bright and gay.


And on that bank
(And on that bank)
There was a little house
(There was a little house)
Just a teeny-weeny little house
(Just a teeny-weeny little house)
And the house was on a bank
And the bank was on a stream
And the stream was on its way...
Where the moon shines high
In the clear blue sky
And all was bright and gay.

Un-golfed (also added a few a+=s):

#!/usr/bin/env python

import urllib as u
import re
import sys

v=sys.argv

f=lambda l,o,n: [re.sub(o,n,i) for i in l]

n='\n';
d=-1;
m=re.findall('i\d.+>(.+)</d',u.urlopen('http://goo.gl/48fMV').read())
a=m[:8]+[n]
z=range
s='stream'


for t in z(len(v)+d):
    a+=f(m,s,v[t])[9:11]
    a+=f(m,s,'little '+v[t+1])[:4]
    a+=['And the '+v[i+1]+' was on a '+v[i] for i in z(t,d,d)]
    a+=m[4:8]+[n]
print n.join(a)
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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