36

The challenge

The shortest code by character count, that will output musical notation based on user input.

Input will be composed of a series of letters and numbers - letters will represent the name of the note and the number will represent the length of the note. A note is made of 4 vertical columns. The note's head will be a capital O, stem, if present will be 3 lines tall, made from the pipe character |, and the flag(s) will be made from backward slash \.

Valid note lengths are none, 1/4 of a note, 1/8 of a note, 1/16 of a note and 1/32 of a note.

       |    |\    |\    |\
       |    |     |\    |\
       |    |     |     |\
 O    O    O     O     O
 1   1/4  1/8  1/16   1/32

Notes are places on the Staff, according to their note name:

  ----

D ----
C     
B ----
A     
G ----
F     
E ----

All input can be assumed to be valid and without errors - Each note separated with a white space on a single line, with at least one valid note.

Test cases

Input:
    B B/4 B/8 B/16 B/32 G/4 D/8 C/16 D B/16
Output:
                              |\               
    --------------------------|---|\--------
          |   |\  |\  |\      |   |\      |\
    ------|---|---|\--|\-----O----|--O----|\
          |   |   |   |\  |      O        | 
    -O---O---O---O---O----|--------------O--
                          |                 
    ---------------------O------------------

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

Input:
    E/4 F/8 G/16 A/32 E/4 F/8 G/16 A/32 
Output:

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

    --------------|\--------------|\
              |\  |\          |\  |\ 
    ------|\--|\--|\------|\--|\--|\
      |   |   |  O    |   |   |  O  
    --|---|--O--------|---|--O------
      |  O            |  O          
    -O---------------O--------------

Input:
    C E/32 B/8 A/4 B F/32 B C/16
Output:

    ------------------------------|\
              |\                  |\
    ----------|---|---------------|-
     O        |   |              O   
    ---------O----|--O----|\-O------
          |\     O        |\        
    ------|\--------------|\--------
          |\             O           
    -----O--------------------------

Code count includes input/output (i.e full program).

LiraNuna
  • 64,916
  • 15
  • 117
  • 140
  • This is becomind pointless (i.e. the result doesn't look like anything resembling notes ...) – Rook Oct 15 '09 at 21:14
  • 2
    @Idigas - fixed, SO's preview != final output – LiraNuna Oct 15 '09 at 21:15
  • Please add comments about input spec (e.g. all input can assume to be well-formed, with single space between each note, on a single line; there will be at least one note). – Brian Oct 15 '09 at 21:23
  • Is it just me, or does this not seem especially "golf-able"? – Ben Blank Oct 15 '09 at 21:32
  • 2
    @Ben Blank: People said that about Lasers and Morse code too :) – LiraNuna Oct 15 '09 at 21:36
  • First test output is produced from `D/8 C/16` not `D/16 C/8` – mob Oct 15 '09 at 21:59
  • @mobrule: Thanks for capturing that! – LiraNuna Oct 15 '09 at 22:02
  • @LiraNuna — Fair enough. :-) – Ben Blank Oct 15 '09 at 22:09
  • 6
    I think it's an awesome code golf! Very original! – Sander Versluys Oct 15 '09 at 22:44
  • 2
    For a second, I thought this was about Lotus Notes! Eek! :O – jasonh Oct 15 '09 at 22:50
  • @mmr: That was in the original idea, but it was too complicated to be added, so I had to simplify it. – LiraNuna Oct 15 '09 at 23:54
  • we could use O for whole/half notes and @ for shorter ones – John La Rooy Oct 15 '09 at 23:58
  • 3
    I don't want to change the spec. Challenge is made. I know how to design my challenges and don't do it lightly. – LiraNuna Oct 15 '09 at 23:59
  • @LiraNuna, i've added that version to my answer. Turned out to be only 10 extra bytes. I know you can't change the challenge after it starts. – John La Rooy Oct 16 '09 at 00:10
  • @gnibbler, I added support myself and it was but seven characters. ;D – strager Oct 16 '09 at 00:19
  • 10
    @Noldorin: Please, oh PLEASE, stop changing the title. while you're at it, why won't we change all of my golf questions to "Code Golf: Determine if the laser hits the target" or even "Code Golf: Seven Segment display in ASCII art using _ and |". This is ridiculous. I see no one complaining about the title. – LiraNuna Oct 16 '09 at 21:12
  • 4
    How about "Musical Notes", at least? As it is, the title barely gives a clue about the content. – Michael Myers Oct 16 '09 at 22:03
  • 2
    @LiraNuna: Thank you so much for posting weekly golf challenges! They are very well-designed, and I have very much enjoyed both golfing myself and watching others. – A. Rex Oct 17 '09 at 21:05
  • @LiraNuna: Sorry if it irritates you, but it's part of the job of cleaning up the site. Questions should have semi-informative titles, and "Notes" doesn't quite do it. Consider yourself lucky this "question" is still open. Anyway, mmyers's suggestion is a good compromise, I think. – Noldorin Oct 17 '09 at 22:23
  • 2
    This is a fantastic challenge. Too bad us users of more verbose languages have to compete against perl! – Callum Rogers Oct 19 '09 at 22:46
  • @Rogers, Pfft. Perl wasn't competition. It was more like letting other people think they have a chance until Golfscript comes along. =] – strager Oct 20 '09 at 02:29

