The Note of Destiny - place a note on a staff

19

5

The zombie apocalypse has come, and the world is coming to an end. Suddenly, someone discovers a formula that takes the current hour, minute, and day, and spits out the perfect note to play on a piano that instantly kills every zombie that hears it. Unfortunately, there is only one piano player left in the world, and he has forgotten how to read notes, but he still knows how to read sheet music. Of course, this is a very time-sensitive thing, so it seems natural to have a computer do it.1

Your challenge is to take a note, such as G, and output the note placed on a staff (in treble clef), like this:

-----

-----
   |
---|-
   |
--O--

-----

Specification:

  • You must output a staff of alternating lines of ----- (5 dashes) and a blank line. There will be 5 -----s total. The note must be superimposed on top of this staff.
  • The input will specify where the note is located. The input will be:
    • an optional H or L, specifying "high" or "low"
    • a letter from A to G, specifying the pitch
    • an optional # or b, specifying sharp or flat.
  • The "note" is defined as:
    • One O (capital O) aligned to the middle of the staff, which is in the place of the note. (The top line is HF (high F), and the bottom line is E (a normal E).)
    • Three |s (vertical bars), the stem, which will be:
      • one space to the left of the note and going downwards (starting one space below the note) if the note is on the middle line (B) or above, or
      • one space to the right of the note and going upwards (starting one space above the note) if the note is below the middle line.
    • A # or b one space directly to the left of the note if specified in the input.
  • Ledger lines must be added if the note is too high or low. These lines will be --- (only 3 dashes in width, as opposed to 5) and will only appear if the note is on or above/below (for top/bottom ledger lines respectively) the ledger lines.
  • Extraneous spaces may be placed anywhere you want; for example, you could make the blank lines have spaces or have a space after the ledger lines if it helps you save any characters.

Here is a visualization, to understand the specification more easily, with all the note names next to the lines:

      HB
 ---  HA
      HG
----- HF
      HE
----- HD
      HC
----- B
      A
----- G
      F
----- E
      D
 ---  C
      LB
 ---  LA
      LG
 ---  LF
... (bottom cut off for brevity, you get the idea anyway)

Here are some more examples that you can use to test your program:

Input: HG#

 #O
-|---
 |
-|---

-----

-----

-----

Input: LAb

-----

-----

-----

-----

-----
   |
 --|
   |
 bO-

Input: HB

  O
 |--
 |
-|---

-----

-----

-----

-----

Input: C

-----

-----

-----

-----
   |
---|-
   |
 -O-

This is , so the shortest code in bytes will win!

1: most realistic exposition evar! :-P

Doorknob

Posted 2014-03-23T20:57:27.480

Reputation: 68 138

2It looks very strange to have # or b at the right of the note rather than at the left; is it really what is required? – Thomas Baruchel – 2014-03-23T21:16:53.983

@ברוכאל No; that's just me not thinking properly ;-) edited – Doorknob – 2014-03-23T21:18:52.603

You have two HC's in your Visualization. I assume the top one should be deleted, as you make no mention of HHC (double high) in the rest of the specification. – Level River St – 2014-03-23T22:27:58.967

@steve Oops; also a mistake. Edited – Doorknob – 2014-03-23T22:29:01.213

2What about B# and the like? 1. plot as-is; 2. reject; 3. silently convert to C? – Digital Trauma – 2014-03-23T22:42:58.220

@DigitalTrauma Plot those too; I've played B#s and E#s in my experience with piano before. (I've even played double sharps, but that's outside the scope of the challenge. ;-)) – Doorknob – 2014-03-23T22:44:31.503

2It may be better to explicitly state that it should be in treble clef. – user12205 – 2014-03-24T03:10:52.457

To clarify, by "on or above/below ... them" you mean the ledger lines, or alternately the pitches represented by the ledger lines. – couchand – 2014-03-24T03:39:46.507

@ace Of course; edited. – Doorknob – 2014-03-24T03:56:05.507

@couchand I thought that would be implied, but it's always good to be specific ;-) edited – Doorknob – 2014-03-24T03:56:55.627

How about your "blank line" requirement? Must it be be an absolutely empty line if there is no note or could it be four/five spaces? – Martin Ender – 2014-03-24T21:03:10.627

1@m.buettner Added an extra rule at the end of the specification to clarify. – Doorknob – 2014-03-24T21:24:24.990

