Antecedentes
En la música occidental, cada nota musical tiene un nombre asignado. Dentro de cada octava, hay doce notas únicas en el siguiente orden: "CC # / Db DD # / Eb EFF # / Gb GG # / Ab AA # / Bb B C", donde la C final está una octava por encima de la primera.
Para diferenciar entre notas de diferentes octavas, se agrega un número (para este desafío restringido a un solo dígito) al final del nombre de la nota. Por lo tanto, C5 es la nota que está una octava por encima de C4. Bb6 está por encima de B5.
Un hecho importante es que B5 y C6 son notas que están una al lado de la otra, y que C0 y B9 son las notas más bajas y más altas.
Entre dos notas, hay una distancia que es el número de semitonos entre ellas. Bb4 es un semitono debajo de B4, que es en sí mismo un semitono debajo de C5. Hay doce semitonos en una octava, por lo que Bb4 está a una distancia de 12 de A # 3, ya que está una octava por encima (observe cómo una sola nota puede tener hasta dos nombres).
El reto
Su desafío es escribir el programa más corto posible que pueda tomar una lista de notas musicales de STDIN e imprimir la lista de cambios de intervalo en STDOUT.
La entrada será una lista de notas musicales separadas por espacios. Cada nota constará de una letra mayúscula AG, un signo opcional b o # y un número de un solo dígito. No tendrá que lidiar con E # / Fb o B # / Cb. Entrada de ejemplo:
C4 D4 E4 F4 G4 A4 B4 C5 C4
La salida será una lista de enteros separados por espacios que representan la distancia entre cada nota sucesiva, siempre con un prefijo + o - para mostrar si la nota fue ascendente o descendente en relación con la anterior. Siempre habrá un número menos generado que las notas ingresadas. Ejemplo de salida para la entrada anterior:
+2 +2 +1 +2 +2 +2 +1 -12
Algunas entradas de ejemplo más:
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
Y sus salidas correspondientes:
-1 +1 -5 +5 +2 -2 -5
+11 +11 +11 +11 +11 +11 +11
+1 -2 +3 -4 +5
Reglas y restricciones
El ganador está determinado por la cantidad de caracteres en el código fuente
Su programa debe constar solo de caracteres ASCII imprimibles
No está autorizado a utilizar ningún tipo de función integrada relacionada con la música o el sonido.
Aparte de eso, se aplican reglas de golf de código estándar
fuente
+0
o-0
o0
por dos notas idénticas?Respuestas:
GolfScript, 61
fuente
Haskell, 161 caracteres
fuente
Perl, 103
fuente
C, 123 caracteres
Basado en la solución de leftaroundabout, con algunas mejoras.
Algunos trucos que creo que vale la pena mencionar:
1.
argv[0]
(aquí llamadob
) es un puntero al nombre del programa, pero se usa aquí como un búfer de memoria virtual. Solo necesitamos 4 bytes (por ejemploC#2\0
), por lo que tenemos suficiente.2)
c
es el número de argumentos, por lo que comienza como 1 (cuando se ejecuta sin argumentos). Lo usamos para evitar la impresión en la primera ronda.Posible problema:
c+=b[..c+=..]
es un poco extraño. No creo que sea un comportamiento indefinido, porque?:
es un punto de secuencia, pero tal vez me equivoque.fuente
c = c + b[..c+=..]
, entonces es un comportamiento claramente indefinido. Independientemente de la secuencia interna[..]
, no sabes si lo externoc
se obtiene antes, durante o despuésb[..]
.REG=c;REG+=b[..c+=..];c=REG
. Sin embargo, me sorprendería ver algo así en la práctica. Pero sigue siendo UB.scanf
un prototipo, y eso está bien. Es bueno saber qué es y qué no es legal en la vida real :)C,
241229183fuente
printf("%+d ",c-d)
.F(*b-65)
lugar dec-=65;
,b[1]<36&&++c||b[1]>97&&c--?2:1
->b[1]&16?1:(c+=b[1]%2*2-1,2)
, abusar de argv por:main(e,b,c,d)char*b{
(Use el primer puntero de argumento como búfer de trabajo).c=F(*b)%12
puede ser reemplazado porc=-~*b*1.6;c%=12
. ¿Por qué?sin
en el originalF
se puede reemplazar con 9.6.c*1.6+9.6
es(c+6)*1.6
,c-=65
y se(c+6)
conviertec-59
, y luegoc+1
(60 * 96% 12 == 0).Factor, 303 caracteres
Con comentarios,
Para este script, una "lista separada por espacios" puede tener 1 o más espacios entre elementos, y 0 o más espacios al principio o al final. Este script imprime un espacio adicional al final de la salida, pero también acepta un espacio adicional (o nueva línea) al final de la entrada.
Si adoptara una definición más estricta, donde una "lista separada por espacios" tiene exactamente 1 espacio entre elementos y 0 espacios al principio o al final, entonces puedo acortar
contents R/ [#-b]+/ all-matching-slices
acontents " " split
(usandosplitting
, noregexp
). Sin embargo, necesitaría agregar más código para evitar el espacio adicional al final de la salida.Si uso la palabra en desuso
dupd
, puedo acortarover [ - "%+d " printf ] dip
ydupd - "%+d " printf
guardar 8 caracteres. No estoy usando palabras obsoletas porque "están destinadas a eliminarse pronto".fuente