12 Answers12

23

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}%
strager
  • 88,763
  • 26
  • 134
  • 176
22

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
mob
  • 117,087
  • 18
  • 149
  • 283
  • 2
    split//,"D3C4B5A6G7F8E9" -> "D3C4B5A6G7F8E9"=~/./g –  Oct 16 '09 at 07:36
  • 2
    @Kinopiko, it's generally frowned upon to perform optimizations on other people's solutions. You can write a comment (as you did), but please don't edit answers unless they say it's okay. – strager Oct 16 '09 at 12:41
  • 2
    grep -> map for one less character. –  Oct 16 '09 at 17:34
  • For those par 5 fancy text formatting holes, Perl is definitely a 1-wood. – mob Oct 17 '09 at 04:04
  • 16
    I'd seriously would like to a read a lengthy step-by-step article of the process the Perl hacker's mind goes through when creating something like this. – Esko Oct 17 '09 at 20:33
  • @mobrule: Using tons of tricks, I can golf yours down to 152 characters: `$\=$/;for(split$",<>){y@DCBAGFE/@3-9,@;($N,$L)=eval;$o[$_].=($p=$N-$_)?$L*$p>0&$p<4?16<$p*$L?" |\\":" | ":$"x4:" O "for 0..9}$|--&&y@ @-@,print for@o` (as in another golf challenge, you have to fix the string constants because spaces got lost) – A. Rex Oct 17 '09 at 22:39
  • @mobrule: 143 now: `@o=($/)x10;for(split$",<>){$N=4+(5-ord)%7;s@.*/@@;$L=$_;$_.=--$N?$L*$N>0&$N<4?16<$N*$L?" |\\":" | ":$"x4:" O "for@o}$|--&&y@ @-@,print for@o` (spaces wrong as always) – A. Rex Oct 17 '09 at 23:58
  • 146! Nice move getting rid of the `$c`ounter variable I had! – mob Oct 18 '09 at 00:01
  • `($L)=m:\d+:g` instead of `s@.*/@@;$L=$_` for 142 – mob Oct 18 '09 at 00:05
  • @mobrule: 136 now!! `@o=($/)x10;for(split$",<>){$N=4+(5-ord)%7;/\/|$/;$_.=--$N?$'*$N>0&$N<4?16<$N*$'?" |\\":" | ":$"x4:" O "for@o}$|--&&y@ @-@,print for@o` (spaces wrong as always) – A. Rex Oct 18 '09 at 00:07
  • Esko: you start with full-sized code that works, then think of tricks to reduce the size. The important point is to get it working first before golfing it. –  Oct 18 '09 at 04:14
  • @Kinopiko, Really? I do the reverse with my solutions. – strager Oct 18 '09 at 04:14
  • 4
    You golf it then debug? Crikey! –  Oct 18 '09 at 04:20
  • Arg..I just got ruby down to 136 and you move the goalpost again! – John La Rooy Oct 19 '09 at 05:22
  • @mobrule: Your new code is amazing! But I don't know why you put the `$'` club away: change your pattern to `/\//` or `m'/'` (whichever you prefer), use `$'` again instead of `$&`, and save one stroke. – A. Rex Oct 19 '09 at 09:19
  • @A. Rex - I thought the script broke when I got rid of the `|$`, but I guess not. – mob Oct 19 '09 at 13:34
  • @mobrule regarding `|$`: It depends on block structure. Both `$&` and `$'` are only set after a successful match, which is bad for our situation because we want them unset after failure; however, they're local to the current block, so depending on that, the code might still work. (You need this for the `/\d+/` actually.) Incidentally, for some versions of the code, `/../` worked fine as a pattern (using `$'`) regardless of block structure because it successfully matched no matter what. – A. Rex Oct 19 '09 at 13:40
  • @mobrule: 121 characters with `#!perl -ap\n$\="$:\n"x5;$p=4+(5-ord)%7,s#..##,$\=~s#(.)\K$#--$p?$_*!($p&~3)?"$1|".(16<$p*$_?"\\":$1).$1:$1x4:O.$1x3#gemfor@F` after replacing both occurrences of `\n` with literal newlines. – A. Rex Oct 19 '09 at 16:09
  • @A. Rex: by my count, that's actually 122, unfortunately. However, you can save yourself a few more: remove the `#!perl -ap\n` from the script (-11), and add `-ap ` (+4) to the command line. Gives a total savings of 7, and a final script of 115. – Robert P Oct 19 '09 at 16:58
  • I don't know if I should allow switches. Not because I'm evil, but because I can do something like `gcc -DA=somecode` – LiraNuna Oct 19 '09 at 20:36
  • @Robert P: You're right that it's 122 -- oops. @LiraNuna: This coincides with how it's scored in Perl golf competitions. I don't know if you should allow it here (you're the MC!), although I think it'd be cool to see what other languages can do with switches and every time I've participated I wanted switches. I do think it's remarkable that I can get savings even if I have to write the `#!perl ` though. – A. Rex Oct 19 '09 at 21:42
  • @LiraNuna, the perl golf guys used to count any characters past "perl" including the whitespace as part of the solution – John La Rooy Oct 19 '09 at 21:43
  • By the way, if people don't know: if you have `#!perl [switches]` on the first line of a Perl program, you don't actually need the shell to interpret the switches. Perl will read them and apply them itself. So even if command-line switches aren't allowed, shebang ones definitely are -- it's part of the language you get when you just run `perl`. – A. Rex Oct 19 '09 at 21:45
  • That `-a` would be nice to have in other languages though for only 3 strokes! – John La Rooy Oct 19 '09 at 21:51
  • Thing is, we have two solutions that can win, depend on those rules. I think it would be fair to use the 122 chars solution (shebang used) as the answer, because I find it fair - especially since we count *"The shortest code by character count"* – LiraNuna Oct 19 '09 at 22:50
  • Just wait until I get 114 chars. Then we won't have to worry about this. =] – strager Oct 19 '09 at 23:26
15

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.... :)

