A Dicotomia Maior-Menor


15

Dada uma lista de acordes, identifique-os como 'Maior' ou 'Menor'.

Entrada

A entrada será uma lista de acordes, um por linha, composta de 3 notas separadas por um espaço. Cada nota consistirá no nome da nota em maiúsculas ( A- G) e um acidental ( #ou b) opcional . Os acordes podem estar em qualquer inversão (ou seja, as notas podem estar em qualquer ordem).

Resultado

Se o acorde for maior, produza 'Maior'. Se o acorde for menor, produza 'Menor'. Se o acorde não for maior nem menor, produza uma linha em branco.

Exemplo

Entrada

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

Resultado

Major
Minor

Minor
Major
Minor
Major

Scripts de teste

Como em algumas das minhas perguntas anteriores, mais uma vez massacrei alguns scripts de teste criados originalmente por Joey e Ventero para fornecer alguns casos de teste para esta pergunta:

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

Recompensas

Cada entrada que eu possa verificar que atenda às especificações, passa nos testes e obviamente teve alguma tentativa de jogar golfe receberá um voto positivo de mim (por isso, forneça instruções de uso com sua resposta). A solução mais curta até o final de 13/10/2012 será aceita como vencedora.

Um pouco de teoria

Para aqueles que não têm conhecimento de teoria musical, aqui estão informações suficientes para poder competir.

Um acorde maior ou menor é composto de três notas que são separadas por um padrão específico de semitons. Se considerarmos que a raiz (nota inferior) do acorde é 0, um acorde maior é o padrão 0-4-7 e um acorde menor é o padrão 0-3-7. As coisas ficam mais estranhas pelo fato de que algumas notas são um semitom à parte e outras são um tom à parte. A propagação de semitons de Ab- G#é a seguinte:

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 essa G#é a mesma nota que Ab. A partir disso, podemos ver que o acorde Ab C Ebé um acorde maior e Ab Cb Ebmenor.

Para complicar ainda mais, o acorde Eb Cb Abé considerado o mesmo que Ab Cb Eb, Cb Eb Abe Cb Ab Ebe assim por diante. Cada uma dessas variações ainda é um acorde menor.


2
Acho que seu testador de bash precisa de entradas e respostas esperadas trocadas.
Flex 29/09/2012

@flodel Sim, você está certo. Desculpe por isso, eu o corrigi agora. Precisarei verificar se o script de teste do Powershell também não tem o mesmo problema.
Gareth

Respostas:


3

GolfScript, 83 caracteres

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

'>2%}%

Esta é uma primeira solução rápida; Tenho certeza de que isso pode ser jogado ainda mais. Passa no conjunto de testes do bash, após corrigir o erro apontado pelo flodel nos comentários.

Editar 1: salvou 5 caracteres com uma maneira mais curta de reconhecer os padrões de acordes maior e menor canonizados.

Edit 2: economizou mais 2 caracteres com codificação de saída mais compacta inspirada na solução da grc. (Obrigado!) Como efeito colateral, o código agora imprime uma linha em branco extra após a saída, mas o equipamento de teste parece aceitar isso, então acho que está tudo bem. :)

Veja como funciona:

  • O loop externo n%{ }%n*apenas divide a entrada em linhas, executa o código dentro das chaves para cada linha e junta os resultados com novas linhas.

  • ' '%divide cada linha em uma matriz de notas. Para cada uma dessas anotações, 1\{'A#BC D EF G'?+}/converte a anotação em um número de semitons pesquisando cada um de seus caracteres na sequência 'A#BC D EF G'e adicionando as posições (que será -1 para qualquer caractere não encontrado na sequência, incluindo inclusive b). (Tenho certeza de que já vi esse truque antes.) Finalmente, o .número é duplicado, de modo que, no final do loop, por exemplo, a entrada F Ab Cfoi transformada [9 9 0 0 4 4].

  • Em seguida, classificamos as notas com $, movemos a primeira nota para o final com (+e dividimos o array em pares com 2/, para que agora pareça, por exemplo [[9 0] [0 4] [4 9]]. Em seguida, {~- 12%}%mapeia cada par de notas para o seu módulo de diferença 12, transformando nosso exemplo de matriz [9 8 7].

  • Em seguida, .(+faz uma cópia da matriz e gira seus elementos deixados em uma posição. Fazemos isso duas vezes e coletamos as cópias em uma matriz com ], de modo que nosso exemplo agora seja semelhante [[9 8 7] [8 7 9] [7 9 8]].

  • Em seguida, classificamos essa matriz de matrizes $e pegamos o primeiro elemento - nesse caso [7 9 8]- com 0=. Em seguida, fazemos uma cópia dessa matriz ( .), classificamos ( $), coletamos a matriz não classificada e a não classificada em outra matriz de matrizes ( ]) e pesquisamos a primeira ocorrência da matriz [7 8 9](que é escrita 10,7>para salvar dois caracteres). ) iniciar.

  • Isso nos fornece 0(se a matriz não classificada era [7 8 9]e, portanto, o acorde é maior), 1(se a matriz não classificada era uma permutação de [7 8 9]que, dado que seu primeiro elemento deve ser menor, só pode ser [7 9 8], tornando a corda menor) ou -1(se mesmo a matriz classificada não for igual [7 8 9]).

  • Esse número é então usado como um índice inicial na string "MMaijnoorr\n\n"(onde os \ns são dados como feeds de linha reais no código), a partir dos quais tomamos esse caractere e cada segundo subsequente como saída. Se o índice for -1, começamos com o último caractere da string, que é apenas um feed de linha.


Boa explicação. Estou tendo a mesma dificuldade que sempre pareço ter com o GolfScript - posso chamar uma linha por vez para testar, echo "G# B# Eb" | ruby golfscript.rb ilmari.gsmas como executo o script de teste? Eu tentei, ./test ruby golfscript.rb ilmari.gsmas não estava tendo nada disso. (Eu já te dei um +1, porque, obviamente, funciona, mas eu sou apenas curioso)
Gareth

1
@ Gareth: Parece que isso é um bug no script de teste do bash - ele não lida com vários argumentos corretamente. Para corrigi-lo, substitua args="$@"por args=("$@")e got=$("$cmd" "$args")com got=$("$cmd" "${args[@]}"). (Ou simplesmente tornar golfscript.rbexecutável e executá-lo 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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.