Generate the names of the keys on a piano

7

2

On a standard 88 key piano, each key has a scientific name.

The first three keys are A0, B♭0, and B0. The keys then proceed through C1, D♭1, D1, E♭1, E1, F1, G♭1, G1, A♭1, A1, B♭1, B1, and start over again at C2. This continues up through B7, and the final key is C8.

Any flat can instead be written as a sharp of the preceding note, e.g. D♭4 can also be written C♯4. If necessary, you can write "D♭4" as "Db4".

Your program should build an ordered sequence (array, list, vector, etc.) containing the key names (as strings, symbols, or some similar data structure) in order.

Program length should be measured in characters, to avoid penalizing people who properly generate ♯ or ♭ rather than # or b. However, Unicode recoding is forbidden.

user4987

Posted 2012-07-28T09:02:28.970

Reputation:

I'd prefer having scoring by bytes, except in the case of ♯ and ♭ which count as one byte each. – lirtosiast – 2015-06-08T20:35:26.023

Here is a previous question that might be useful, as it involves taking note names as input. – PhiNotPi – 2012-07-28T13:13:33.153

3"Unicode recoding is forbidden." Can you edit the question to explain what that means, please? – Chris Jester-Young – 2012-07-30T17:31:06.597

@Chris: I think it may refer to putting a compressed byte sequence into a Unicode string and just decompressing that. – Joey – 2015-10-11T14:03:47.843

Answers

6

Bash shell script (58)

echo {8..0}{B,♭B,A,♭A,G,♭G,F,E,♭E,D,♭D,C}|rev|cut -b40-410

If you do not have rev, you can instead use tac -rs. at a cost of five characters.

Bending the rules, I can subtract thirteen characters (for a score of 45):

echo {8..0}{B,♭B,A,♭A,G,♭G,F,E,♭E,D,♭D,C}|rev

If you really need a bash array, add six characters to the score (for a score of 64):

a=(`echo {8..0}{B,♭B,A,♭A,G,♭G,F,E,♭E,D,♭D,C}|rev|cut -b40-410`)

PleaseStand

Posted 2012-07-28T09:02:28.970

Reputation: 5 369

Can you say more about tac -rs? In GNU coreutils 8.23 (and 6.10), tac -rs (the same as tac --regex --separator) complains about -s missing an argument, and tac -rs "" says it cannot be empty. I don't see a BSD version of tac (though BSD does have rev) to compare to. – Adam Katz – 2015-09-04T21:43:21.523

5

GolfScript, 60 57 characters

"A BbB C DbD EbE F GbG Ab"88,{1$2<@2>1$+\{8%},@9+12/+}%\;

The snippet produces the following array (see here):

["A0" "Bb0" "B0" "C1" "Db1" "D1" "Eb1" "E1" "F1" "Gb1" "G1" "Ab1" 
"A1" "Bb1" "B1" "C2" "Db2" "D2" "Eb2" "E2" "F2" "Gb2" "G2" "Ab2" 
"A2" "Bb2" "B2" "C3" "Db3" "D3" "Eb3" "E3" "F3" "Gb3" "G3" "Ab3" 
"A3" "Bb3" "B3" "C4" "Db4" "D4" "Eb4" "E4" "F4" "Gb4" "G4" "Ab4" 
"A4" "Bb4" "B4" "C5" "Db5" "D5" "Eb5" "E5" "F5" "Gb5" "G5" "Ab5" 
"A5" "Bb5" "B5" "C6" "Db6" "D6" "Eb6" "E6" "F6" "Gb6" "G6" "Ab6" 
"A6" "Bb6" "B6" "C7" "Db7" "D7" "Eb7" "E7" "F7" "Gb7" "G7" "Ab7" 
"A7" "Bb7" "B7" "C8"]

Edit: Changed from " "/""* to {8%}, to remove space.

Howard

Posted 2012-07-28T09:02:28.970

Reputation: 23 109

I'm kind of intrigued by GolfScript, but a bit confused. Do you know of any tutorials that would help a beginner learn the language? I've tried the tutorial on the official GolfScript web site and looked at several other pages retrieved on Google, but it doesn't make a whole lot of sense. – Rob – 2012-07-28T18:34:14.283

