Ajude-me a tocar minha gaita

8

Ontem comprei uma gaita:

minha gaita Figura 1: A gaita.

No entanto, meus sonhos de poder tocar gaita de blues com alma que move as pessoas e faz um homem adulto chorar foram rapidamente frustrados por dois problemas:

  1. A gaita só pode tocar certas notas;
  2. Eu sou deprimente ruim em tocar gaita.

Apesar da minha falta de habilidade na gaita, ainda existem algumas músicas que eu posso tocar nela. No entanto, não é imediatamente óbvio se eu sou capaz de tocar alguma música na gaita ou não. Dadas as notas de uma peça musical, escreva um programa para determinar se eu poderia tocar na minha gaita ou não.

Como mostra a figura acima, minha gaita tem dez buracos. Em cada buraco, eu posso expirar ou inspirar nele - o buraco que eu escolher, e se eu inspiro ou expiro nele, altera o tom do som resultante. Cada buraco tem um tom diferente ao expirar e inspirar, mas existem algumas combinações que resultam na mesma nota. No geral, minha gaita pode tocar 19 arremessos diferentes. Os arremessos são apresentados em notação científica musical - a letra representa a nota e o número representa em que oitava está.

 Hole   Breathing   Note  
 1      Exhale      C4    
 1      Inhale      D4    
 2      Exhale      E4    
 2      Inhale      G4    
 3      Exhale      G4
 3      Inhale      B4
 4      Exhale      C5    
 4      Inhale      D5    
 5      Exhale      E5    
 5      Inhale      F5    
 6      Exhale      G5    
 6      Inhale      A5    
 7      Exhale      C6    
 7      Inhale      B5    
 8      Exhale      E6    
 8      Inhale      D6    
 9      Exhale      G6    
 9      Inhale      F6    
 10     Exhale      C7    
 10     Inhale      A6    

Por exemplo, se eu expirasse no buraco 3, receberia uma G4nota. Se eu inalasse no buraco 2, também receberia uma G4nota. Se eu expirasse no buraco 7, receberia um C6.

Quando respiro a gaita, além de exalar ou inalar, também posso escolher se devo respirar fina ou amplamente . Respirar levemente faz com que apenas um orifício soe, enquanto a respiração causa amplamente um orifício e os dois orifícios de ambos os lados do orifício. Eu não tenho as habilidades de embocadura para fazer dois furos - é um ou três.

Por exemplo, se eu exalasse levemente o orifício 4, apenas o orifício 4 soaria, então eu obteria um som C5. Se eu exalasse amplamente no orifício 4, os orifícios 3, 4 e 5 soariam e eu receberia um acorde G4, C5, E5. Se eu inalasse amplamente no orifício 4, os orifícios 3, 4 e 5 soariam, mas eles tocariam o tom da inspiração, resultando em um acorde B4, D5, F5. Observe que, para os orifícios de cada extremidade, se eu respirar fundo neles, soariam apenas dois orifícios (porque não há orifício 0 ou orifício 11).

No entanto, não consigo inspirar e expirar ao mesmo tempo. Por exemplo, eu poderia expirar nos orifícios 4, 5 e 6 para fazer com que as notas C5, E5 e G5 soassem ao mesmo tempo, formando um acorde. No entanto, não consigo inspirar e expirar ao mesmo tempo, por isso seria impossível tocar o acorde C5, F5, A5, pois teria que exalar de alguma forma no orifício 4 e inalar no orifício 5 e 6. Se ainda não está claro, esse tópico de comentários pode ser útil.

A entrada são as notas da música. As notas são anotadas da mesma maneira que estão acima na tabela e são separadas por vírgula. Notas envoltas em colchetes representam um acorde. Por exemplo:

C4,D4,G4,{D5,F5,A5},B5

Isso significa: "C4, então D4, depois G4, então D5, F5 e A5 ao mesmo tempo, depois B5". Seu programa pegará uma string nesse formato como entrada e saída, Truese for possível tocar música na minha gaita ou de Falseoutra forma. Para entradas e saídas de amostra, o exemplo acima deve ser exibido True. A entrada, {C5,F5,A5}por outro lado, será exibida False.

Isso é código de golfe, portanto a entrada mais curta vence.

Aqui estão alguns casos de teste:

Entrada (escala principal CA):

C4,D4,E4,F4,G4,A4,B4,C5

Resultado:

False

(porque a gaita não pode tocar F4 ou A4)

Entrada (as 2 barras de abertura do Let It Go ):

E6,F6,A5,E6,F6,F6,E6,A5,F6,E6

