Ayúdame a tocar mi armónica

8

Ayer compré una armónica:

mi armónica Figura 1: La armónica.

Sin embargo, mis sueños de poder tocar una armónica de blues conmovedora que conmueve a las personas y hace llorar a un hombre adulto se desvanecieron rápidamente por dos problemas:

  1. La armónica solo puede tocar ciertas notas;
  2. Soy deprimentemente malo tocando la armónica.

A pesar de mi falta de habilidad en la armónica, todavía hay algunas canciones que puedo tocar en ella. Sin embargo, no es obvio de inmediato si puedo tocar alguna pieza musical en la armónica o no. Dadas las notas de una pieza musical, escriba un programa para determinar si podría tocarlo en mi armónica o no.

Como muestra la imagen de arriba, mi armónica tiene diez agujeros. Con cada orificio, puedo exhalar o inhalar, el orificio que elijo y si inhalo o exhalo cambia el tono del sonido resultante. Cada hoyo tiene un tono diferente al exhalar e inhalar, pero hay algunas combinaciones que dan como resultado la misma nota. En general, mi armónica puede tocar 19 tonos diferentes únicos. Los tonos se presentan en notación científica musical: la letra representa la nota y el número representa en qué octava se encuentra.

 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 ejemplo, si exhalo en el hoyo 3, obtendría una G4nota. Si inhalara en el hoyo 2, también recibiría una G4nota. Si exhalara en el hoyo 7, obtendría un C6.

Cuando respiro en la armónica, además de exhalar o inhalar, también puedo elegir si respirar con dificultad o con dificultad . Respirar ligeramente hace que suene solo un agujero, mientras que la respiración hace que suene un agujero y ambos agujeros a cada lado de ese agujero. No tengo las habilidades de embocadura para soplar en dos agujeros: es uno o tres.

Por ejemplo, si exhalo por poco en el hoyo 4, solo sonaría el hoyo 4, por lo que obtendría un sonido C5. Si exhalara ampliamente en el hoyo 4, sonarían los agujeros 3, 4 y 5, y obtendría un acorde G4, C5, E5. Si inhalara ampliamente en el hoyo 4, sonarían los agujeros 3, 4 y 5, pero en su lugar tocarían los tonos de inhalación, lo que da como resultado un acorde B4, D5, F5. Tenga en cuenta que para los agujeros en cualquier extremo, si respiro profundamente en ellos, solo sonarían dos agujeros (porque no hay un agujero 0 o un agujero 11).

Sin embargo, no puedo inhalar y exhalar al mismo tiempo. Por ejemplo, podría exhalar en los agujeros 4, 5 y 6 para que las notas C5, E5 y G5 suenen al mismo tiempo, formando un acorde. Sin embargo, no puedo inhalar y exhalar al mismo tiempo, por lo que sería imposible para mí tocar el acorde C5, F5, A5 ya que de alguna manera tendría que exhalar en el hoyo 4 e inhalar en el hoyo 5 y 6. Si Esto aún no está claro, este hilo de comentarios podría ser útil.

La entrada son las notas de la música. Las notas se anotan de la misma manera que en la tabla anterior y están separadas por comas. Las notas envueltas entre corchetes representan un acorde. Por ejemplo:

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

Esto significa "C4, luego D4, luego G4, luego D5, F5 y A5 al mismo tiempo, luego B5". Su programa tomará una secuencia en este formato como entrada y salida Truesi me es posible reproducir la música en mi armónica, o de Falseotra manera. Para entradas y salidas de muestra, se debe mostrar el ejemplo anterior True. La entrada {C5,F5,A5}por otro lado saldrá False.

Este es el código de golf, por lo que gana la entrada más corta.

Aquí hay algunos casos de prueba:

Entrada (escala principal de CA):

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

Salida:

False

(porque la armónica no puede tocar F4 o A4)

Entrada (las 2 barras iniciales de Let It Go ):

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

Salida:

True

Entrada:

{E6,G6,F6}

Salida:

False

