Print the fingering for the note on a saxophone

4

Your challenge is, given a series of notes, print the fingerings that minimize the amount of movements you need to make (explained below).

My not standard way of transforming fingerings to text: The | line separates the left and right hand. Use 1 for the index finger, 2 for the middle finger and 3 for the ring finger. Use a-d for the right hand to represent the side keys played by the pinkies (and just a and b for the left hand).

An example for low A#/Bb: Poorly scaled saxophone fingering chart

which would be written as 123d|123b.

The side keys, which are hit with the part of your hand between the thumb and index finger, are labeled as e, f, and g.

In addition, there is a little key between the right hand's 1 and 2 used for playing Bb. This is called the i key.

The octave key is labeled o

These are the fingerings (note that b means flat, not the note B which is uppercase):

A#3 or Bb3: 123d|123b
B3 or Cb4: 123c|123b
B#3 or C4: 123|123b
C#4 or Db4: 123b|123b
D4: 123|123
D#4 or Eb4: 123|123a
E4 or Fb4: 123|12
E#4 or F4: 123|1
F#4 or Gb4: 123|2
G4: 123|                // Note that the | is still necessary
G#4 or Ab4: 123a|
A4: 12|
A#4 or Bb4: 12|g OR 1i| OR 1|1 OR 1|2
B4 or Cb5: 1|
B#4 or C5: 2| OR 1|f
C#5 or Db5: |  OR o3|  // No fingers down for first fingering
D5: o123|123
/* All fingerings from D5 - B#5/C6 are the same as the lower octave
   but with the octave key (prefixed with o) */
C#6 or Db6: o|
D6: of|
D#6 or Eb6: oef|
E6 or Fb6: oef|e
E#6 or F6: oefg|

Input: A series of notes separated by semicolons.

Output: A series of fingerings separated by semicolons. If there is more than one way to finger a certain note, the program must chose the fingering that minimizes distance from its neighbors. If it is the only note or there is a tie, you may output any fingering.

A fingering's distance from another is how many fingers you would have to lift/press to change the note.

Example: 12| --> 1| has a distance of 1 because you have to lift finger 2. Example: 12|g --> 12| has a distance of 1 because you only have to lift one side key.

Test cases:

C#5;D5;C#5 --> o3|;o123|123;o3|

Bonus: -100 if your program takes an audio file (probably midi) as input and outputs the fingering corresponding to the notes played.

soktinpk

Posted 2015-01-11T23:50:04.963

Reputation: 4 080

Is C#5 o13| (as in the test case) or o3| (as in the spec)? – Uri Granta – 2015-01-13T13:13:32.247

Sorry it should be o3 – soktinpk – 2015-01-13T21:38:47.710

Answers

2

Python 3, 528 525 bytes (ouch!)

Not the prettiest code in the world, but I think it works. Calculates the shortest overall distance by trying all possible fingering combinations, so also not the most efficient.

from itertools import*
def f(x,y):a,b=x.split('|');c,d=y.split('|');return len(set(a)^set(c))+len(set(b)^set(d))
print(";".join(min(product(*["zd|zb zc|zb z|zb zb|zb z|z z|za z|12 z|1 z|2 z| za| 12| 12|g&1i|&1|1&1|2 1| 2|&1|f |&o3| oz|z oz|za oz|12 oz|1 oz|2 oz| oza| o12| o12|g&o1i|&o1|1&o1|2 o1| o2|&o1|f o| of| oef| oef|e oefg|".replace('z','123').split()["C D EF G A B".find(n[0])+" #".find(n[1:-1])+12*int(n[-1])-46].split('&') for n in input().split(';')]),key=lambda x:sum(f(x[i],x[i+1]) for i in range(len(x)-1)))))

Not many tricks. Saved a bit by a string-replace on "123". Simplified distance calculation by doing each half separately. Note name to pitch calculation is fairly tight but should be able to golf the rest down.

Uri Granta

Posted 2015-01-11T23:50:04.963

Reputation: 2 675