Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Code Golf: Musical Notes

Golfscript (112 characters)

' '%:A;10,{):y;A{2/.0~|1=~:r;0=0=5\- 7%
4y@--:q'  '' O'if-4q&!q*r*{16q/r<'|\\'
'| 'if}'  'if+{.32=y~&{;45}*}%}%n}%

Perl, 126 characters (115/122 with switches)

Perl in 239 226 218 216 183 180 178 172 157 142 136 133 129 128 126 chars

This 126 character solution in Perl is the result of a lengthy collaboration between myself and A. Rex.

@o=($/)x10;$/=$";map{m[/];$p=4+(5-ord)%7;
$_.=--$p?!($p&~3)*$'?16<$p*$'?"  |\\":"  | ":$/x4:" O  ",
$|--&&y@ @-@for@o}<>;print@o

A. Rex also proposes a solution to run with the perl -ap switch. With 111(!) characters in this solution plus 4 strokes for the extra command-line switch, this solution has a total score of 115.

$\="$:
"x5;$p=4+(5-ord)%7,s#..##,$\=~s#(.)\K$#--$p?
$_*!($p&~3)?"$1|".(16<$p*$_?"\\":$1).$1:$1x4:O.$1x3#gemfor@F

The first newline in this solution is significant.

Or 122 characters embedding the switches in the shebang line:

#!perl -ap
$\="$:
"x5;$p=4+(5-ord)%7,s#..##,$\=~s#(.)\K$#--$p?$_*!($p&~3)?"$1|".(16<$p*$_?
"\\":$1).$1:$1x4:O.$1x3#gemfor@F

(first two newlines are significant).

Half-notes can be supported with an additional 12 chars:

@o=($/)x10;$/=$";map{m[/];$p=4+(5-ord)%7;
$_.=--$p?!($p&~3)*$'?16<$p*$'?"  |\\":"  | ":$/x4:$'>2?" @  ":" O  ",
$|--&&y@ @-@for@o}<>;print@o

LilyPond - 244 bytes

Technically speaking, this doesn't adhere to the output specification, as the output is a nicely engraved PDF rather than a poor ASCII text substitute, but I figured the problem was just crying out for a LilyPond solution. In fact, you can remove the "\autoBeamOff\cadenzaOn\stemUp" to make it look even more nicely formatted. You can also add "\midi{}" after the "\layout{}" to get a MIDI file to listen to.

o=#(open-file"o""w")p=#ly:string-substitute
#(format o"~(~a"(p"2'1""2"(p"4'1""4"(p"6'1""6"(p"8'1""8"(p"/""'"(p"C""c'"(p"D""d'"(p" ""/1"(p"
"" "(ly:gulp-file"M")))))))))))#(close-port o)\score{{\autoBeamOff\cadenzaOn\stemUp\include"o"}\layout{}}

Usage: lilypond thisfile.ly

Notes:

  1. The input must be in a file named "M" in the same directory as the program.
  2. The input file must end in a newline. (Or save 9 bytes by having it end in a space.)
  3. The output is a PDF named "thisfile.pdf", where "thisfile.ly" is the name of the program.
  4. I tested this with LilyPond 2.12.2; other versions might not work.

I haven't done much in LilyPond, so I'm not sure this is the best way to do this, since it has to convert the input to LilyPond format, write it to an auxiliary file, and then read it in. I currently can't get the built-in LilyPond parser/evaluator to work. :(

Now working on an ASCII-output solution.... :)


C89 (186 characters)

#define P,putchar(
N[99];*n=N;y;e=45;main(q){for(;scanf(" %c/%d",n,n+1)>0;n
+=2);for(;y<11;q=y-(75-*n++)%7 P+q-4?e:79)P*n&&q<4&q>0?
124:e)P*n++/4>>q&&q?92:e))*n||(e^=13,n=N,y++P+10))P+e);}

Half-note support (+7 characters)

#define P,putchar(
N[99];*n=N;y;e=45;main(q){for(;scanf(" %c/%d",n,n+1)>0;n
+=2);for(;y<11;q=y-(75-*n++)%7 P+q-4?e:v<4?79:64)P*n&&q<4&q>0?
124:e)P*n++/4>>q&&q?92:e))*n||(e^=13,n=N,y++P+10))P+e);}

Python 178 characters

The 167 was a false alarm, I forgot to suppress the stems on the whole notes.

R=raw_input().split()
for y in range(10):
 r=""
 for x in R:o=y-(5-ord(x[0]))%7;b=" -"[y&1]+"O\|";r+=b[0]+b[o==3]+b[-(-1<o<3and''<x[1:])]+b[2*(-1<o<":862".find(x[-1]))]
 print r

Python 167 characters (Broken)

No room for the evil eye in this one, although there are 2 filler characters in there, so I added a smiley. This technique takes advantage of the uniqueness of the last character of the note lengths, so lucky for me that there are no 1/2 notes or 1/64 notes

R=raw_input().split()
for y in range(10):
 r=""
 for x in R:o=y-(5-ord(x[0]))%7;b=" -"[y&1]+"O\|";r+=b[0]+b[o==3]+b[-(-1<o<3)]+b[2*(-1<o<":862".find(x[-1]))]
 print r

Python 186 characters <<o>>

Python uses the <<o>> evil eye operator to great effect here. The find() method returns -1 if the item is not found, so that is why D doesn't need to appear in the notes.


R=raw_input().split()
for y in range(10):
 r=""
 for x in R:o='CBAGFE'.find(x[0])+4;B=" -"[y%2];r+=B+(B,'O')[o==y]+(x[2:]and
y+4>o>y and"|"+(B,'\\')[int(x[2:])<<o>>6+y>0]or B*2)
 print r

11 extra bytes gives a version with half notes


R=raw_input().split()
for y in range(10):
 r=""
 for x in R:t='CBAGFE'.find(x[0])+4;l=x[2:];B=" -"[y%2];r+=B+(B,'@O'[l
in'2'])[t==y]+(l and y+4>t>y and"|"+(B,'\\')[int(l)>>(6+y-t)>0]or B*2)
 print r
$ echo B B/2 B/4 B/8 B/16 B/32 G/4 D/8 C/16 D B/16| python notes.py 
                              |\            
------------------------------|---|\--------
      |   |   |\  |\  |\      |   |\      |\
------|---|---|---|\--|\-----@----|--O----|\
      |   |   |   |   |\  |      @        | 
-O---O---@---@---@---@----|--------------@--
                          |                 
-------------------------@------------------

--------------------------------------------