Entrada:

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

Salida:

True

Puede suponer que los acordes vendrán en un orden de tono más bajo a más alto.

Ajenjo
fuente
2
¿Tiene que alternar exhalar e inhalar moviéndose de nota en nota?
COTO
1
@COTO No. Suponga que tengo una capacidad de respiración infinita.
absenta
el enlace del hilo de comentarios referenciado no funciona para mí. esto funciona para mí: meta.codegolf.stackexchange.com/a/2149/3348
ardnew
¿tiene un conjunto de casos de prueba que podamos usar?
ardnew
44
PUEDO tocar bluesharp (armónica afinada Richter), pero solo toco blues en él. El hoyo 7 con C6 bajando a B5 parece extraño pero es correcto. Tiene dos soluciones: comprar una armónica más avanzada con una afinación diferente, o aprender a doblar las notas (si puede doblar, TODAVÍA no podrá tocar todas las notas, pero puede tocar un blues aullante para expresar su frustración .) La regla sobre solo poder tocar 1 o 3 notas es bastante precisa. Aquí hay una buena representación del ajuste de Richter: en.wikipedia.org/wiki/Richter-tuned_harmonica . La sección sobre diferentes teclas también es musicalmente interesante
Level River St

Respuestas:

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 la lectura:

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 una cadena formateada como en la descripción del problema, tregrese Truesi la secuencia se puede reproducir en la armónica descrita, y Falsesi no lo es.

No se verifica el orden de las notas en los acordes. A menos que se indique lo contrario, creo que esto es suficiente ya que eso no está en la declaración del problema, y ​​pasa todas las pruebas dadas en:

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
fuente
Puede eliminar muchos espacios: ] if "".join(x) not-> Las ]if"".join(x)notpalabras clave pueden estar adyacentes a las cadenas, por lo que "and"es correcto.
Bakuriu
Primero codifique el golf aquí, así que pensé que me faltaba algo. ¡Gracias!
Poik
1

Javascript - 245 243 caracteres

Minified:

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'}

Y ampliado:

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'
}

La función pacepta una cadena como entrada y devuelve Truesi la secuencia de nota / acorde se puede reproducir, de lo Falsecontrario. Devuelve resultados indefinidos si la entrada no es sintácticamente válida.

También asume audazmente que las notas de acorde se ingresan en orden de agujero ascendente (como en el ejemplo).

El recuento de caracteres se puede reducir en 14 si se permite que la función devuelva lógica truey falseno sus equivalentes de cadena.

COTO
fuente
1

JavaScript (ES6), 230

Solo una versión reescrita de la respuesta de @ 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'}

Agradecería cualquier consejo sobre jugar golf más abajo ya que estoy empezando a aprender ES6. :-)

rink.attendant.6
fuente
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 ","}=="")

Sin golf:

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?
)

Tenga en cuenta que la entrada con formato incorrecto se maneja mal: cualquier cadena se acepta y muchas cadenas con formato incorrecto devuelven verdadero, por ejemplo:

{C,7.D}.C

Imprime verdadero.

paradigma
fuente
1

Rebol - 188

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

Sin golf:

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 "}"
        ]
    ]
]

Ejemplo de uso (en la consola 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

Si bien este código atrapará galimatías como este:

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

Sin embargo, permitirá cosas como esta a través de:

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

Porque lo analiza como "C4, D4".

Aquí hay una versión más estricta del 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 campo de golf tiene 228 caracteres y ahora vuelve falsea ...

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

JavaScript ES6, 211 209 190 caracteres

Sé que esto se puede jugar más golf. Intentaré hacerlo en unas pocas horas;

Ejecute este código en la última consola web de Firefox, obtendrá un método llamado al Cque puede llamar como C("{G4,C5,E5},{F5,A5,B5}")y regresará Trueo en Falseconsecuencia.

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')

Estoy asumiendo una entrada sintácticamente válida.

EDITAR : Simplificó la expresión regular y la verificación de longitud.

Optimizador
fuente