Does it have to be text output? We should be able to render it as an image if we want. – AJMansfield – 2014-03-25T16:14:50.237

3

Anyone up to attempting this in Fugue?

– AJMansfield – 2014-03-25T16:18:10.577

3@AJM Yes, it has to be ASCII art. – Doorknob – 2014-03-25T17:02:09.910

Answers

1

Golfscript, 211 210 209 197 195 192 characters

Coming in for the (as of this post) win, a GolfScript version of my latest Python version:

"J"\+[0]+.1=71>>3<{}/@7*2/246-@3+7%-:z;:c;21,{..3z<3z
if<\11z>11z
if>|{;}{...2>\12<&\2%.{'-'' 'if}:Q~:9;&Q\.z={c!9{[c]''+}if}{..z>\4z+<&8z>&'|'9if}if\.z='o'9if\..z
4-\<\z<&7z<&'|'9if\;3$n}if}/

Test it out here (first 2 lines are user-input, normally it comes from stdin).

'Readable' version:

;"HCb"

"J"\+[0]+       #process input
.1=71>>3<       #first char is HJL, second is letter, third is #b or space
{}/             #spill chars onto stack, now we working with ints
@7*2/246-@3+7%- #convert HC/JD/LE etc to a number from 0 to 20
:z;:c;
21,{            #for r in range(21):
  ..3z<3z if<           #either out-of-bounds or process the line
  \11z>11z if>|
  {;}{
    ...2>\12<&\2%.{'-'' 'if}:Q~:9;&Q\        #1st char
    .z={c!9{[c]''+}if}                       #2nd char accidental
       {..z>\4z+<&8z>&'|'9if}if\            #2nd char stem or row
    .z='o'9if\                              #3rd char
    ..z 4-\<\z<&7z<&'|'9if\                 #4th char stem or row
    ;3$                                      #5th char=1st char
    n
  }if
}/

Claudiu

Posted 2014-03-23T20:57:27.480

Reputation: 3 870

Aaaaaaand beaten by GolfScript again. :) ... – Martin Ender – 2014-03-25T21:47:26.950

@m.buettner: Haha, it never ends.. surprisingly close though! – Claudiu – 2014-03-25T21:49:06.113

1Better! Now I only need to find 6/9 bytes to catch up :D (although I don't see how I would do that) – Martin Ender – 2014-03-25T21:56:00.293

@m.buettner: Got 2 more bytes down! Each one is so brutal though... I might have to stop for now. Good luck! – Claudiu – 2014-03-25T22:20:39.557

I got 4 because I had an unnecessary variable left from some previous version. But now it seems really hard to go any further without actually trying some completely different algorithm. – Martin Ender – 2014-03-25T22:28:14.000

2Oh bloody hell... just when I thought I had beaten your 209. I think I'm giving up. GolfScript prevails. ;) – Martin Ender – 2014-03-25T23:41:09.987

@m.buettner: All hail the golfscript! I'm seriously impressed by your ruby effort though, usually it's nowhere close... I think this problem was just on the cusp of not being well-suited for golfscript (not all problems are). I have dreams of making Golfscript+, which also uses characters 128-255, to make one-byte functions of common operations (e.g. so if is one byte, a version of : which consumes the variable, etc...). I guess that would just be APL though.. – Claudiu – 2014-03-25T23:45:02.037

6

Ruby – 271 267 252 249 234 229 220 214 characters

I literally just learned Ruby for this. So there is certainly room for improvement in golfing it down. Or doing anything really. But I needed a language with mutable strings. :)

def f(n)s=[0]*20
s.fill{|i|i%2>0?i<3||i>11?" ---":?-*5:" "*5}
s[l=(3-n[(p="H_L".index n[0])?1:0].ord)%7+7*(p||1)][1,2]=("#b"[n[-1]]||s[l][1])+?O
s[l+3-2*o=l>7?3:1,3].map{|t|t[o]=?|}
puts s[[3,l].min..[11,l].max]end

Somewhat ungolfed:

def f(note)
  staff=[]
  0.step(20) {|i| staff[i] = " "*5}
  1.step(19,2) {|i| staff[i] = " ---"}
  3.step(11,2) {|i| staff[i] = "-"*5}
  level = 7
  if !(pos="HL".index note[i=0]).nil?
    level = 14*pos
    i += 1
  end
  level += (73-note[i].ord)%7
  staff[level][2] = "O"
  mark = note[-1]
  if !"#b".index(mark).nil?
    staff[level][1] = mark
  end
  offset = (level > 7) ? 3 : 1
  staff[level-2*offset+3,3].map {|line| line[offset] = "|"}
  first = [3,level].min
  last = [11,level].max
  puts s[first..last]
end

I can cut it by another 2 characters down to 212 characters if leading blank lines are allowed. This solution doesn't fill the lines that aren't printed anyway:

def f(n)s=[]
[3,l=(3-n[(p="H_L".index n[0])?1:0].ord)%7+7*(p||1)].min.step(l>11?l:11){|i|s[i]=i%2>0?i<3||i>11?" ---":?-*5:" "*5}
s[l][1,2]=("#b"[n[-1]]||s[l][1])+?O
s[l+3-2*o=l>7?3:1,3].map{|t|t[o]=?|}
puts s
end

Are lambda's fair game? Then I can get 210 characters with the first approach

f=->n{s=[0]*20
s.fill{|i|i%2>0?i<3||i>11?" ---":?-*5:" "*5}
s[l=(3-n[(p="H_L".index n[0])?1:0].ord)%7+7*(p||1)][1,2]=("#b"[n[-1]]||s[l][1])+?O
s[l+3-2*o=l>7?3:1,3].map{|t|t[o]=?|}
puts s[[3,l].min..[11,l].max]}

Or 207 characters with additional blank lines:

f=->n{s=[]
[3,l=(3-n[(p="H_L".index n[0])?1:0].ord)%7+7*(p||1)].min.step(l>11?l:11){|i|s[i]=i%2>0?i<3||i>11?" ---":?-*5:" "*5}
s[l][1,2]=("#b"[n[-1]]||s[l][1])+?O
s[l+3-2*o=l>7?3:1,3].map{|t|t[o]=?|}
puts s}

Of course, now you'd need to do f.call("HGb").

Martin Ender

Posted 2014-03-23T20:57:27.480

Reputation: 184 808

Ha, +1 for learning an entirely new language! ;-) Here's a tip: !x.nil? is equivalent to !x. And for one line ifs, if x;y;end; is equivalent to y if x. Also you can use a literal newline in that string. – Doorknob – 2014-03-25T01:13:34.013

@Doorknob thanks, I'll try to work those in! – Martin Ender – 2014-03-25T01:16:00.323

@Doorknob hm, I only got the if to work. If I use ?\n (if that's what you meant) I need to add a space, so I gain nothing. And removing the .nil?s didn't work at all (always evaluated to true). – Martin Ender – 2014-03-25T01:28:48.443

I meant literally adding a newline between the two quotes. And I think you need extra parens when removing .nil?, but it's worth it in characters. – Doorknob – 2014-03-25T01:29:50.887

@Doorknob ah, no !x.nil? is !!x. :) – Martin Ender – 2014-03-25T01:36:11.110

Whoops, that's right. I think !!!!!!!!x is the best way though. (Actually, 42 !s is.) :P – Doorknob – 2014-03-25T01:36:48.560

My comment was meant as a joke. !!x is the same as x. ;) – Doorknob – 2014-03-25T01:44:28.543

@Doorknob. oh, I somehow thought if needs a boolean. thinking about it, that doesn't make sense in a language that has a concept of truthy and falsy. I'll fix it tomorrow. – Martin Ender – 2014-03-25T01:58:09.990

2

Python, 329 309 295 286 280 277 characters

Golfed a bit more now. Still can be improved, but not sure if I can beat out the ruby or golfscript solutions with this approach.

R=range
N='J'+raw_input()+' '
X=N[1]>'G'
a,b,c=N[X:3+X]
z=266-ord(a)/2*7+(ord(b)-4)%7
Z=[list((' '*5,(' ---','-'*5)[8<r<18])[r%2])for r in R(21)]
Z[z][2]='o'
if' '<c:Z[z][1]=c
Q=(z<13)*2
for i in(1,2,3):Z[z+i*Q-i][Q+1]='|'
for r in R(max(17,z),min(z-1,8),-1):print''.join(Z[r])

Initially I was printing out line-by-line, but it turned out to take too much, so I generate a string grid and then fill in what needs be filled in. Input is from command line, e.g.:

>echo HG# | python note2_golf.py
 #o
-|---
 |
-|---

-----

-----

-----

Claudiu

Posted 2014-03-23T20:57:27.480

Reputation: 3 870

In line 5 you can remove the space before the second comma – user12205 – 2014-03-24T06:47:35.800

@ace: Thanks, missed that one – Claudiu – 2014-03-24T06:52:24.457

2

GolfScript - 243 232 228 227 characters

I translated my CoffeeScript answer into GolfScript, which is much more suited to the string manipulations.

EDIT: Saved six characters by properly using the increment operator, three by making good use of the stack, six more by irresponsibly redefining operators I'm not using, and one more by not printing the trailing space after grace lines.

Entirely golfed:

..0="HL"?2+3%:o)2%.@="CDEFGAB"?7o*+:`2%45 32if:r;
).2$,<{=}{;;r}if:&;
[" "5*:|" ---":g]4*[|"-"5*]5*+[|g|]+.
[`<~]\[`>([0=:^&79r^]''+\~]
+17`<`)18if<9`>`9if:j>:t 13`>.2*):x;
4,1>{`j-\2${+}{-}if}%\;
{.@<\t>(:v[x<'|'+x)v>+]\++:t}
/-1%n*

With comments:

# extract octave
..0="HL"?2+3%:o

# extract note
2%1\-.@="CDEFGAB"?7o*+:k

# line spacer
2%45 32if:r;

# extract accidental
1+.2$,<{=}{;;r}if:a;

# staff
[" "5*:|" --- ":g]4*[|"-"5*]5*+[|g|]+.

# lines below
[k<~]\

# note line and above
[k>([0=:w a 79r w]''+\~]+

# cut off just what we need
17k<1k+18if<
9k>k 9if:j>:t;

# and the note stem
13k>.2*1+:x;4,1>{k j-\2${+}{-}if}%\;

{
  .t<\
  t>(:v[x<'|'+1x+v>+]\++:t;
}/

# now output the note
t-1%n*

couchand

Posted 2014-03-23T20:57:27.480

Reputation: 296

I would have been astonished if I could beat a GolfScript solution in a language that I have no experience in ;) – Martin Ender – 2014-03-25T14:07:09.873

1I'm no GolfScript expert but I think I've eked out just about all the characters I'm going to get out of this, so if you can find another two, you're golden! – couchand – 2014-03-25T14:09:45.527

Try to type Go in it. it will output oo||| :) – Jamie – 2014-04-26T09:17:25.140

1

Java - 921 907 863 characters

I build up each string seperately, storing each string in an array. Then loop through the array and print out each line.

public class D{public static void main(String[]a){char[]z=a[0].toCharArray();char[]y=new char[3];y[0]=('H'==z[0]||'L'==z[0])?z[0]:'N';int o=(y[0]=='N')?0:1;y[1]=z[o++];y[2]=z.length>o?z[o]:'!';int n=y[1]<'C'?((int)(y[1]-'A'))+6:((int)(y[1]-'C'))+1;n=(y[0]=='N')?n+7:(y[0]=='H'?n+14:n);String s="     ";String b=" --- ";String[]u=new String[22];for(int i=1;i<=21;i+=2){u[i]=s;}for(int i=10;i<=18;i+=2){u[i]="-----";}u[20]=n>19?b:s;u[2]=n<3?b:s;u[4]=n<5?b:s;u[6]=n<7?b:s;u[8]=n<9?b:s;char c=u[n].charAt(0);char e=u[n].charAt(1);char[]h=new char[]{c,y[2]=='!'?e:y[2],'O',e,c};u[n]=new String(h);for(int i=0;i<22;i++){if(n<14&&i-n<4&&i>n)u[i]=u[i]!=null?u[i].substring(0,3)+"|"+u[i].charAt(4):s;else if(n>13&&n-i<4&&n>i)u[i]=u[i]!=null?u[i].substring(0,3)+"|"+u[i].charAt(4):s;}for(int i=21;i>=0;i--)if(!(i>n&&i>18||i<n&&i<10))System.u.println((u[i]==null)?s:u[i]);}}

Oh please don't hate me, it's my first time. I coulnd't find any faq/introduction so I hope my posting format is ok. Not sure how serious people got about character counts.... normal version of the code - extra is linebreak/spaces (1313 characters):

public class DisplayNote
{
  public static void main(String[] args)
  {
    char[] z=args[0].toCharArray();
    char[] y=new char[3];
    y[0]=('H'==z[0]||'L'==z[0])?z[0]:'N';
    int o=(y[0]=='N')?0:1;
    y[1]=z[o++];
    y[2]=z.length>o?z[o]:'!';

    int noteValue=y[1]<'C'?((int) (y[1] - 'A')) + 6:((int) (y[1] - 'C')) + 1;
    noteValue=(y[0]=='N')?noteValue+7:(y[0]=='H'?noteValue+14:noteValue);
    String s="     ";
    String b=" --- ";
    String[] out=new String[22];
    for (int i=1;i<=21;i+=2){out[i]=s;}
    for (int i=10;i<=18;i+=2){out[i]="-----";}
    out[20]=noteValue>19?b:s;
    out[2]=noteValue<3?b:s;
    out[4]=noteValue<5?b:s;
    out[6]=noteValue<7?b:s;
    out[8]=noteValue<9?b:s;

    char c=out[noteValue].charAt(0);
    char e=out[noteValue].charAt(1);
    char[] h=new char[]{c,y[2]=='!'?e:y[2],'O',e,c};
    out[noteValue]=new String(h);
    for (int i=0;i<22;i++)
    {
      if (noteValue<14&&i-noteValue<4&&i>noteValue)
        out[i]=out[i]!=null?out[i].substring(0,3)+"|"+out[i].charAt(4):s;
      else if (noteValue>13&&noteValue-i<4&&noteValue>i)
        out[i]=out[i]!=null?out[i].substring(0,3)+"|"+out[i].charAt(4):s;        
    }

    for (int i=21;i>=0;i--)
      if (!(i>noteValue&&i>18||i<noteValue&&i<10))
        System.out.println((out[i]==null)?s:out[i]);
  }
}

Will_61

Posted 2014-03-23T20:57:27.480

Reputation: 51

I see tons of unnecessary whitespace (especially after semicolons and around operators and brackets and parens) and long variable names (like args). – Doorknob – 2014-03-24T23:42:01.010

In the character counting submission: 921 characters, all whitespace is gone :P – Will_61 – 2014-03-24T23:43:10.127

The second submission with whitespace everywhere is to let people read the code, as I said it's my first time so not sure if we're meant to leave 1 submission and 1 where you try to reduce the character limit... or what? – Will_61 – 2014-03-24T23:44:13.620

No; I see an enormous amount of useless whitespace in that version. For example, spaces after semicolons, spaces around operators, spaces after [], spaces around parentheses, etc. – Doorknob – 2014-03-24T23:44:18.603

Removed them all now (I think) Thanks :) – Will_61 – 2014-03-24T23:57:55.960

If you rename out to o you can save another 2n characters (with n a reasonably sized integer). – CompuChip – 2014-03-25T15:05:20.753

1

Python, 250 245 242 235 characters

A very different approach which ended up beating out my other one! Input processing code is similar but that's about it.

M=' -'
N=raw_input()+M
a,b,c=('J'+N)[N>'G':][:3]
z=ord(a)*7/2-246-(ord(b)+3)%7
for r in range(21):
 L=M[r%2];F=M[2<r<12and r%2]
 if min(3,z)<=r<=max(11,z):print F+((L,'|')[8>z<r<z+4],(L,c)[M<c])[r==z]+(L,'o')[r==z]+(L,'|')[z-4<r<z>7]+F

I mapped out each character's value based on the row and column and then golfed the printing:

#given row r, with note on row n, how to print each char?
#rows are:
#       HB : 0
#  ---  HA : 1
#       HG : 2
# ----- HF : 3
#       HE : 4
# ----- HD : 5
#       HC : 6
# ----- B  : 7
#       A  : 8
# ----- G  : 9
#       F  : 10
# ----- E  : 11
#       D  : 12
#  ---  C  : 13
#       LB : 14
#  ---  LA : 15
#       LG : 16
#  ---  LF : 17
#       LE : 18
#  ---  LD : 19
#       LC : 20
#chars are:
# 0 | 1 | 2 | 3 | 4
#
# 0,4:
#    if r%2:
#      if 2<r<12: '-'
#      else ' '
#    else: ' '
# 1: ' -b#|'
#    if r==n:
#      if A: c
#      else: ' -'[r%2]
#    elif n<8 and n<r<n+4: '|'
#    else: ' -'[r%2]
# 2: ' -o'
#    if r==n: 'o'
#    else: ' -'[r%2]
# 3: ' -|'
#    if n>7 and n-4<r<n: '|'
#    else: ' -'[r%2]

Claudiu

Posted 2014-03-23T20:57:27.480

Reputation: 3 870

+1, Last line seems more Perl's black magic than Pythonic stuff – Antonio Ragagnin – 2014-03-26T13:14:03.227

1

Haskell 377C

import Data.Char
(<.)=elem
n(c:r)|elem c"HL"=let(s,a)=n r in(s+case c of 'H'->7;_-> -7,a)|1<2=(mod(ord c-67)7-2,case r of[]->' ';[x]->x)
r(s,a)y x=c where d|s>4= -1|1<2=1;c|x<.[0,4]&&(y<0||y>8)=' '|x==2&&y==s='o'|y==s&&x==1&&' '/=a=a|x==2+d&&y<.[s+k*d|k<-[1..3]]='|'|1<2="- "!!mod y 2
g p@(s,a)=unlines$[map(r p y)[0..4]|y<-reverse[min 0 s..max 8 s]]
main=getLine>>=putStr.g.n

Ungolfed version:

import Data.Char

fromName ('H':s) = let (step, alter) = fromName s in ((step + 7), alter)
fromName ('L':s) = let (step, alter) = fromName s in ((step - 7), alter)
fromName (x:s) = (mod (ord x - 67) 7 - 2, if null s then ' ' else head s)

renderChar :: (Int, Char) -> Int -> Int -> Char
renderChar (step, alter) y x = let
    dir = if step >  4 then -1 else 1
    normal = "- "!!mod y 2
    stemYs = [step + k * dir | k <- [1..3]]
    c | elem x [0,4] && not(elem y [0,2,4,6,8]) = ' '
      | x == 2 && y == step = 'o'
      | y == step && x == 1 && alter /= ' ' = alter
      | elem y stemYs && x == 2 + dir = '|'
      | otherwise = normal
  in c

render :: (Int, Char)-> String
render (step, alter) = unlines [map (renderChar (step, alter) y) [0..4] | y <- ys] 
  where
    ys = reverse [min 0 step .. max 8 step]

main = getLine >>= (putStr.render.fromName)

Ray

Posted 2014-03-23T20:57:27.480

Reputation: 1 946

0

Literate CoffeeScript - 497 527 characters

I'm sure there's a better way to build the grid but I can't figure it out.

One golf helper.

_=(q)->->q.split ""

A C major scale and staff.

s=_("CDEFGAB")()
l=_ "-----"
e=_ "     "
g=_ " --- "
t=->
  o=[e(),l(),e(),l(),e(),l(),e(),l(),e(),l(),e(),g(),e()]
  o.unshift e(),g() for [0..3]
  o

Our notation function will take the string representation of a note.

f=(i)->
  o=1
  m=t()

First we'll determine the octave.

  if /L|H/.test i[0]
    if i[0]=="L" then o=0 else o=2
    i=i[1..]

Then the note and accidental. Gotta love deconstructing assignment.

  [n,a]=i

Let's convert the note and octave to an index and plot the note.

  x=7*o+s.indexOf n

  m[x][1]=a if a
  m[x][2]='O'

Now we'll cut out only as much staff as we need.

  j=9
  k=17
  if x>17
    k=x
  else if x<9
    j=x
  u=x-j
  m=m[j..k]

And the note stem.

  if x<13
    m[x][3]='|' for x in [u+3...u]
  else
    m[x][1]='|' for x in [u-3...u]

Now let's output the results.

  m.map((p)->p.join '').reverse().join '\n'

Finally, we'll export the function for console testing. These characters don't count towards the total.

module.exports = f

couchand

Posted 2014-03-23T20:57:27.480

Reputation: 296

Looking closer it seems like I screwed up when refactoring the note stem, so it produces illegal output at the moment. – couchand – 2014-03-25T01:53:53.870

I fixed it, but it added 30 characters :-/ – couchand – 2014-03-25T05:00:44.197

0

C, 325 304

Now 21 bytes shorter thanks to @ace!

i;j;c;n;main(t){char
x[133];for(i;i<132;i++){x[i]="-----\n     \n"[i%12];if((i<18||i>77)&&!((i%12)&11))x[i]=32;}for(;!n;){c=getchar();if(c>71)t=c^72?2:0;else
n=7*t+7-(c-4)%7;}x[i=n*6+2]=79;if((c=getchar())>32)x[i-1]=c;for(t=0,j=n<9?i+5:i-17;t<3;t++,j+=6)x[j]='|';x[n<13?77:n*6+5]=0;puts(x+(n>4?24:n*6));}

Output:

./a.out
HBb
 bO  
 |-- 
 |   
-|---

-----

-----

-----

-----


./a.out
LG#
-----

-----

-----

-----

-----

 --| 
   | 
 --| 
 #O  

r3mainer

Posted 2014-03-23T20:57:27.480

Reputation: 19 135

Global variable are initialised to zero by default, so you don't need to initialise n and you can remove the i=0 in the first for loop. – user12205 – 2014-03-25T03:23:15.903

Also, in the first if statement, ((i%12)&11)==0 can be replaced with !((i%12)&11). – user12205 – 2014-03-25T03:26:22.170

Finally, ?: has a very lower precedence than ^ and <, so you can remove the brackets of the conditions before the ?. And you can replace printf("%s", with puts(. – user12205 – 2014-03-25T03:38:44.960

0

JavaScript 390 388

A bit of a challenge, I'll have to admit... I'm sure there's ways of reducing this further... I'm open to suggestions...

First Iteration

C=(a,x,o,c)=>{a[x]=a[x].substr(0,o)+c+a[x].substr(o+1)};l=7;s=[];for(i=21;i--;)s[i]="    ";for(j=1;19>j;j+=2)s[j]=" ---";for(k=3;12>k;k+=2)s[k]="-----";~(p="HL".indexOf((n=prompt())[i=0]))&&(l=14*p,i++);l+=(73-n.charCodeAt(i))%7;C(s,l,2,"O");m=n[n.length-1];"#"!=m&   "b"!=m||C(s,l,1,m);o=7<l?3:1;for(z=0;3>z;C(s,t=l-2*o+3+z++,o,"|"));S=s.splice(3<=l?3:l,11>=l?11:l);console.log(S.join("\n"))

Second Iteration (using n.slice(-1) instead of n[n.length-1]), shaves 2 bytes

C=(a,x,o,c)=>{a[x]=a[x].substr(0,o)+c+a[x].substr(o+1)};l=7;s=[];for(i=21;i--;)s[i]="    ";for(j=1;19>j;j+=2)s[j]=" ---";for(k=3;12>k;k+=2)s[k]="-----";~(p="HL".indexOf((n=prompt())[i=0]))&&(l=14*p,i++);l+=(73-n.charCodeAt(i))%7;C(s,l,2,"O");m=n.slice(-1);"#"!=m& "b"!=m||C(s,l,1,m);o=7<l?3:1;for(z=0;3>z;C(s,t=l-2*o+3+z++,o,"|"));S=s.splice(3<=l?3:l,11>=l?11:l);console.log(S.join("\n"))

Ungolfed version:

function C(a,x,o,c){
    a[x]=a[x].substr(0,o)+c+a[x].substr(o+1);
}
l=7;s=[];
for(i=21;i--;){
    s[i]="    ";
}
for(j=1;19>j;j+=2){
    s[j]=" ---";
}
for(k=3;12>k;k+=2){
    s[k]="-----";
}
i=0;n=prompt();
p="HL".indexOf(n[i]);
if(p>=0){
    l=14*p;i++;
}
l+=(73-n.charCodeAt(i))%7;
C(s,l,2,"O");
m=n.slice(-1);
if((m=="#")||m=="b"){
    C(s,l,1,m);
}
o=7<l?3:1;
for(z=0;3>z;z++){
    C(s,t=l-2*o+3+z,o,"|");
}
F=Math.min(3,l);
L=Math.max(11,l);
S=s.splice(F,L);
console.log(S.join("\n"));

WallyWest

Posted 2014-03-23T20:57:27.480

Reputation: 6 949

Could you add an ungolfed (readable) version, please? – Martin Ender – 2014-03-27T11:34:02.027

@m.buettner Done... I hope it helps give you a better understanding of what I've done :) – WallyWest – 2014-03-27T12:38:31.727