Resultado:

True

Entrada:

{E6,G6,F6}

Resultado:

False

Entrada:

{G4,C5,E5},{F5,A5,B5}

Resultado:

True

Você pode supor que os acordes serão de ordem mais baixa para a mais alta.

absinto
fonte
2
Você precisa alternar a expiração e a inspiração, passando de nota para nota?
COTO
1
@COTO Não. Suponha que eu tenha capacidade de respiração infinita.
absinto
o link do tópico do comentário referenciado não funciona para mim. isso funciona para mim: meta.codegolf.stackexchange.com/a/2149/3348
ardnew
você tem um conjunto de casos de teste que podemos usar?
ardnew
4
Eu POSSO tocar bluesharp (gaita afinada por Richter), mas só toco blues nela. O buraco 7 com C6 descendo para B5 parece estranho, mas está correto. Você tem duas soluções: compre uma gaita mais avançada com afinação diferente ou aprenda a dobrar as notas (se você puder dobrar, AINDA não será capaz de tocar todas as notas, mas poderá tocar um blues uivante para expressar sua frustração .) A regra de poder tocar apenas uma ou três notas é bastante precisa. Aqui está uma boa representação do ajuste de Richter: en.wikipedia.org/wiki/Richter-tuned_harmonica . Seção sobre chaves diferentes também é musicalmente interessante
Nível River St

Respostas:

2

Python - 218 209 189 caracteres

Mínimo:

def t(s):from re import sub as r;exec('l=bool([x for x in['+r('"{','("',r('}"','")',r(',','","','"'+s+'"')))+']if"".join(x)not in"C4E4G4C5E5G5C6E6G6C7|D4G4B4D5F5A5B5D6F6A6"])');return not l

Para facilitar a leitura:

def t(s):
    from re import sub as r
    exec('l=bool([x for x in'
         ' [' + r( '"{' , '("' ,
                  r( '}"' , '")' , 
                    r( ',' , '","' , '"' + s + '"' ))) +
         ']'
         ' if "".join(x) not in "C4E4G4C5E5G5C6E6G6C7|D4G4B4D5F5A5B5D6F6A6"])')
    return not l

Dada uma sequência formatada como na descrição do problema, tretorne Truese a sequência for reproduzível na gaita descrita e Falsese não for.

Não há verificação da ordem das notas nos acordes. Salvo indicação em contrário, acredito que isso é suficiente, uma vez que não está na declaração do problema e passa todos os testes fornecidos em:

assert not t("C4,D4,E4,F4,G4,A4,B4,C5")
assert t("E6,F6,A5,E6,F6,F6,E6,A5,F6,E6")
assert not t("{E6,G6,F6}")
assert t("{G4,C5,E5},{F5,A5,B5}")
Poik
fonte
Você pode remover muitos espaços: ] if "".join(x) not-> ]if"".join(x)notPalavras-chave podem ser adjacentes a seqüências de caracteres, portanto, "and"está correto.
Bakuriu 9/09/14
Primeiro código de golfe aqui, então achei que estava faltando alguma coisa. Obrigado!
Poik 9/09/14
1

Javascript - 245 243 caracteres

Minificado:

function p(s){function f(s){s=s.replace(/\W/g,'');l=s.length;return((l-6)*(l-2)?l-4?'':'C4E4 G6C7 D4G4 F6A6':'C4E4G4C5E5G5C6E6G6C7 D4G4B4D5F5A5B5D6F6A6').indexOf(s)<0?0:''}return s.replace(/{.*?}/g,f).split(',').map(f).join('')?'False':'True'}

E expandido:

function p(s) {
    function f(s) {
        s = s.replace( /\W/g, '' );
        l = s.length;
        return ( (l-6)*(l-2) ? ( (l-4) ? '' : 'C4E4 G6C7 D4G4 F6A6' ) : 'C4E4G4C5E5G5C6E6G6C7 D4G4B4D5F5A5B5D6F6A6' ).
            indexOf( s ) < 0 ? 0 : ''
    }
    return s.replace( /{.*?}/g, f ).split( ',' ).map( f ).join( '' ) ? 'False' : 'True'
}

A função paceita uma string como entrada e retorna Truese a sequência de notas / acordes for reproduzível, Falsecaso contrário. Retorna resultados indefinidos se a entrada não for sintaticamente válida.

Ele também assume com ousadia que as notas dos acordes são inseridas na ordem do furo ascendente (como no exemplo).

A contagem de caracteres pode ser reduzida em 14 se a função tiver permissão para retornar lógico truee falsenão seus equivalentes de cadeia.