KirarinSnow
  • 1,062
  • 2
  • 9
  • 22
  • 2
    Wow, just wow. Though the point is ASCII printing of patterns :). Still **wow** – LiraNuna Oct 18 '09 at 07:08
  • 1
    I should mention that LilyPond is a music typesetting engine (http://lilypond.org/web). It has a built-in Scheme interpreter, but amazingly enough can still manage to beat Scheme on some golfing tasks (see http://stackoverflow.com/questions/1433263/decision-tree-code-golf/1584216#1584216) – KirarinSnow Oct 18 '09 at 09:35
14

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);}
strager
  • 88,763
  • 26
  • 134
  • 176
14

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---@---@---@---@----|--------------@--
                          |                 
-------------------------@------------------

--------------------------------------------
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
9

159 Ruby chars

n=gets.split;9.downto(0){|p|m='- '[p%2,1];n.each{|t|r=(t[0]-62)%7;g=t[2..-1]
print m+(r==p ?'O'+m*2:p>=r&&g&&p<r+4?m+'|'+(g.to_i>1<<-p+r+5?'\\':m):m*3)}
puts}
Paige Ruten
  • 172,675
  • 36
  • 177
  • 197
7

Ruby 136

n=gets;10.times{|y|puts (b=' -'[y&1,1])+n.split.map{|t|r=y-(5-t[0])%7
(r==3?'O':b)+(t[1]&&0<=r&&r<3?'|'<<(r<t[2,2].to_i/8?92:b):b+b)}*b}

