La dichotomie majeure-mineure

15

Étant donné une liste d'accords, étiquetez-les comme «majeurs» ou «mineurs».

Contribution

L'entrée sera une liste d'accords, un par ligne, composé de 3 notes séparées par un espace. Chaque note se composera du nom de la note en majuscule (A - G) et d'un accidentel ( #ou b) facultatif . Les accords peuvent être dans n'importe quelle inversion (c'est-à-dire que les notes peuvent être dans n'importe quel ordre).

Production

Si l'accord est majeur, sortez «Major». Si l'accord est mineur, sortez «Minor». Si l'accord n'est ni majeur ni mineur, sortez une ligne vierge.

Exemple

Contribution

C E G
F Ab C
C Eb Gb
E G B
Db F Ab
Bb G D
D A Gb

Production

Major
Minor

Minor
Major
Minor
Major

Scripts de test

Comme dans certaines de mes questions précédentes, j'ai une fois de plus massacré des scripts de test créés à l'origine par Joey et Ventero pour fournir des cas de test pour cette question:

Usage: ./test [your program and its arguments]

Récompenses

Chaque entrée dont je peux vérifier qu'elle répond aux spécifications, réussit les tests et a évidemment eu une tentative de golf recevra un vote positif de ma part (veuillez donc fournir des instructions d'utilisation avec votre réponse). La solution la plus courte d'ici la fin du 13/10/2012 sera acceptée comme gagnante.

Un peu de théorie

Pour ceux d'entre vous qui n'ont aucune connaissance de la théorie musicale, voici suffisamment d'informations pour pouvoir participer.

Un accord majeur ou mineur est composé de trois notes séparées par un motif spécifique de demi-tons. Si nous considérons la racine (note du bas) de l'accord comme étant 0, alors un accord majeur est le motif 0-4-7 et un accord mineur est le motif 0-3-7. Les choses sont rendues plus gênantes par le fait que certaines notes sont séparées par un demi-ton et d'autres par un ton différent. La répartition des demi-tons de Ab- G#est la suivante:

G#/Ab A A#/Bb B/Cb B#/C C#/Db D D#/Eb E/Fb E#/F F#/Gb G G#/Ab
  0   1   2    3     4    5   6   7    8     9    10  11  12

G#/Absignifie que c'est G#la même note que Ab. De cela, nous pouvons voir que l'accord Ab C Ebest un accord majeur, et c'est Ab Cb Ebmineur.

Pour compliquer encore les choses, l'accord Eb Cb Abest considéré comme le même que Ab Cb Eb, Cb Eb Abet Cb Ab Ebet ainsi de suite. Chacune de ces variations est encore un accord mineur.

Gareth
la source
2
Je pense que votre testeur bash a besoin d'entrées et de réponses attendues échangées.
flodel
@flodel Oui, vous avez raison. Désolé, je l'ai corrigé maintenant. Je vais devoir vérifier que le script de test Powershell n'a pas le même problème.
Gareth

Réponses:

3

GolfScript, 83 caractères

n%{' '%{1\{'A#BC D EF G'?+}/.}%$(+2/{~- 12%}%.(+.(+]$0=.$]10,7>?'MMaijnoorr

'>2%}%

Ceci est une première solution rapide; Je suis sûr que cela peut être approfondi. Réussit la suite de tests bash, après avoir corrigé le bogue signalé par flodel dans les commentaires.

Modifier 1: 5 caractères enregistrés avec un moyen plus court de reconnaître les modèles d'accords majeurs et mineurs canonisés.

Édition 2: enregistrement de 2 caractères supplémentaires avec un encodage de sortie plus compact inspiré de la solution de grc. (Merci!) Comme effet secondaire, le code imprime maintenant une ligne vierge supplémentaire après la sortie, mais le faisceau de test semble accepter cela, donc je suppose que c'est OK. :)

Voici comment ça fonctionne:

  • La boucle externe n%{ }%n*divise simplement l'entrée en lignes, exécute le code à l'intérieur des accolades pour chaque ligne et joint les résultats avec des sauts de ligne.

  • ' '%divise chaque ligne en un tableau de notes. Pour chacune de ces notes, 1\{'A#BC D EF G'?+}/convertit ensuite cette note en un demi-ton en recherchant chacun de ses caractères dans la chaîne 'A#BC D EF G'et en additionnant les positions (qui seront -1 pour tout caractère non trouvé dans la chaîne, y compris notamment b). (Je suis sûr que j'ai déjà utilisé cette astuce auparavant.) Enfin, le .double chaque numéro, de sorte qu'à la fin de la boucle, par exemple, l'entrée F Ab Ca été transformée en [9 9 0 0 4 4].

  • Nous trions ensuite les notes avec $, déplaçons la première note à la fin avec (+et divisons le tableau en paires avec 2/, de sorte qu'il ressemble maintenant, par exemple [[9 0] [0 4] [4 9]]. Puis {~- 12%}%mappe chaque paire de notes dans sa différence modulo 12, transformant notre exemple de tableau en [9 8 7].

  • Ensuite, .(+fait une copie du tableau et fait pivoter ses éléments vers la gauche d'une position. Nous faisons cela deux fois et collectons les copies dans un tableau avec ], de sorte que notre exemple ressemble maintenant [[9 8 7] [8 7 9] [7 9 8]].

  • Nous trions ensuite ce tableau de tableaux avec $et prenons le premier élément - dans ce cas [7 9 8]- avec 0=. Nous faisons ensuite une copie de ce tableau ( .), le trions ( $), collectons à la fois le tableau non trié et le tableau non trié dans un autre tableau de tableaux ( ]), et recherchons la première occurrence du tableau [7 8 9](qui est écrite 10,7>pour enregistrer deux caractères ) en elle.

  • Cela nous donne soit 0(si le tableau non trié était [7 8 9], et donc l'accord est majeur), 1(si le tableau non trié était une permutation de [7 8 9], qui, étant donné que son premier élément doit être le plus petit, ne peut l'être que [7 9 8], ce qui rend l'accord mineur) ou -1(si même le tableau trié n'est pas égal [7 8 9]).

  • Ce nombre est ensuite utilisé comme index de départ dans la chaîne "MMaijnoorr\n\n"(où le\n s sont donnés en tant que sauts de ligne réels dans le code), dont nous prenons ce caractère et chaque seconde suivante comme sortie. Si l'index est -1, nous partons du dernier caractère de la chaîne, qui n'est qu'un saut de ligne.

Ilmari Karonen
la source
Belle explication. J'ai la même difficulté que celle que j'ai toujours avec GolfScript - je peux l'invoquer une ligne à la fois pour tester, echo "G# B# Eb" | ruby golfscript.rb ilmari.gsmais comment exécuter le script de test dessus? J'ai essayé ./test ruby golfscript.rb ilmari.gsmais ça n'en avait pas. (Je vous ai déjà donné un +1 car cela fonctionne évidemment, mais je suis juste curieux)
Gareth
1
@Gareth: On dirait que c'est un bogue dans le script de test bash - il ne gère pas correctement plusieurs arguments. Pour le réparer, remplacez args="$@"par args=("$@")et got=$("$cmd" "$args")par got=$("$cmd" "${args[@]}"). (Ou tout simplement rendre golfscript.rbexécutable et l'exécuter comme ./test ./golfscript.rb chords.gs.)
Ilmari Karonen
4

Python, 160

f='A#BC D EF G3453543'.find
try:
 while 1:x,y,z=sorted(map(lambda x:f(x[0])+f(x[1:])+1,raw_input().split()));print'MMianjoorrr'[f(`y-x`+`z-y`)/14:-1:2]
except:0
grc
la source