1

@MikeDtrick There are some Golfscript answers on this website that have explanations about how they work (e.g. http://codegolf.stackexchange.com/a/6058/3527). However, the best way to learn GS is to start coding something. Even better - try submitting a GS answer and you'll learn from the feedback you'll get :)

– Cristian Lupascu – 2012-07-30T15:25:03.757

1

@MikeDtrick other commented examples: http://codegolf.stackexchange.com/a/166/3527, http://codegolf.stackexchange.com/a/172/3527

– Cristian Lupascu – 2012-07-30T15:26:58.260

@w0lf Thank you for the resources! – Rob – 2012-07-31T19:41:36.583

@w0lf I know this probably isn't the proper place to ask a question, but I'm trying to code an answer for this question in GolfScript. I have a work in progress for the question, but I wanted to get in touch with someone who is skilled in this area. This is just practice, I won't post the answer if someone helps me out. Sorry for being a pest.

– Rob – 2012-08-02T00:57:22.747

@MikeDtrick I can't say I'm skilled, but I want to help you if I can. I've created a chat room for this: http://chat.stackexchange.com/rooms/4361/discussion-between-w0lf-and-mike-dtrick

– Cristian Lupascu – 2012-08-02T10:53:59.160

4

Mathematica 95 112 100 97 104 chars

Admittedly not very streamlined:

Take[Flatten@Table[# <> ToString@k & /@ 
Partition[Characters[" CDb DEb E FGb GAb ABb B"], 2], {k, 0, 8}], {10, 97}]

The Flat symbol, although it occupies a single character, is transcribed to SO as \[Flat] so I used the letter "b" here.

Output:

keys

Length@%
(* out *)
88

DavidC

Posted 2012-07-28T09:02:28.970

Reputation: 24 524

How do you count 95 chars? – Matt – 2012-07-28T14:45:24.000

I forgot to change the character count when I made a correction. It is now correct. (White spaces are there for legibility only, with the exception of those between quotes.) – DavidC – 2012-07-28T14:57:58.543

I get 100 keys from this rather than 88, but I can't find a rule against that, so +1 :-) – Mr.Wizard – 2012-07-29T14:15:11.930

Weird. I too had noticed the 100 keys, but couldn't find an error. – DavidC – 2012-07-29T14:21:27.773

David, your comment made me look at this again. The output is no longer agreeing with the picture you included. It starts "A0", "Bb0", " B0", " C0", and furthermore "C1" doesn't occur until after "Db1", " D1"` etc. (Previously I thought the real keys were in order and there were extras interspersed.) Sorry, but it's broken. :-( – Mr.Wizard – 2012-07-29T16:10:17.667

You are right once again. And here I was happy, thinking I had broken 100 chars. – DavidC – 2012-07-29T16:32:43.473

4

Python 103 96 94 78

[x+y for y in'0123456789'for x in'C Db D Eb E F Gb G Ab A Bb B'.split()][9:97]

updated according to Ev_genus's suggestion

updated according to Howard's suggestion

Matt

Posted 2012-07-28T09:02:28.970

Reputation: 1 395

94 [x+y for y in'0123456789'for x in['C','Db','D','Eb','E','F','Gb','G','Ab','A','Bb','B']][9:97] – Ev_genus – 2012-07-28T14:46:12.473

1Maybe you can use 'C Db D Eb E F Gb G Ab A Bb B'.split()? – Howard – 2012-07-28T15:13:50.833

omg, really! 78 [x+y for y in'0123456789'for x in'C Db D Eb E F Gb G Ab A Bb B'.split()][9:97] – Ev_genus – 2012-07-28T15:26:29.473

@Howard yeah, i forgot about that – Matt – 2012-07-28T16:13:12.840

4

Ruby: 75 71 characters

[*?0..?9].product(%w{C Db D Eb E F Gb G Ab A Bb B}).map{|a,b|b+a}[9,88]

(Base idea borrowed from Matt's solution.)

manatwork

Posted 2012-07-28T09:02:28.970

Reputation: 17 865

3You can use [*?0..?9] which is a little shorter. – Howard – 2012-07-28T17:52:21.280

I felt that I am missing something there, but I completely forgot the splat. Thank you @Howard. – manatwork – 2012-07-28T18:35:03.280

3

J, 81 76 63 62 61 58 characters

_11}.9}.(_2]\,|:9#"0'C DbD EbE F GbG AbA BbB '),.12#1":i.9

Output:

A 0 
Bb0 
B 0 
C 1 
Db1 
D 1 
Eb1 
E 1
...
G 7 
Ab7 
A 7 
Bb7 
B 7 
C 8

Probably a bit of room for shortening here.

Gareth

Posted 2012-07-28T09:02:28.970

Reputation: 11 678

3

C (92 84 characters)

Not impressive, could be reduced further.

main(i){for(i=9;printf("%c%c%d\n","CDDEEFGGAABB"[i%12]," b b  b b b "[i%12],i/12),++i<97;);}

Using Dietrich Epp's suggestion :

main(i){for(i=9;printf("%.2s%d\n","C DbD EbE F GbG AbA BbB "+2*i%24,i/12),++i<97;);}

It produces the following output :

A 0
Bb0
B 0
C 1
Db1
D 1
Eb1
E 1
F 1
Gb1

... // lines skipped

Eb7
E 7
F 7
Gb7
G 7
Ab7
A 7
Bb7
B 7
C 8

overcoder

Posted 2012-07-28T09:02:28.970

Reputation: 131

Can shave off 6 characters: main(i){for(i=9;printf("%.2s%d\n","C DbD EbE F GbG AbA BbB "+(i%12)*2,i/12),++i<97;);} – Dietrich Epp – 2012-07-29T00:02:40.617

@DietrichEpp: Thanks! I shaved off two other characters. – overcoder – 2012-07-30T01:54:04.867

3

Mathematica, 88

88 characters for 88 keys :-)

