Wie viele Halbtöne

21

Richtlinien

Aufgabe

Berechnen Sie bei zwei als Zeichenfolgen oder Listen / Arrays eingegebenen Noten, wie viele Halbtöne (einschließlich der Noten selbst) voneinander entfernt sind, und geben Sie sie als Zahl aus.

Erklärung eines Halbtons:

Ein Halbton ist eine Stufe höher oder tiefer auf der Tastatur. Ein Beispiel ist C bis C #. Wie Sie unten sehen können, befindet sich die Note C auf einer weißen Note und C # ist die schwarze Note direkt darüber. Halbtöne sind die Sprünge von einer schwarzen Note zur nächsten weißen Note nach oben oder unten, mit Ausnahme von:

  • B bis C
  • C nach B
  • E bis F
  • F bis E

Tastatur

Beispiele

'A, C' -> 4

'G, G#' -> 2

'F#, B' -> 6

'Bb, Bb' -> 13


Regeln

  • Der größte Abstand zwischen zwei Noten beträgt 13 Halbtöne.
  • Die zweite eingegebene Note steht immer über der ersten eingegebenen Note.
  • Sie können Eingaben entweder als Zeichenfolge oder als Array / Liste annehmen. Wenn Sie es als Zeichenfolge verwenden, werden die Noten durch Kommas getrennt (z String -> 'A, F'. B.Array -> ['A', 'F'] ).
  • Sie können davon ausgehen, dass Sie immer zwei gültige Noten erhalten.
  • Scharfe Stellen werden als #und flache Stellen als bezeichnetb
  • Ihr Code muss Enharmonic-Entsprechungen unterstützen (z. B. muss er sowohl F # als auch Gb unterstützen)
  • Ihr Code muss keine Notizen unterstützen, die mit, aber ohne Scharf oder Flach benannt werden können (dh Sie müssen E # oder Cb nicht unterstützen). Bonuspunkte, wenn Ihr Code dies unterstützt.
  • Ihr Code muss keine Double Sharps oder Double Flats unterstützen.
  • Sie können davon ausgehen, dass die zweite nicht genau eine Oktave über der ersten liegt, wenn Sie die gleichen Noten oder die gleiche Tonhöhe (z. B. 'Gb, Gb' oder 'A #, Bb') erhalten.
  • Dies ist Codegolf, daher gewinnt die Antwort mit der geringsten Anzahl von Bytes.
Amorris
quelle
Ich bekomme 2 für, G -> G#weil sie beide enthalten sind.
HyperNeutrino
@HyperNeutrino Ja, tut mir leid. Fehler in meinem Namen.
Amorris
1
Müssen wir für Notizen wie Cboder sorgen E#? Was ist mit Double Sharps / Wohnungen?
Sok
1
@Sok Nein, Ihr Code muss keine Notizen wie E # oder Cb unterstützen und es müssen keine Double Sharps oder Flats unterstützt werden. Ich habe die Frage aktualisiert, um sie klarer zu machen. Entschuldigen Sie die Verwirrung.
Amorris
2
Nur um klar zu sein, wenn Sie von einer musiktheoretischen Bedeutung sprechen, enthält die Entfernung in Halbtönen nicht die Note, mit der Sie beginnen. In der Mathematik wird es so dargestellt, (X, Y]dass C bis C # 1 Halbton und C bis C 12 Halbtöne sind.
Dom

Antworten:

7

Python 2 , 66 Bytes

r=1
for s in input():r=cmp(s[1:]+s,s)-ord(s[0])*5/3-r
print-r%12+2

Probieren Sie es online!


Python 2 , 68 Bytes

lambda s,t:13-(q(s)-q(t))%12
q=lambda s:ord(s[0])*5/3+cmp(s,s[1:]+s)

Probieren Sie es online!

xnor
quelle
Zusätzliche Punkte für die Fähigkeit, Noten wie B # und Fb zu verarbeiten und dabei die bisher kürzeste zu bleiben.
Amorris
7

JavaScript (ES6), 78 Byte

1 Byte dank @Neil gespeichert

Nimmt die Notizen in Curry-Syntax auf (a)(b).

a=>b=>((g=n=>'0x'+'_46280ab_91735'[parseInt(n+3,36)*2%37%14])(b)-g(a)+23)%12+2

Testfälle

Hash-Funktion

Der Zweck der Hash-Funktion besteht darin, eine Note in einen Zeiger in einer Nachschlagetabelle umzuwandeln, die die hexadezimal gespeicherten Halbton-Offsets (C = 0, C # = 1, ..., B = 11) enthält.

Wir fügen zuerst eine '3' an die Note an und analysieren den resultierenden String in base-36, was zu einer Ganzzahl N führt . Weil '#' ein ungültiges Zeichen ist, wird es einfach ignoriert, zusammen mit allen darauf folgenden Zeichen.

Dann berechnen wir:

H(N) = ((N * 2) MOD 37) MOD 14

Nachfolgend finden Sie eine Zusammenfassung der Ergebnisse.

 note | +'3' | parsed as | base 36->10 |   *2  | %37 | %14 | offset
------+------+-----------+-------------+-------+-----+-----+--------
  C   |  C3  |    c3     |         435 |   870 |  19 |   5 |  0x0
  C#  |  C#3 |    c      |          12 |    24 |  24 |  10 |  0x1
  Db  |  Db3 |    db3    |       17247 | 34494 |  10 |  10 |  0x1
  D   |  D3  |    d3     |         471 |   942 |  17 |   3 |  0x2
  D#  |  D#3 |    d      |          13 |    26 |  26 |  12 |  0x3
  Eb  |  Eb3 |    eb3    |       18543 | 37086 |  12 |  12 |  0x3
  E   |  E3  |    e3     |         507 |  1014 |  15 |   1 |  0x4
  F   |  F3  |    f3     |         543 |  1086 |  13 |  13 |  0x5
  F#  |  F#3 |    f      |          15 |    30 |  30 |   2 |  0x6
  Gb  |  Gb3 |    gb3    |       21135 | 42270 |  16 |   2 |  0x6
  G   |  G3  |    g3     |         579 |  1158 |  11 |  11 |  0x7
  G#  |  G#3 |    g      |          16 |    32 |  32 |   4 |  0x8
  Ab  |  Ab3 |    ab3    |       13359 | 26718 |   4 |   4 |  0x8
  A   |  A3  |    a3     |         363 |   726 |  23 |   9 |  0x9
  A#  |  A#3 |    a      |          10 |    20 |  20 |   6 |  0xa
  Bb  |  Bb3 |    bb3    |       14655 | 29310 |   6 |   6 |  0xa
  B   |  B3  |    b3     |         399 |   798 |  21 |   7 |  0xb

Über Wohnungen und scharfe Gegenstände

Unten ist der Beweis, dass diese Hash-Funktion sicherstellt, dass eine Note gefolgt von einem '#' dasselbe Ergebnis liefert wie die nächste Note gefolgt von einem 'b' . In diesem Absatz verwenden wir das Präfix @ für Basis-36-Mengen.

Beispielsweise wird Db in @ db3 und C # konvertiert. in @c konvertiert (siehe vorherigen Absatz). Wir wollen beweisen, dass:

H(@db3) = H(@c)

Oder im allgemeinen Fall mit Y = X + 1 :

H(@Yb3) = H(@X)

@ b3 ist 399 dezimal. Deshalb:

H(@Yb3) =
@Yb3 * 2 % 37 % 14 =
(@Y * 36 * 36 + 399) * 2 % 37 % 14 =
((@X + 1) * 36 * 36 + 399) * 2 % 37 % 14 =
(@X * 1296 + 1695) * 2 % 37 % 14

1296 ist kongruent zu 1 modulo 37 , daher kann dies vereinfacht werden als:

(@X + 1695) * 2 % 37 % 14 =
((@X * 2 % 37 % 14) + (1695 * 2 % 37 % 14)) % 37 % 14 =
((@X * 2 % 37) + 23) % 37 % 14 =
((@X * 2 % 37) + 37 - 14) % 37 % 14 =
@X * 2 % 37 % 14 =
H(@X)

Ein Sonderfall ist der Übergang von G # nach Ab , da wir erwarten würden, dass Hb den obigen Formeln entspricht. Dies funktioniert jedoch auch, weil:

@ab3 * 2 % 37 % 14 = @hb3 * 2 % 37 % 14 = 4
Arnauld
quelle
@ Neil Danke! Ihre Optimierung spart mehr Bytes als meine.
Arnauld
Huh, ich fand tatsächlich das Gegenteil mit meiner Batch-Lösung ...
Neil
@ Neil Weil das Zeichen des Modulo in Batch das Zeichen des Divisors ist, denke ich?
Arnauld
Nein, es ist das Vorzeichen der Dividende, wie bei JS, aber es hat sich als etwas besser herausgestellt, das Vorzeichen des Ergebnisses zu korrigieren, das aufgrund eines früheren Golfspiels invertiert worden war.
Neil
4

Perl, 39 32 Bytes

Enthält +1fürp

Geben Sie die Start- und Endnoten als zwei Zeilen auf STDIN an

(echo "A"; echo "C") | perl -pe '$\=(/#/-/b/-$\+5/3*ord)%12+$.}{'; echo

Nur der Code:

$\=(/#/-/b/-$\+5/3*ord)%12+$.}{
Tonne Hospel
quelle
@wastl Also mir wurde gesagt. Ich würde gerne wissen, welcher Meta-Post ich habe, damit ich nicht zustimmen kann :-)
Ton Hospel
Mein Kommentar ist ein Link. Fühlen Sie sich frei, darauf zu klicken.
Wastl
Sieht aus wie das funktioniert sehr ähnlich wie meins - aber unglaublich kurz für Perl, +1
Level River St
@LevelRiverSt Nun, das ist Ton Hospel.
msh210
4

Japt , 27 Bytes

®¬x!b"C#D EF G A"ÃrnJ uC +2

Online testen!Übernimmt die Eingabe als Array von zwei Zeichenfolgen.

Funktioniert auch für eine beliebige Anzahl von Spitzen oder Abflachungen auf jeder Basisnote!

Erläuterung

®¬x!b"C#D EF G A"ÃrnJ uC +2   Let's call the two semitones X and Y.
®                Ã            Map X and Y by
 ¬                              splitting each into characters,
  x                             then taking the sum of
   !b"C#D EF G A"               the 0-based index in this string of each char.
                                C -> 0, D -> 2, E -> 4, F -> 5, G -> 7, A -> 9.
                                # -> 1, adding 1 for each sharp in the note.
                                b -> -1, subtracting 1 for each flat in the note.
                                B also -> -1, which happens to be equivalent to 11 mod 12.
                                The sum will be -2 for Bb, 2 for D, 6 for F#, etc.
                              Now we have a list of the positions of the X and Y.
                  rnJ         Reduce this list with reversed subtraction, starting at -1.
                              This gets the difference Y - (X - (-1)), or (Y - X) - 1.
                      uC      Find the result modulo 12. This is 0 if the notes are 1
                              semitone apart, 11 if they're a full octave apart.
                         +2   Add 2 to the result.
ETHproductions
quelle
2

Perl 5+ -p, 66 Bytes

s/,/)+0x/;y/B-G/013568/;s/#/+1/g;s/b/-1/g;$_=eval"(-(0x$_-1)%12+2"

Probieren Sie es online!

Nimmt durch Kommas getrennte Werte an. Funktioniert auch für Cb, B #, E #, Fb und multiple # / b.

Erläuterung:

# input example: 'G,G#'
s/,/)+0x/; # replace separator with )+0x (0x for hex) => 'G)+0xG#'
y/B-G/013568/; # replace keys with numbers (A stays hex 10) => '8)+0x8#'
s/#/+1/g; s/b/-1/g; # replace accidentals with +1/-1 => '8)+0x8+1'
$_ = eval # evaluate => 2
    "(-(0x$_-1)%12+2" # add some math => '(-(0x8)+0x8+1-1)%12+2'

Erklärung zur Auswertung:

(
    - (0x8) # subtract the first key => -8
    + 0x8 + 1 # add the second key => 1
    - 1 # subtract 1 => 0
) % 12 # mod 12 => 0
+ 2 # add 2 => 2
# I can't use % 12 + 1 because 12 (octave) % 12 + 1 = 1, which is not allowed
wastl
quelle
2

Ruby , 56 Bytes

->a{a.map!{|s|s.ord*5/3-s[-1].ord/32}
13-(a[0]-a[1])%12}

Probieren Sie es online!

Die Buchstaben werden 5/3wie folgt gemäß ihrer ASCII-Code-Zeiten analysiert (dies ergibt die erforderliche Anzahl von Halbtönen plus einen Versatz von 108).

A    B    C    D    E    F    G
108  110  111  113  115  116  118

Das letzte Zeichen ( #, boder der Brief wieder) als sein ASCII - Code durch 32 geteilt geparst wie folgt

# letter (natural) b 
1  { --- 2 --- }   3

Dies wird vom Buchstabencode abgezogen.

Dann wird das Endergebnis als zurückgegeben 13-(difference in semitones)%12

Level River St
quelle
2

Stax , 25 24 Bytes

╝─°U┤ƒXz☺=≡eA╕δ┴╬\¿☺zt┼§

Führen Sie es online aus und debuggen Sie es

Dies ist die entsprechende ASCII-Darstellung desselben Programms.

{h9%H_H32/-c4>-c9>-mrE-v12%^^

Tatsächlich berechnet es den Tastaturindex jeder Note mithilfe einer Formel und berechnet dann das resultierende Intervall.

  1. Beginnen Sie mit der Basisnote, A = 2, B = 4, ... G = 14
  2. Berechnen Sie den versehentlichen Offset, 2 - code / 32wobei codeder ASCII-Code des letzten Zeichens ist.
  3. Addiere sie zusammen.
  4. Wenn das Ergebnis> 4 ist, subtrahieren Sie 1, um B # zu entfernen.
  5. Wenn das Ergebnis> 7 ist, subtrahieren Sie 1, um E # zu entfernen.
  6. Subtrahieren Sie die beiden resultierenden Notenindizes modular und addieren Sie 1.
rekursiv
quelle
1
["F#","B"]sollte 6.
Weijun Zhou
1
Vielen Dank. Ich habe die eine Hälfte der Berechnung geändert, ohne die andere anzupassen. Es ist repariert.
rekursiven
1

Batch, 136 135 Bytes

@set/ac=0,d=2,e=4,f=5,g=7,a=9,r=24
@call:c %2
:c
@set s=%1
@set s=%s:b=-1%
@set/ar=%s:#=+1%-r
@if not "%2"=="" cmd/cset/a13-r%%12

Erläuterung: Die Ersetzungen im cUnterprogramm ersetzen #im Notennamen mit +1und bmit -1. Da dies case insensitiv ist, Bbwird -1-1. Die Variablen für C... A(auch ohne Berücksichtigung der Groß- / Kleinschreibung) werden daher so gewählt, dass sie die entsprechende Anzahl von Halbtönen entfernt sind B=-1. Die resultierende Zeichenfolge wird dann ausgewertet, und @ xnors Trick, das Ergebnis vom Wert zu subtrahieren, ergibt den gewünschten Effekt, die Notenwerte voneinander zu subtrahieren. Bearbeiten: Schließlich verwende ich @ Arnauld's Trick, das Modulo von 13 zu subtrahieren, um die gewünschte Antwort zu erhalten und 1 Byte zu sparen.

Neil
quelle
1

Python 3 , 95 Bytes

lambda a,b:(g(b)+~g(a))%12+2
g=lambda q:[0,2,3,5,7,8,10][ord(q[0])-65]+" #".find(q.ljust(2)[1])

Probieren Sie es online!

-14 Bytes dank user71546

HyperNeutrino
quelle
-8 Bytes mit ord(q[0])-65Ersetzen "ABCDEFG".find(q[0]);)
Shieru Asakoto
Oh, -6 weitere Bytes mit dem (g(b)+~g(a))%12+2Ersetzen1+((g(b)-g(a))%12or 12)
Shieru Asakoto
@ user71546 oh cool, danke!
HyperNeutrino
1

Gelee , 28 Bytes

O64_ṠH$2¦ḅ-AḤ’d5ḅ4µ€IḞṃ12FṪ‘

Ein monadischer Link, der eine Liste mit zwei Zeichenlisten akzeptiert und eine Ganzzahl zurückgibt.

Probieren Sie es online! oder sehen alle möglichen Fälle .

Wie?

Führt eine bizarre Arithmetik an den Ordnungszahlen der eingegebenen Zeichen durch, um die Noten auf die Ganzzahlen Null bis Zwölf abzubilden, und führt dann eine Basisdekomprimierung als Proxy für Modulo durch Zwölf durch, wobei dann Null durch 12 ersetzt und Eins addiert wird.

O64_ṠH$2¦ḅ-AḤ’d5ḅ4µ€IḞṃ12FṪ‘ - Main link, list of lists    e.g. [['F','#'],['B']]  ...or [['A','b'],['G','#']]
                  µ€         - for €ach note list          e.g.  ['F','#'] ['B']          ['A','b'] ['G','#']
O                            - { cast to ordinal (vectorises)    [70,35]   [66]           [65,98]   [71,35]
 64                          -   literal 64
   _                         -   subtract (vectorises)           [-6,29]   [-2]           [-1,-34]  [-7,29]
        ¦                    -   sparse application...
       2                     -   ...to indices: [2] (just index 2)
      $                      -   ...do: last two links as a monad:
    Ṡ                        -          sign                     [-6,1]    [-2]           [-1,-1]   [-7,1]
     H                       -          halve                    [-6,-0.5] [-2]           [-1,-0.5] [-7,0.5]
         ḅ-                  -   convert from base -1            5.5       -2             0.5       7.5
           A                 -   absolute value                  5.5       2              0.5       7.5
            Ḥ                -   double                          11.0      4              1.0       15.0
             ’               -   decrement                       10.0      3              0.0       14.0
              d5             -   divmod by 5                     [2.0,2.0] [0,3]          [0.0,0.0] [2.0,4.0]
                ḅ4           -   convert from base 4             10.0      3              0.0       12.0
                             - } -->                             [10.0,3]                 [0.0,12.0]
                    I        - incremental differences           [-7.0]                   [12.0]
                     Ḟ       - floor (vectorises)                [-7]                     [12]
                      ṃ12    - base decompress using [1-12]      [[5]]                    [[1,12]]
                         F   - flatten                           [5]                      [1,12]
                          Ṫ  - tail                              5                        12
                           ‘ - increment                         6                        13

Auch bei 28 Bytes ...

Ein (nicht so direkter) Port von Xnors Python 2 Antwort ...

O×5:3z60_Ṡ¥2¦60U1¦Fḅ-‘N%12+2

Versuche alle möglichen Fälle

Jonathan Allan
quelle