Contexte
Dans la musique occidentale, chaque note de musique a un nom attribué. Dans chaque octave, il y a douze notes uniques dans l'ordre suivant: "CC # / Db DD # / Eb EFF # / Gb GG # / Ab AA # / Bb B C", où le do final est une octave au-dessus de la première.
Pour faire la différence entre les notes d'octaves différentes, un numéro (pour ce défi limité à un seul chiffre) est ajouté à la fin du nom de la note. Ainsi, C5 est la note qui est une octave au-dessus de C4. Bb6 est supérieur à B5.
Un fait important est que B5 et C6 sont des notes qui sont côte à côte et que C0 et B9 sont les notes les plus basses et les plus hautes.
Entre deux notes, il y a une distance qui est le nombre de demi-tons entre elles. Bb4 est un demi-ton en dessous de B4, qui est lui-même un demi-ton en dessous de C5. Il y a douze demi-tons dans une octave, donc Bb4 est à une distance de 12 de A # 3 car c'est une octave au-dessus (remarquez comment une seule note peut avoir jusqu'à deux noms).
Le défi
Votre défi est d'écrire le programme le plus court possible qui peut prendre une liste de notes de musique de STDIN et imprimer la liste des changements d'intervalle dans STDOUT.
L'entrée sera une liste de notes de musique séparées par des espaces. Chaque note se compose d'une lettre majuscule AG, d'un signe b ou # facultatif et d'un numéro à un chiffre. Vous n'aurez pas à gérer E # / Fb ou B # / Cb. Exemple d'entrée:
C4 D4 E4 F4 G4 A4 B4 C5 C4
La sortie sera une liste d'entiers séparés par des espaces qui représentent la distance entre chaque note successive, toujours préfixée par un + ou - pour montrer si la note était ascendante ou descendante par rapport à la précédente. Il y aura toujours un nombre de moins émis que les notes entrées. Exemple de sortie pour l'entrée ci-dessus:
+2 +2 +1 +2 +2 +2 +1 -12
Quelques exemples d'entrées supplémentaires:
E5 D#5 E5 B4 E5 F#5 E5 B4
C0 B0 Bb1 A2 G#3 G4 F#5 F6
G4 Ab4 Gb4 A4 F4 A#4
Et leurs sorties correspondantes:
-1 +1 -5 +5 +2 -2 -5
+11 +11 +11 +11 +11 +11 +11
+1 -2 +3 -4 +5
Règles et restrictions
Le gagnant est déterminé par le nombre de caractères dans le code source
Votre programme ne doit comprendre que des caractères ASCII imprimables
Vous n'êtes pas autorisé à utiliser toute sorte de fonction intégrée liée à la musique ou au son
Autre que cela, les règles de golf de code standard s'appliquent
la source
+0
ou-0
ou0
pour deux notes identiques?Réponses:
GolfScript, 61
la source
Haskell, 161 caractères
la source
Perl, 103
la source
C, 123 caractères
Basé sur la solution de leftaroundabout, avec quelques améliorations.
Quelques astuces qui, à mon avis, méritent d'être mentionnées:
1.
argv[0]
(appelé icib
) est un pointeur sur le nom du programme, mais utilisé ici comme tampon de travail. Nous n'avons besoin que de 4 octets (par exempleC#2\0
), nous en avons donc assez.2.
c
est le nombre d'arguments, il commence donc par 1 (lorsqu'il est exécuté sans arguments). Nous l'utilisons pour empêcher l'impression au premier tour.Problème possible -
c+=b[..c+=..]
est plutôt étrange. Je ne pense pas que ce soit un comportement indéfini, car?:
c'est un point de séquence, mais je me trompe peut-être.la source
c = c + b[..c+=..]
, alors c'est un comportement assez clairement indéfini. Quel que soit le séquençage à l'intérieur[..]
, vous ne savez pas si l'extérieurc
est récupéré avant, pendant ou aprèsb[..]
.REG=c;REG+=b[..c+=..];c=REG
. Cependant, je serai surpris de voir quelque chose comme ça dans la pratique. Mais c'est toujours UB.scanf
sans prototype, et ça va. C'est juste bon de savoir ce qui est et ce qui n'est pas légal dans la vraie vie :)C,
241229183la source
printf("%+d ",c-d)
.F(*b-65)
au lieu dec-=65;
,b[1]<36&&++c||b[1]>97&&c--?2:1
->b[1]&16?1:(c+=b[1]%2*2-1,2)
, abusez d'argv par:main(e,b,c,d)char*b{
(Utilisez le premier pointeur d'argument comme tampon de travail).c=F(*b)%12
peut être remplacé parc=-~*b*1.6;c%=12
. Pourquoi?sin
dans l'originalF
peut être remplacé par 9,6.c*1.6+9.6
est(c+6)*1.6
,c-=65
et(c+6)
devientc-59
, puisc+1
(60 * 96% 12 == 0).Facteur, 303 caractères
Avec des commentaires,
Pour ce script, une "liste séparée par des espaces" peut avoir 1 ou plusieurs espaces entre les éléments et 0 ou plusieurs espaces au début ou à la fin. Ce script imprime un espace supplémentaire à la fin de la sortie, mais il accepte également un espace supplémentaire (ou une nouvelle ligne) à la fin de l'entrée.
Si j'adoptais une définition plus stricte, où une "liste séparée par des espaces" a exactement 1 espace entre les éléments et 0 espace au début ou à la fin, alors je peux raccourcir
contents R/ [#-b]+/ all-matching-slices
encontents " " split
(en utilisantsplitting
, pasregexp
). Cependant, j'aurais besoin d'ajouter plus de code pour éviter l'espace supplémentaire à la fin de la sortie.Si j'utilise le mot déconseillé
dupd
, je peux le raccourcirover [ - "%+d " printf ] dip
endupd - "%+d " printf
économisant 8 caractères. Je n'utilise pas de mots déconseillés car ils "sont destinés à être supprimés prochainement".la source