La dicotomía mayor-menor

15

Dada una lista de acordes los etiqueta como 'Mayor' o 'Menor'.

Entrada

La entrada será una lista de acordes, uno por línea, compuesta de 3 notas separadas por un espacio. Cada nota consistirá en el nombre de la nota en mayúscula ( A- G) y un accidental opcional ( #o b). Los acordes pueden estar en cualquier inversión (es decir, las notas pueden estar en cualquier orden).

Salida

Si el acorde es mayor, salga 'Mayor'. Si el acorde es menor, envíe 'Menor'. Si el acorde no es mayor ni menor, genera una línea en blanco.

Ejemplo

Entrada

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

Salida

Major
Minor

Minor
Major
Minor
Major

Scripts de prueba

Como en algunas de mis preguntas anteriores, una vez más eliminé algunos scripts de prueba creados originalmente por Joey y Ventero para proporcionar algunos casos de prueba para esta pregunta:

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

Recompensas

Cada entrada que pueda verificar que cumpla con las especificaciones, pase las pruebas y obviamente haya tenido algún intento de jugar al golf recibirá un voto positivo de mí (así que proporcione instrucciones de uso con su respuesta). La solución más corta para fines del 13/10/2012 será aceptada como ganadora.

Una pequeña teoría

Para aquellos de ustedes que no tienen conocimientos de teoría musical, aquí hay suficiente información para que puedan competir.

Un acorde mayor o menor se compone de tres notas que están separadas por un patrón específico de semitonos. Si consideramos que la raíz (nota inferior) del acorde es 0, entonces un acorde mayor es el patrón 0-4-7 y un acorde menor es el patrón 0-3-7. Las cosas se vuelven más incómodas por el hecho de que algunas notas están separadas por un semitono y otras son un tono aparte. La propagación de semitonos de Ab- G#es la siguiente:

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#/Absignifica que esa G#es la misma nota que Ab. De esto podemos ver que el acorde Ab C Ebes un acorde mayor, y eso Ab Cb Ebes menor.

Para complicar más las cosas, el acorde Eb Cb Abse considera que es la misma que Ab Cb Eb, Cb Eb Aby Cb Ab Ebetcétera. Cada una de estas variaciones sigue siendo un acorde menor.

Gareth
fuente
2
Creo que su probador de bash necesita entradas y respuestas esperadas intercambiadas.
flodel
@flodel Sí, tienes razón. Lo siento, lo he corregido ahora. Tendré que comprobar que el script de prueba de Powershell no tenga el mismo problema también.
Gareth

Respuestas:

3

GolfScript, 83 caracteres

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

'>2%}%

Esta es una primera solución rápida; Estoy seguro de que esto se puede jugar más. Pasa el conjunto de pruebas de bash, después de corregir el error señalado por flodel en los comentarios.

Edición 1: guardado 5 caracteres con una forma más corta de reconocer los patrones de acordes mayores y menores canonicalizados.

Edición 2: guardó 2 caracteres más con una codificación de salida más compacta inspirada en la solución de grc. (¡Gracias!) Como efecto secundario, el código ahora imprime una línea en blanco adicional después de la salida, pero el arnés de prueba parece aceptar eso, así que supongo que está bien. :)

Así es como funciona:

  • El bucle externo n%{ }%n*solo divide la entrada en líneas, ejecuta el código dentro de las llaves para cada línea y une los resultados con nuevas líneas.

  • ' '%divide cada línea en una matriz de notas. Para cada una de esas notas, 1\{'A#BC D EF G'?+}/luego convierte esa nota en un número de semitono buscando cada uno de sus caracteres en la cadena 'A#BC D EF G'y sumando las posiciones (que será -1 para cualquier carácter que no se encuentre en la cadena, incluyendo notablemente b). (Estoy seguro de que he visto este truco usado antes). Finalmente, .duplica cada número, de modo que, al final del ciclo, por ejemplo, la entrada F Ab Cse ha convertido [9 9 0 0 4 4].

  • Luego ordenamos las notas con $, movemos la primera nota al final con (+y dividimos la matriz en pares con 2/, de modo que ahora se vea, por ejemplo, como [[9 0] [0 4] [4 9]]. Luego {~- 12%}%mapea cada par de notas en su módulo de diferencia 12, convirtiendo nuestra matriz de ejemplo en [9 8 7].

  • A continuación, .(+hace una copia de la matriz y gira sus elementos a la izquierda en una posición. Hacemos esto dos veces y recopilamos las copias en una matriz con ], de modo que nuestro ejemplo ahora se ve así [[9 8 7] [8 7 9] [7 9 8]].

  • Luego clasificamos esta matriz de matrices con $y tomamos el primer elemento, en este caso [7 9 8], con 0=. Luego hacemos una copia de esta matriz ( .), la clasificamos ( $), recopilamos la matriz sin clasificar y la sin clasificar en otra matriz de matrices ( ]), y buscamos la primera aparición de la matriz [7 8 9](que se escribe 10,7>para guardar dos caracteres) ) en eso.

  • Esto nos da ya sea 0(si la matriz sin clasificar era [7 8 9], y por lo tanto el acorde es mayor), 1(si la matriz sin clasificar era una permutación de [7 8 9], que, dado que su primer elemento debe ser más pequeño, solo puede ser [7 9 8], haciendo que el acorde sea menor) o -1(si incluso la matriz ordenada no es igual [7 8 9]).

  • Este número se usa como índice inicial en la cadena "MMaijnoorr\n\n"(donde los \ns se dan como avances de línea reales en el código), de donde tomamos ese carácter y cada segundo posterior como salida. Si el índice es -1, comenzamos desde el último carácter de la cadena, que es solo un avance de línea.

Ilmari Karonen
fuente
Buena explicación Tengo la misma dificultad que siempre tengo con GolfScript: puedo invocar una línea a la vez para probar, echo "G# B# Eb" | ruby golfscript.rb ilmari.gspero ¿cómo ejecuto el script de prueba en ella? Lo intenté ./test ruby golfscript.rb ilmari.gspero no tenía nada de eso. (Ya te he dado un +1 porque obviamente funciona, pero tengo curiosidad)
Gareth
1
@Gareth: Parece que es un error en el script de prueba de bash, no maneja varios argumentos correctamente. Para solucionarlo, reemplace args="$@"con args=("$@")y got=$("$cmd" "$args")con got=$("$cmd" "${args[@]}"). (O simplemente hacer golfscript.rbejecutable y ejecutarlo como ./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
fuente