Draw an ASCII key signature

22

Given an input of a note, output an ASCII drawing of the corresponding major key on the treble clef.

Here are all the major keys (that don't include double-sharps or double-flats) and their corresponding key signatures:


Circle of fifths deluxe 4 by Wikipedia user Just plain Bill, copyright CC BY-SA 3.0

If the input is a key with sharps, draw the following ASCII art with the appropriate number of sharps:

   #
-#-------
      #
----#----
  #
-------#-
     #
---------

---------

And if the input is a key with flats:

---------
  b
----b----
      b
-b-------
   b
-----b---
       b
---------

Here is a concise summary of the possible inputs as well as how many sharps or flats they use:

   0   1   2   3   4   5   6   7
#  C   G   D   A   E   B   F#  C#
b  C   F   Bb  Eb  Ab  Db  Gb  Cb

All five lines of dashes must always be drawn, but there may be any number of dashes per line such that the sharps or flats have at least one column of padding on each side, as long as each line of dashes has the same length. For example, these are all also acceptable outputs for the input Ab:

---------   ------   ---------   ----------------
  b           b           b          b
----b----   ----b-   -------b-   ------b---------

-b-------   -b----   ----b----   ---b------------
   b           b           b          b
---------   ------   ---------   ----------------

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

In the case of C major, which has no sharps nor flats, any positive number of dashes per line (even one) is acceptable.

Any amount of leading or trailing whitespace is fine, as are trailing spaces on each line. Extra leading spaces are okay as long as there are the same number on each line.

You may take input in lowercase or require that inputs without a sharp or flat contain a trailing space, if you so desire.

Since this is , the shortest solution in bytes will win.

Doorknob

Posted 2017-12-24T06:47:46.013

Reputation: 68 138

Related – Neil – 2017-12-24T16:03:40.673

3@Neil Ah, sorry for stealing your challenge >_< I searched the main site before posting but didn't think to check the sandbox. – Doorknob – 2017-12-24T17:07:05.403

Answers

3

Python 2, 206 197 178 175 168 161 bytes

Thanks to Mr. Xcoder for -12 bytes!

This is a function which returns the result as a 2D list of characters. If the input does not contain a sharp/flat, it should be padded with a space.

def f(k,r=range(10)):n="CGDAEB".find(k[0])+7*' #'.find(k[1]);return[[(' -'[i%2],'b#'[n>0])[0<j<=abs(n)and`i`==(n*"1403625"+"5263748")[j-1]]for j in r]for i in r]

Try it online!

FlipTack

Posted 2017-12-24T06:47:46.013

Reputation: 13 242

I think "FCGDAEB".find(k[0])-1 maps F to -1 and the others to their index - 1, so I think n="CGDAEB".find(k[0])+7*('#'in k)-7*('b'in k) would work instead. (175 bytes?)

– Mr. Xcoder – 2017-12-24T15:38:52.367

@Mr.Xcoder That's smart... thank you. – FlipTack – 2017-12-24T15:45:31.183

3

Charcoal, 60 bytes

≔⁻⁺⊖﹪⊗℅§θ¬χ⁷×⁷№θ#×⁷№θbθ←UO⁹¦⁹-¶Fθ«Jι⊖﹪⊕׳ι⁷#»F±θ«Jι⊕﹪⁺³×⁴ι⁷b

Try it online! Link is to verbose version of code. Explanation:

≔⁻⁺⊖﹪⊗℅§θ¬χ⁷×⁷№θ#×⁷№θbθ

Calculate the number of sharps in the key signature.

←UO⁹¦⁹-¶

Print the stave, but one square left of the origin so that the first sharp/flat is in column zero.

Fθ«

Loop over any sharps.

Jι⊖﹪⊕׳ι⁷#»

Calculate the row of the sharp and print it.

F±θ«

Loop over any flats.

Jι⊕﹪⁺³×⁴ι⁷b

Calculate the row of the flat and print it.

Neil

Posted 2017-12-24T06:47:46.013

Reputation: 95 035

2

Befunge, 139 bytes

~9%:4%7*+4/7%~6%1-2/7*+vv\`0:\!-g02+*2g00+1%7+g00*+3g00::<<0+55p02:_@
- b#09p01*-1*2p00:`0:-8<>10g`!**:00g2+*\!20g2%*+1g,1+:8`!#^_>$,:1-\^1

Try it online!

Note that the input is expected to be terminated with a linefeed, as would typically occur when running the program interactively.

Explanation

We start by reading two characters from stdin - the main note, n, and an accidental, a (which can be a linefeed if there is no accidental). Using those values, we calculate the key signature number, signum, as follows:

signum = (n%9 + n%9%4*7)/4%7 + (a%6 - 1)/2*7 - 8

This returns a value in the range -7 to 7, where the sign tells us whether we need sharps or flats (positive or negative), and the absolute value gives us the number of sharps or flats required. So for later use, we extract the sign, s, and the the accidental count, cnt, with:

s   = (signum > 0)
cnt = abs(signum) 

Then we have two nested loops, iterating a row number, r, from 9 down to 0, and a column number, c, from 0 up to 8. For a particular row and column, we calculate whether an accidental should be visible at that point with:

accidental = (r == (c*(s+3) + s)%7 + 1 + s*2) and (c > 0) and (c <= cnt)

If it's not an accidental, we need to output a line or space depending on whether the row, r, is odd or even. And if it is an accidental, we need to output a sharp or flat depending on the sign, s. So we evaluate the following formula:

index = (!accidental * (r%2)) + (accidental * (s+2))

Which gives us an index in the range 0 to 3, representing either a line, a space, a flat or a sharp. We simply use that index to lookup the required output character from a table, which you can see embedded at the start of the second line of code.

James Holderness

Posted 2017-12-24T06:47:46.013

Reputation: 8 298