Combien de demi-tons

21

Des lignes directrices

Tâche

Étant donné deux notes, entrées sous forme de chaînes ou de listes / tableaux, calculez le nombre de demi-tons qui les séparent (y compris les notes elles-mêmes), en sortie sous forme de nombre.

Explication d'un demi-ton:

Un demi-ton est une étape vers le haut ou vers le bas du clavier. Un exemple est C à C #. Comme vous pouvez le voir ci-dessous, la note C est sur une note blanche et C # est la note noire juste au-dessus. Les demi-tons sont les sauts d'une note noire à la prochaine note blanche, vers le haut ou vers le bas, à l'exception de:

  • B à C
  • C à B
  • E à F
  • F à E

clavier

Exemples

'A, C' -> 4

'G, G#' -> 2

'F#, B' -> 6

'Bb, Bb' -> 13


Règles

  • La plus grande distance entre deux notes est de 13 demi-tons.
  • La deuxième note entrée sera toujours au-dessus de la première note entrée.
  • Vous pouvez prendre l'entrée sous forme de chaîne ou de tableau / liste. Si vous le prenez comme une chaîne, les notes seront séparées par des virgules (par exemple String -> 'A, F', Array -> ['A', 'F']).
  • Vous pouvez supposer que vous recevrez toujours deux notes valides.
  • Les objets tranchants seront désignés par #et les appartements seront désignés parb
  • Votre code doit prendre en charge les équivalents enharmoniques (par exemple, il doit prendre en charge F # et Gb)
  • Votre code n'a pas besoin de prendre en charge les notes nommées avec, mais peut être nommé sans tranchant ou plat (c'est-à-dire que vous n'avez pas besoin de prendre en charge E # ou Cb). Des points bonus si votre code le prend en charge.
  • Votre code n'a pas besoin de prendre en charge les doubles objets tranchants ou doubles.
  • Vous pouvez supposer que si vous obtenez les deux les mêmes notes ou la même hauteur (par exemple 'Gb, Gb' ou 'A #, Bb'), la seconde ne sera pas exactement une octave au-dessus de la première.
  • C'est le golf de code donc la réponse avec le moins d'octets gagne.
Amorris
la source
J'en reçois 2 G -> G#car ils sont tous les deux inclus.
HyperNeutrino
@HyperNeutrino Yep désolé. Erreur en mon nom.
Amorris
1
Devons-nous prendre en charge des notes comme Cbou E#? Qu'en est-il des doubles objets tranchants / plats?
Sok
1
@Sok Non, votre code n'a pas besoin de prendre en charge les notes telles que E # ou Cb, et il n'a pas besoin de prendre en charge les doubles objets tranchants ou plats. J'ai mis à jour la question pour la rendre plus claire. Désolé pour toute confusion.
Amorris
2
Juste pour être clair, lorsque vous parlez d'une distance de détection de la théorie musicale en demi - tons n'inclut pas la note sur laquelle vous commencez. En mathématiques, il sera représenté comme (X, Y]si C à C # est 1 demi-ton et C à C est 12 demi-tons.
Dom

Réponses:

7

Python 2 , 66 octets

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

Essayez-le en ligne!


Python 2 , 68 octets

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

Essayez-le en ligne!

xnor
la source
Des points supplémentaires pour pouvoir gérer des notes comme B # et Fb, tout en restant le plus court jusqu'à présent.
Amorris
7

JavaScript (ES6), 78 octets

1 octet enregistré grâce à @Neil

Prend les notes dans la syntaxe de curry (a)(b).

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

Cas de test

Fonction de hachage

Le but de la fonction de hachage est de convertir une note en un pointeur dans une table de recherche contenant les décalages en demi-tons (C = 0, C # = 1, ..., B = 11), stockés en hexadécimal.

Nous avons d' abord ajout d' un « 3 » à la note et analyser la chaîne résultant en base-36, conduisant à un nombre entier N . Parce que «#» est un caractère non valide, il est simplement ignoré, ainsi que tout caractère qui le suit.

Ensuite, nous calculons:

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

Voici un résumé des résultats.

 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

À propos des appartements et des objets tranchants

Vous trouverez ci-dessous la preuve que cette fonction de hachage garantit qu'une note suivie d'un «#» donne le même résultat que la note suivante suivie d'un «b» . Dans ce paragraphe, nous utilisons le préfixe @ pour les quantités en base 36.

Par exemple, Db sera converti en @ db3 et C # sera converti en @c (voir le paragraphe précédent). Nous voulons prouver que:

H(@db3) = H(@c)

Ou dans le cas général, avec Y = X + 1 :

H(@Yb3) = H(@X)

@ b3 est 399 en décimal. Donc:

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 est congru à 1 modulo 37 , donc cela peut être simplifié comme:

(@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)

Un cas particulier est la transition de G # à Ab , car nous nous attendons à ce que l' Hb soit conforme aux formules ci-dessus. Cependant, celui-ci fonctionne également parce que:

@ab3 * 2 % 37 % 14 = @hb3 * 2 % 37 % 14 = 4
Arnauld
la source
@Neil Merci! Votre optimisation économise plus d'octets que le mien.
Arnauld
Huh, j'ai trouvé l'inverse avec ma solution Batch ...
Neil
@Neil Parce que le signe du modulo dans Batch est le signe du diviseur, je suppose?
Arnauld
Non, c'est le signe du dividende, comme dans JS, mais il s'est avéré être un peu golfeur de corriger le signe du résultat qui avait été inversé en raison d'un golf antérieur.
Neil
4

Perl, 39 32 octets

Comprend +1pourp

Donnez les notes de début et de fin sur deux lignes sur STDIN

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

Juste le code:

$\=(/#/-/b/-$\+5/3*ord)%12+$.}{
Ton Hospel
la source
@wastl Donc on m'a dit. J'aimerais savoir quel meta post pour que je puisse y aller et être en désaccord :-)
Ton Hospel
Mon commentaire est un lien. N'hésitez pas à cliquer dessus.
wastl
On dirait que cela fonctionne de manière très similaire à la mienne - mais incroyablement court pour Perl, +1
Level River St
@LevelRiverSt bien, c'est Ton Hospel.
msh210
4

Japt , 27 octets

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

Testez-le en ligne! Prend l'entrée comme un tableau de deux chaînes.

Fonctionne également pour toute quantité d'objets tranchants ou plats sur n'importe quelle note de base!

Explication

®¬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
la source
2

Perl 5 + -p, 66 octets

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

Essayez-le en ligne!

Prend des valeurs séparées par des virgules. Fonctionne également pour Cb, B #, E #, Fb et multiple # / b.

Explication:

# 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'

Explication pour eval:

(
    - (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
la source
2

Rubis , 56 octets

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

Essayez-le en ligne!

Les lettres sont analysées en fonction de leur temps de code ASCII 5/3comme suit (cela donne le nombre requis de demi-tons plus un décalage de 108)

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

Le dernier caractère ( #, bou la lettre à nouveau) est analysé comme son code ASCII divisé par 32 comme suit

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

Ceci est soustrait du code lettre.

Ensuite, le résultat final est renvoyé comme 13-(difference in semitones)%12

Level River St
la source
2

Stax , 25 24 octets

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

Exécutez-le et déboguez-le en ligne

La représentation ascii correspondante du même programme est la suivante.

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

En effet, il calcule l'index du clavier de chaque note à l'aide d'une formule, puis calcule l'intervalle résultant.

  1. Partir de la note de fond, A = 2, B = 4, ... G = 14
  2. Calculez le décalage accidentel 2 - code / 32codeest le code ascii du dernier caractère.
  3. Ajoutez-les ensemble.
  4. Si le résultat est> 4, soustrayez 1 pour supprimer B #.
  5. Si le résultat est> 7, soustrayez 1 pour supprimer E #.
  6. Soustrayez modulablement les deux index de notes résultants et ajoutez 1.
récursif
la source
1
["F#","B"]devrait être 6.
Weijun Zhou
1
Merci. J'ai changé la moitié du calcul sans ajuster l'autre. C'est réparé.
récursif
1

Lot, 136 135 octets

@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

Explication: Les substitutions du csous - programme sont remplacées #dans le nom de la note par +1et bpar -1. Comme cela est insensible à la casse, Bbdevient -1-1. Les variables pour C... A(également insensibles à la casse) sont donc choisies pour être le nombre approprié de demi-tons B=-1. La chaîne résultante est ensuite évaluée, et l'astuce @ xnor de soustraire le résultat de la valeur donne l'effet souhaité de soustraire les valeurs de note les unes des autres. Edit: Enfin, j'utilise l'astuce de @ Arnauld pour soustraire le modulo de 13 pour obtenir la réponse souhaitée, en économisant 1 octet.

Neil
la source
1

Python 3 , 95 octets

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])

Essayez-le en ligne!

-14 octets grâce à user71546

HyperNeutrino
la source
-8 octets avec ord(q[0])-65remplacement "ABCDEFG".find(q[0]);)
Shieru Asakoto
Oh, -6 octets de plus avec (g(b)+~g(a))%12+2remplacement1+((g(b)-g(a))%12or 12)
Shieru Asakoto
@ user71546 oh cool, merci!
HyperNeutrino
1

Gelée , 28 octets

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

Un lien monadique acceptant une liste de deux listes de caractères et renvoyant un entier.

Essayez-le en ligne! ou voir tous les cas possibles .

Comment?

Effectue une arithmétique bizarre sur les ordinaux des caractères d'entrée pour mapper les notes sur les nombres entiers de zéro à douze, puis effectue une décompression de base en tant que proxy pour modulo par douze où zéro est ensuite remplacé par 12 puis en ajoute un.

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

Également à 28 octets ...

Un port (pas si direct) de la réponse Python 2 de xnor ...

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

Essayez tous les cas possibles

Jonathan Allan
la source