Ruby 139 (Tweet)

n=gets;10.times{|y|puts (b=' -'[y&1,1])+n.split.map{|t|r=y-(5-t[0])%7
(r==3?'O':b)+(t[1]&&0<=r&&r<3?'|'<<(r<141>>(t[-1]&7)&3?92:b):b+b)}*b}

Ruby 143

n=gets.split;10.times{|y|puts (b=' -'[y&1,1])+n.map{|t|r=y-(5-t[0])%7;m=t[-1]
(r==3?'O':b)+(m<65&&0<=r&&r<3?'|'<<(r<141>>(m&7)&3?92:b):b+b)}*b}

Ruby 148

Here is another way to calculate the flags,
where m=ord(last character), #flags=1+m&3-(1&m/4)

and another way #flags=141>>(m&7)&3, that saves one more byte

n=gets.split;10.times{|y|b=' -'[y&1,1];n.each{|t|r=y-(5-t[0])%7;m=t[-1]
print b+(r==3?'O':b)+(m<65&&0<=r&&r<3?'|'<<(r<141>>(m&7)&3?92:b):b+b)}
puts}

Ruby 181

First try is a transliteration of my Python solution

n=gets.split;10.times{|y|r="";n.each{|x|o=y-(5-x[0])%7
r+=(b=" -"[y&1,1]+"O\\|")[0,1]+b[o==3?1:0,1]+b[-1<o&&o<3&&x[-1]<64?3:0,1]+b[-1<o&&o<(":862".index(x[-1]).to_i)?2:0,1]}
puts r}
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
6

F#, 458 chars

Reasonably short, and still mostly readable:

let s=Array.init 10(fun _->new System.Text.StringBuilder())
System.Console.ReadLine().Split([|' '|])
|>Array.iter(fun n->
for i in 0..9 do s.[i].Append(if i%2=1 then"----"else"    ")
let l=s.[0].Length
let i=68-int n.[0]+if n.[0]>'D'then 7 else 0
s.[i+3].[l-3]<-'O'
if n.Length>1 then
 for j in i..i+2 do s.[j].[l-2]<-'|'
 for j in i..i-1+(match n.[2]with|'4'->0|'8'->1|'1'->2|_->3)do s.[j].[l-1]<-'\\')
for x in s do printfn"%s"(x.ToString())

With brief commentary:

// create 10 stringbuilders that represent each line of output
let s=Array.init 10(fun _->new System.Text.StringBuilder())
System.Console.ReadLine().Split([|' '|])
// for each note on the input line
|>Array.iter(fun n->
// write the staff
for i in 0..9 do s.[i].Append(if i%2=1 then"----"else"    ")
// write note (math so that 'i+3' is which stringbuilder should hold the 'O')
let l=s.[0].Length
let i=68-int n.[0]+if n.[0]>'D'then 7 else 0
s.[i+3].[l-3]<-'O'
// if partial note
if n.Length>1 then
 // write the bar
 for j in i..i+2 do s.[j].[l-2]<-'|'
 // write the tails if necessary
 for j in i..i-1+(match n.[2]with|'4'->0|'8'->1|'1'->2|_->3)do s.[j].[l-1]<-'\\')
// print output
for x in s do printfn"%s"(x.ToString())
Brian
  • 117,631
  • 17
  • 236
  • 300
4

Lua, 307 Characters

b,s,o="\\",io.read("*l"),io.write for i=1,10 do for n,l in
s:gmatch("(%a)/?(%d*)")do x=n:byte() w=(x<69 and 72 or 79)-x
l=tonumber(l)or 1 d=i%2>0 and" "or"-"o(d..(i==w and"O"or
d)..(l>3 and i<w and i+4>w and"|"or d)..(l>7 and i==w-3
and b or l>15 and i==w-2 and b or l>31 and i==w-1 and b or
d))end o"\n"end
gwell
  • 2,695
  • 20
  • 20
4

C 196 characters <<o>>