(Row@{#2,#1}&@@@Tuples@{0~Range~8,StringSplit@"C D♭ D E♭ E F G♭ G A♭ A B♭ B"})[[10;;97]]

Mr.Wizard

Posted 2012-07-28T09:02:28.970

Reputation: 2 481

2

C, 105 chars

- failing on size, so ended up aiming for a wtf different solution.

Probably only works on little-endian arch (e.g. intel) due to assumptions of treating int as small string... Assumes C program is called with no arguments, i.e. that w=1

t=12352,f;
main(w){
  t=t&64?t>>8:(w=1+w%7,(w-3)%3?t<<8|98:t+(w==3));
  f=t<<8|w+64;
  puts(&f);
  f-14403?main(w):0;
}

Output:

A0
Bb0
B0
C1
Db1
D1
Eb1
E1
F1
Gb1
G1
Ab1
--lines skipped--
Bb7
B7
C8

Edits

  • -9 chars - removing some brackets and reorganising an 'if'
  • -18 chars - code shuffling, sub 64 from w and pass as main arg
  • -13 chars - Use 't' to carry state rather than 'f'

baby-rabbit

Posted 2012-07-28T09:02:28.970

Reputation: 1 623

Really creative answer! – Krzysztof Szewczyk – 2019-08-26T16:45:45.087

1

Haskell: 72 chars

take 88$drop 9[p++show o|o<-[0..],p<-words$"C D♭ D E♭ F F♯ G G♯ A B♭ B"]

PLL

Posted 2012-07-28T09:02:28.970

Reputation: 139

1

Clojure - 71 chars

(for[c(range 10)n["C""Db""D""Eb""E""F""Gb""G""Ab""A""Bb""B"]](str n c))

kaoD

Posted 2012-07-28T09:02:28.970

Reputation: 584

1

Perl, 57+1

Just dug this up, a nice golfing exercise. Requires -E for say -- counted in score.

say+(CDbDEbEFGbGAbABbB=~/(.b?)/g)[$_%12],$_/12%9for 9..96

chinese perl goth

Posted 2012-07-28T09:02:28.970

Reputation: 1 089