COTO
fonte
1

JavaScript (ES6), 230

Apenas uma versão reescrita da resposta da @ COTO:

f=s=>{s=s.replace(/\W/g,'');l=s.length;return((l-6)*(l-2)?(l-4?'':'C4E4 G6C7 D4G4 F6A6'):'C4E4G4C5E5G5C6E6G6C7 D4G4B4D5F5A5B5D6F6A6').indexOf(s)<0?0:''};p=s=>{return s.replace(/{.*?}/g,f).split(',').map(f).join('')?'False':'True'}

Gostaria muito de receber dicas sobre isso ainda mais como eu estou começando a aprender ES6! :-)

rink.attendant.6
fonte
1

Scala 178

print(readLine./:(""){(a,c)=>if("..C4E4G4C5E5G5C6E6G6C7...D4G4B4D5F5A5B5D6F6A6...."sliding(6)flatMap(y=>Seq("{"+y.diff("..")+"}",y take 2))contains a+c)""else a+c diff ","}=="")

Ungolfed:

print(
  readLine.foldLeft(""){(a,c)=>                             # loop through the input
    if("..C4E4G4C5E5G5C6E6G6C7...D4G4B4D5F5A5B5D6F6A6...."  # from the harmonica
      .sliding(6)                                     # take 6 at a time
      .flatMap(y=>Seq("{"+y.diff("..")+"}",y take 2)) # chords + single notes     
      .contains(a+c)) ""                              # clear matches
    else a+c diff ","                                 # drop commas
  }==""                                               # did everything match?
)

Observe que a entrada malformada é mal tratada - qualquer string é aceita e muitas strings malformadas retornam true, por exemplo:

{C,7.D}.C

imprime verdadeiro.

paradigmsort
fonte
1

Rebol - 188

t: func[s][trim/with s ","h: next split n:"C4E4G4C5E5G5C6E6G6C7..D4G4B4D5F5A5B5D6F6A6"2 forskip h 2[i

Ungolfed:

t: func [s] [
    trim/with s ","
    h: next split n: "C4E4G4C5E5G5C6E6G6C7..D4G4B4D5F5A5B5D6F6A6" 2
    forskip h 2 [insert h '|]
    h: head h

    parse s [
        any [
            h | "{" x: copy c to "}" (unless find n c [c: n])
            :x c "}"
        ]
    ]
]

Exemplo de uso (no console Rebol):

>> t "C4,D4,G4,{D5,F5,A5},B5"
== true

>> t "{C5,F5,A5}"
== false

>> t "C4,D4,E4,F4,G4,A4,B4,C5"
== false

>> t "E6,F6,A5,E6,F6,F6,E6,A5,F6,E6"
== true

>> t "{E6,G6,F6}"
== false

>> t "{G4,C5,E5},{F5,A5,B5}"
== true

Enquanto esse código capta bobagens assim:

>> t "{C,7.D}.C"
== false

No entanto, permitirá coisas como esta através de:

>> t "C,4,D4"
== true

Porque está analisando como "C4, D4".

Aqui está uma versão mais rigorosa do código:

t: func [s] [
    h: next split n: "C4E4G4C5E5G5C6E6G6C7..D4G4B4D5F5A5B5D6F6A6" 2
    forskip h 2 [insert h '|]
    h: head h
    d: ["," | end]

    parse s [
      any [
            [
                h | "{" x: copy c to "}" (
                    unless all [
                        parse c [any [h d]]
                        find n trim/with copy c ","
                    ] [c: n]
                )
                :x c "}"
            ]
            d
      ]
    ]
]

Este golfe até 228 caracteres e agora retorna false...

>> t "C,4,D4"
== false
draegtun
fonte
1

JavaScript ES6, 211 209 190 caracteres

Eu sei que isso pode ser jogado ainda mais. Vou tentar fazer isso em algumas horas;

Execute este código no Console da Web mais recente do Firefox, você receberá um método nomeado Cque poderá chamar comoC("{G4,C5,E5},{F5,A5,B5}") e ele retornará Trueou de Falseacordo.

C=n=>(s='D4G4D5F5A5B5D6F6A6,C4E4G4C5E5G5C6E6G6C7',n.split(/[,}{]/g).some(a=>a&&!~s.search(a))||(m=n.match(/{[^}]+/g))&&m.some(a=>a.length!=9|!~s.search(a.replace(/{|,/g,"")))?'False':'True')

Estou assumindo uma entrada sintaticamente válida.

EDIT : Simplificado o regex e a verificação de comprimento.

Optimizer
fonte