Borrowing a few ideas off strager. Interesting features include the n+++1 "triple +" operator and the <<o>> "evil eye" operator

#define P,putchar
N[99];*n=N;y;b;main(o){for(;scanf(" %c/%d",n,n+1)>0;n+=2);for(;y<11;)
n=*n?n:(y++P(10),N)P(b=y&1?32:45)P((o=10-(*n+++1)%7-y)?b:79)P(0<o&o<4&&*n?'|':b)
P(*n++<<o>>6&&0<o&o<4?92:b);}
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • I managed to get 196 when SO was down but couldn't post. Your solution (well, modifications of mine) has hinted me at more optimizations. Thanks, but I'm gonna win this one. ;D – strager Oct 16 '09 at 12:25
  • 1
    Ahh, but will you have the evil eye? and the triple +? :) – John La Rooy Oct 16 '09 at 12:51
  • `scanf(" %c/%d",n,n+1)+1` is not portable because by the standard `EOF` must be `< 0` (thus *may* be `-1`). Use `>0` like in my answer (or `>=0` if needed). – strager Oct 16 '09 at 21:41
  • @gnibbler, Yes, I will by the end of today (EST). I really want to beat that Perl solution! – strager Oct 16 '09 at 23:01
  • you should explain the `n+++1` and the `<>` operators and what they do (and mention if it is undefined/implementation defined behavior) – Evan Teran Oct 19 '09 at 05:30
  • It's really `*n+++1` and it is a combination of `n++` and `*n+1`, so give me whatever n is pointing to plus one and then increment n to point at the next character. The evil eye is `<>6` so left shift by `o` and right shift by `6`. Standard C meaning, just unusual to see it. – John La Rooy Oct 19 '09 at 06:06
  • 1
    @Evan Teran: more examples of that kind would be the 'goes forward operator': `while(x --> 0)`, which actually means `while(x-- > 0)`, and the 'cast to boolean operator': `!!integer`, which does what you think it does :) – LiraNuna Oct 19 '09 at 21:09
4

168 characters in Perl 5.10

My original solution was 276 characters, but lots and lots of tweaking reduced it by more than 100 characters!

$_=<>;
y#481E-GA-D62 #0-9#d;
s#.(/(.))?#$"x(7+$&).O.$"x($k=10).($1?"|":$")x3 .$"x(10-$2)."\\"x$2.$"x(9-$&)#ge;
s#(..)*?\K (.)#-$2#g;
print$/while--$k,s#.{$k}\K.#!print$&#ge

If you have a minor suggestion that improves this, please feel free to just edit my code.

A. Rex
  • 31,633
  • 21
  • 89
  • 96
1

C -- 293 characters

Still needs more compression, and it takes the args on the command line instead of reading them...

i,j,k,l;main(c,v)char **v;{char*t;l=4*(c-1)+2;t=malloc(10*l)+1;for(i=0;i<10;i
++){t[i*l-1]='\n';for(j=0;j<l;j++)t[i*l+j]=i&1?'-':' ';}t[10*l-1]=0;i=1;while
(--c){j='G'-**++v;if(j<3)j+=7;t[j*l+i++]='O';if(*++*v){t[--j*l+i]='|';t[--j*l
+i]='|';t[--j*l+i]='|';if(*++*v!='4'){t[j++*l+i+1]='\\';if(**v!='8'){t[j++*l+
i+1]='\\';if(**v!='1'){t[j++*l+i+1]='\\';}}}}i+=3;}puts(t);}

edit: fixed the E

edit: down to 293 characters, including the newlines...

#define X t[--j*l+i]='|'
#define Y t[j++*l+i+1]=92
i,j,k,l;main(c,v)char**v;{char*t;l=4*(c-1)+2;t=malloc(10*l)+1;for(i=10;i;)t[--i*
l-1]=10,memset(t+i*l,i&1?45:32,l-1);t[10*l-1]=0;for(i=1;--c;i+=3)j=71-**++v,j<3?
j+=7:0,t[j*l+i++]=79,*++*v?X,X,X,*++*v-52?Y,**v-56?Y,**v-49?Y:0:0:0:0;puts(t);}
Chris Dodd
  • 2,920
  • 15
  • 10