Organiza la música de la iglesia gregoriana


19

El año es 930, y la Iglesia Gregoriana está teniendo un problema. Tienen miles de páginas de música de canto, pero el problema es que todas las partituras simplemente se arrojaron a una pila en lugar de tener un sistema de organización real:

Imagen de partituras
Imagen del usuario gamerprinter en el Gremio de Cartógrafos .

La Iglesia necesita organizar todas las partituras, por lo que han contratado a un ingeniero de software medieval para escribir un programa para organizarlo para ellos. Usted es el ingeniero de software que ha sido contratado. Sin embargo, el proceso de compilación en la época medieval implica que el programa está escrito en papel por un equipo de escribas bíblicos lentos. Para disminuir el tiempo que le toma al equipo de escribanos compilar su código, debe hacer que el programa sea lo más pequeño posible.

La Iglesia quiere que la música del canto se organice en función de la escala musical en la que están escritos. Toda la música del canto de la Iglesia está escrita en escalas dorias . Dadas las notas de cierta pieza musical, su programa generará la escala Dorian en la que se encuentra. Aquí, explicaré exactamente qué es una escala Dorian. Si ya lo sabe, puede omitir esta sección.

Hay 12 notas posibles en cualquier melodía. Aquí están en orden:

C C# D D# E F F# G G# A A# B

Un semitono (representado mediante a S) está incrementando un paso hacia la derecha, envolviéndose (de modo que un semitono desde B volvería a C). Un tono (representado con a T) son dos semitonos. Por ejemplo, un semitono desde F # sería G. Un tono desde F # sería G #.

Para crear una escala Dorian, comenzamos desde cualquier nota en la lista, y luego avanzamos en el siguiente patrón, enumerando las notas que encontramos:

T, S, T, T, T, S

Un ejemplo. Comienzo de A. Las notas de mi escala Dorian se convierten en:

A
B  (up a tone)
C  (up a semitone)
D  (up a tone)
E  (up a tone)
F# (up a tone)
G  (up a semitone)

La escala tiene las notas A, B, C, D, E, F #, y G. porque empecé desde A, vamos a llamar a esta la escala de Dorian en A . Por lo tanto, hay 12 escalas dorias diferentes, cada una de las cuales lleva el nombre de la nota desde la que comenzaron. Cada uno de ellos usa el mismo patrón de tonos y semitonos, comenzando desde una posición diferente. Si mi explicación no es coherente, también puede consultar Wikipedia .

La entrada del programa se puede dar desde lo que sea apropiado para su programa (por ejemplo, STDIN, argumento de línea de comando, raw_input()). Puede no estar preinicializado en una variable. La entrada será una lista de notas separadas por comas, que representa la melodía de la pieza. Puede haber notas repetidas. Siempre habrá suficientes notas diferentes en la entrada para poder deducir decisivamente la escala de la pieza. Un ejemplo de entrada:

B,B,D,E,D,B,A,G#,A,G#,E,D,F#,E,F#,E,F#,G#,A

La salida del programa debe ser la cadena Dorian scale in X, donde X es la nota inicial de la escala. La salida de la entrada de ejemplo:

Dorian scale in B

Comparando esto con la escala Dorian en B ( B C# D E F# G# A), vemos que todas las notas de la melodía están dentro de esta escala. La nota C # no se usa en este caso. Sin embargo, hay suficientes notas para identificar inequívocamente a B Dorian como la clave correcta. Ninguna otra escala Dorian encaja, porque cualquiera que sea la otra escala que intentemos, siempre hay al menos una nota de la melodía que no pertenece a la escala.

Este es el código de golf, por lo que gana la entrada con el menor número de caracteres. Pregunte en los comentarios si tiene preguntas.


Entonces, ¿qué debemos hacer es interpretar solo el primer tono / semitono?
Avall

@Avall Lo siento, no entiendo tu pregunta. La entrada no siempre comenzará con el tónico, si eso es lo que está preguntando.
ajenjo

Por favor bríndenos más ejemplos. Especialmente aquellos que no comienzan con el tónico.
Avall

1
El problema inverso es Escala de tecla y modo
Peter Taylor

1
@David Según esta meta pregunta , otorgué la respuesta a la respuesta más corta después de un período de espera de 12 días desde que comencé el desafío. Simplemente sucedió que la respuesta de CJam se publicó justo cuando iba a aceptar la siguiente más corta.
absenta

Respuestas:



8

C, 171 146

i,b;main(int c,char**v){for(;c=v[1][i];)b|=c/65<<c*2%7+v[1][++i]%2*7;for(i=12;i--;)b&(1016056>>i)||printf("Dorian scale in %c%c",65+i*3%7,(i<5)*35);}

Analizar cadenas en C no es tan fácil, así que opté por un enfoque más matemático.

Aprovecho el círculo de quintas. Si organizamos las notas en el siguiente orden en función de contar hasta 7 semitonos a la vez (conocido como "quinto"), encontramos que todas las notas permitidas en cualquier escala forman un bloque consecutivo de 7 notas y todas las notas prohibidas formar un bloque consecutivo de 5 notas.

F C G D A E B F# C# G# D# A#

(es un círculo, se envuelve Fal final).

La posición de una nota natural en la secuencia anterior se puede calcular como (ASCII code) * 2 % 7. Luego, si el siguiente carácter es impar (se aplica #pero no a coma, espacio o byte cero), agregamos 7 para que sea nítido. Almacenamos un mapa de bits de las notas que se han utilizado.

El número 243(binario 11111000) corresponde a las notas prohibidas en la escala de A # Dorian. Lo multipliqué por (1<<12)+1=4097para dar el número mágico 1016056. Esto se desplaza por derechos para verificar (mediante AND) si la melodía contiene notas prohibidas para cada una de las 12 escalas. Si la melodía no contiene notas prohibidas, se imprime la escala.

Para la salida, necesitamos imprimir el nombre de la escala codificado en el orden inverso al ciclo de quintos anterior, recuerde que estamos retrocediendo porque estamos desplazando los derechos). La secuencia ASCII ADGCFBEADGCFes generada por 65+i*3%7. Para los primeros cinco de estos también debe imprimirse un filo.

Código sin golf

i,b;
main(int c,char**v){
  for(;c=v[1][i];)                          //for each character in first commanline argument v[1]
                                               //if it is a letter (assume uppercase, ASCII 65 or over)
   b|=c/65<<c*2%7+v[1][++i]%2*7;               //convert to position in the circle of fifths. 
                                               //Add 7 if the next character is odd (ASCII'#')
                                               //leftshift 1 by this number and OR this with the contents of b.

  for(i=12;i--;)b&(1016056>>i)||printf         //if melody includes no prohibited notes for the scale i, print
   ("Dorian scale in %c%c",65+i*3%7,(i<5)*35); //the scale letter, and a # (ASCII 35) if required, otherwise an ASCII 0.
}

Comportamiento de entrada no válido: si se suministran notas insuficientes para determinar inequívocamente la escala, generará todas las escalas posibles. Si se proporciona una combinación imposible de notas, no generará nada. Las notas deben estar delimitadas por una coma (u otro carácter que no sea un espacio en blanco con un código ASCII par <= 64). Los espacios no se pueden usar ya que todo después del primer espacio se consideraría un argumento diferente. Los códigos ASCII> 64 se interpretarán como notas de la manera descrita.


¡Me sorprendió que el círculo de quintas tenga esta propiedad! Tal vez pueda usarlo para jugar al golf un poco más.
Ray

1
@Ray Esta es la razón por la que tenemos el conjunto de notas que tenemos. La octava tiene una relación de frecuencia de 2: 1. El quinto, tal como lo define Pitágoras, tiene una relación de 3: 2 y es el intervalo musical más importante después de la octava. Debido a que 1.5 ^ 12 está cerca pero no es igual a 2 ^ 7, la quinta temperatura moderada moderna se reduce a 1.4983 para que exactamente 12 quintas quepan en 7 octavas. La solución pasada de moda era usar solo 7 notas de las 12 disponibles del círculo. Es por eso que tenemos una escala basada en 7 notas desigualmente espaciadas. No es una convención al azar, hay algunas matemáticas sólidas detrás.
Level River St el

Hay varios instrumentos que organizan notas en quintas por razones de conveniencia (el violín se afina de esta manera, y el bajo se afina en cuartos, que es una relación de 4: 3). El ejemplo más llamativo (y el único instrumento que conozco que tiene notas en un círculo de quintas para un buen diseño acústico) es el steelpan: google.es/patents/US7696421 . Con este diseño, no importa si la nota al lado de la que estás tocando suena un poco.
Level River St

4

Haskell - 152

w=words
n=w"C C# D D# E F F# G G# A A# B"
f s="Dorian scale in "++[n!!i|i<-[0..11],all(`elem`[(n++n)!!(i+j)|j<-[0,2,3,5,7,9,10]])s]!!0
main=interact$f.w

Sin golf

type Note = String
type Scale = [Note]

notes :: [Note]
notes = words "C C# D D# E F F# G G# A A# B"

isScale :: Scale -> [Note] -> Bool
isScale scale notes = all (`elem` scale) notes

takeScale :: Int -> Scale
takeScale i = [(notes ++ notes) !! (i + j) | j <- [0, 2, 3, 5, 7, 9, 10]]

findScale :: [Note] -> Note
findScale xs = head [notes !! i | i <- [0..11], isScale (takeScale i) xs]

main = interact (("Dorian scale in "++) . findScale . words)

3

Python 2 - 177 caracteres

No es tan corto, pero Python cree que es divertido escribir múltiples bucles anidados en una línea, incluso cuando no se juega al golf. Desafortunadamente, tuve que poner la declaración de entrada en una línea separada para que no se ejecute más de una vez.

j=set(raw_input().split(','))
print"Dorian Scale in",[x for x in[["A A# B C C# D D# E F F# G G#".split()[(b+n)%12]for n in[0,2,3,5,7,9,10]]for b in range(12)]if j<set(x)][0][0]

No uso Python 3, pero creo que esta es una instancia rara cuando la declaración de impresión no necesitaría más caracteres. Dado que printes una función allí, podría compensar la necesidad de paréntesis con el uso del *operador de desempaquetado de listas para reemplazar el último [0].


2
También sería capaz de sustituir inputpor raw_inputy guardar 4 caracteres en Python 3.
comperendinous

"Encuentro la alegría de Python escribir múltiples bucles anidados para en una línea": ¿pero encuentras alegría al leerlos?
Caleb Paul

@Wideshanks Por supuesto que no ... ¡todo se trata del código de solo escritura!
feersum

3

Rubí - 132

12.times{|i|$*[0].split(?,)-(g=(0..6).map{|j|%w{C C# D D# E F F# G G# A A# B}[-i+=~(58>>j&1)]})==[]?(puts"Dorain scale in "+g[0]):g}

Entrada de la línea de comando args.
p.ejruby dorianscale.rb B,B,D,E,D,B,A,G#,A,G#,E,D,F#,E,F#,E,F#,G#,A

Pruébalo en: ideone


3

Haskell - 140

Utilice la propiedad Circle of Fifths introducida por @steveverrill. Si dejamos circle0 = words "C G D A E B F# C# G# D# A# F"y circle = circle0 ++ circle0, entonces podemos construir todas las escalas tomando 7 notas consecutivas circle.

scales = [take 7 . drop i $ circle | i <- [0..11]]

En cada escala construida de esta manera scale !! 3, el cuarto elemento es el nombre de la escala.

Código

w=words
n=w"C G D A E B F# C# G# D# A# F"
f s="Dorian scale in "++[x!!3|x<-[take 7.drop i$n++n|i<-[0..]],all(`elem`x)s]!!0
main=interact$f.w

Sin golf

type Note = String
type Scale = [Note]

notes :: [Note]
notes = words "C G D A E B F# C# G# D# A# F"

scales :: [Scale]
scales = [take 7 . drop i $ notes ++ notes | i <- [0..11]]

findScale :: [Note] -> Note
findScale xs = head [scale !! 3 | scale <- scales, all (`elem` scale) xs]

main = interact (("Dorian scale in "++) . findScale . words)

2

Scala 130 128 127

print("Dorian scale in "+(".#?".r findAllIn "FCGDAEBF#C#G#D#A#"*2 sliding(7)find{l=>args(0)split','forall(l contains _)}get 3))

Usando el método del círculo de quintas. Entrada de la línea de comando args es decir

scala dorianscale.scala B,B,D,E,D,B,A,G#,A,G#,E,D,F#,E,F#,E,F#,G#,A
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.