¿Es esta una escala mayor (o equivalente)?

16

Salvadera

La escala mayor (o escala jónica) es una de las escalas musicales más utilizadas, especialmente en la música occidental. Es una de las escalas diatónicas. Al igual que muchas escalas musicales, se compone de siete notas: la octava duplica la primera al doble de su frecuencia, por lo que se llama una octava más alta de la misma nota.

Las siete notas musicales son:

C, D, E, F, G, A, B , C (repetido por ejemplo)

Una escala mayor es una escala diatónica. Tome la sucesión previa de notas como una escala mayor (en realidad, es la escala C mayor) . La secuencia de intervalos entre las notas de una escala mayor es:

entero, entero, medio, entero, entero, entero, medio

donde "entero" representa un tono completo (una curva roja en forma de U en la figura), y "medio" representa un semitono (una línea roja discontinua en la figura).

ingrese la descripción de la imagen aquí

En este caso, de C a D existe un tono completo , de D a E existe un tono completo , de E a F existe medio tono, etc.

Tenemos 2 componentes que afectan la distancia de tono entre notas. Estos son el símbolo Sharp (♯) y el símbolo plano (♭).

El símbolo de Sharp (♯) agrega medio tono a la nota. Ejemplo. De C a D mencionamos que existe un tono completo, si usamos C♯ en lugar de C, entonces de C♯ a D existe un medio tono.

El símbolo Flat (♭) hace lo contrario del símbolo Sharp, resta medio tono de la nota. Ejemplo: de D a E mencionamos que existe un tono completo, si usamos Db en su lugar D, entonces de Db a E existe un tono y medio.

Por defecto, de nota a nota existe un tono completo, excepto para E to Fy B to Cen donde solo existe medio tono.

Tenga en cuenta que, en algunos casos, el uso de tonos enarmónicos puede crear un equivalente a una Escala mayor. Un ejemplo de esto es C#, D#, E#, F#, G#, A#, B#, C#dónde E#y B#son enarmónicos, pero la escala sigue la secuencia de una Escala mayor.


Desafío

Dada una escala, genera un valor verdadero si es una Escala mayor o equivalente, de lo contrario, genera un valor falsey.

Reglas

  • Método de E / S estándar permitido
  • Aplican reglas estándar de
  • No es necesario tener en cuenta la octava nota. Suponga que la entrada solo constará de 7 notas
  • Suponga que el doble plano (♭♭), el doble afilado (♯♯) o el signo natural (♮) no existen

Casos de prueba

C, D, E, F, G, A, B                 => true
C#, D#, E#, F#, G#, A#, B#          => true
Db, Eb, F, Gb, Ab, Bb, C            => true
D, E, Gb, G, A, Cb, C#              => true
Eb, E#, G, G#, Bb, B#, D            => true
-----------------------------------------------
C, D#, E, F, G, A, B                => false
Db, Eb, F, Gb, Ab, B, C             => false
G#, E, F, A, B, D#, C               => false 
C#, C#, E#, F#, G#, A#, B#          => false
Eb, E#, Gb, G#, Bb, B#, D           => false
Luis felipe De jesus Munoz
fuente
@Abigail Básicamente sí. Tienen el mismo tono aunque son notas diferentes.
Luis felipe De jesus Munoz
1
y Cx (o C ##) = D
SaggingRufus
1
Por cierto, las escalas pentatónicas no tienen una de cada letra: v
Luis felipe De jesus Munoz
1
@Neil Las escalas cromáticas no tienen letras únicas y estoy seguro de que hay un tipo de escala que no sigue un orden ascendente
Luis felipe De jesus Munoz
1
Voy a tener que votar esto porque @Neil lo votó de nuevo muchas gracias
David Conrad

Respuestas:

11

Perl 6 , 76 65 63 59 bytes

-4 bytes gracias a Phil H

{221222==[~] (.skip Z-$_)X%12}o*>>.&{13*.ord+>3+?/\#/-?/b/}

Pruébalo en línea!

Explicación

*>>.&{ ... }  # Map notes to integers
  13*.ord     # 13 * ASCII code:  A=845 B=858 C=871 D=884 E=897 F=910 G=923
  +>3         # Right shift by 3: A=105 B=107 C=108 D=110 E=112 F=113 G=115
              # Subtracting 105 would yield A=0 B=2 C=3 D=5 E=7 F=8 G=10
              # but isn't necessary because we only need differences
  +?/\#/      # Add 1 for '#'
  -?/b/       # Subtract 1 for 'b'

{                           }o  # Compose with block
            (.skip Z-$_)        # Pairwise difference
                        X%12    # modulo 12
         [~]  # Join
 221222==     # Equals 221222
nwellnhof
fuente
Si va a hacer una diferencia por pares y el módulo 12, no necesita restar 105; Es solo un desplazamiento. -4 caracteres: tio.run/…
Phil H
@ Phil Sí, por supuesto. ¡Gracias!
nwellnhof
¡Esa es una forma muy inteligente de asignar las notas a sus valores relativos, +1 de mi parte!
Sok
10

Node.js v10.9.0 , 78 76 71 69 bytes

a=>!a.some(n=>(a-(a=~([x,y]=Buffer(n),x/.6)-~y%61)+48)%12-2+!i--,i=3)

Pruébalo en línea!

¿Cómo?

Cada nota norte se convierte en un número negativo en [118,71] con:

[x, y] = Buffer(n) // split n into two ASCII codes x and y
~(x / .6)          // base value, using the ASCII code of the 1st character
- ~y % 61          // +36 if the 2nd character is a '#' (ASCII code 35)
                   // +38 if the 2nd character is a 'b' (ASCII code 98)
                   // +1  if the 2nd character is undefined

Lo que da:

  n   | x  | x / 0.6 | ~(x / 0.6) | -~y % 61 | sum
------+----+---------+------------+----------+------
 "Ab" | 65 | 108.333 |    -109    |    38    |  -71
 "A"  | 65 | 108.333 |    -109    |     1    | -108
 "A#" | 65 | 108.333 |    -109    |    36    |  -73
 "Bb" | 66 | 110.000 |    -111    |    38    |  -73
 "B"  | 66 | 110.000 |    -111    |     1    | -110
 "B#" | 66 | 110.000 |    -111    |    36    |  -75
 "Cb" | 67 | 111.667 |    -112    |    38    |  -74
 "C"  | 67 | 111.667 |    -112    |     1    | -111
 "C#" | 67 | 111.667 |    -112    |    36    |  -76
 "Db" | 68 | 113.333 |    -114    |    38    |  -76
 "D"  | 68 | 113.333 |    -114    |     1    | -113
 "D#" | 68 | 113.333 |    -114    |    36    |  -78
 "Eb" | 69 | 115.000 |    -116    |    38    |  -78
 "E"  | 69 | 115.000 |    -116    |     1    | -115
 "E#" | 69 | 115.000 |    -116    |    36    |  -80
 "Fb" | 70 | 116.667 |    -117    |    38    |  -79
 "F"  | 70 | 116.667 |    -117    |     1    | -116
 "F#" | 70 | 116.667 |    -117    |    36    |  -81
 "Gb" | 71 | 118.333 |    -119    |    38    |  -81
 "G"  | 71 | 118.333 |    -119    |     1    | -118
 "G#" | 71 | 118.333 |    -119    |    36    |  -83

Calculamos las diferencias por pares del módulo 12 entre estos valores.

La diferencia más baja posible entre 2 notas es 47 , por lo que es suficiente agregar 4×12=48 antes de aplicar el módulo para asegurarse de obtener un resultado positivo.

12'#'36mod12=0'b'38mod12=2

aNaN

[NaN,2,2,1,2,2,2]

i12

Arnauld
fuente
Gran enfoque, mucho más interesante que mi respuesta
Skidsdev
4

JavaScript (Node.js) , 150 131 125 bytes

l=>(l=l.map(x=>'C0D0EF0G0A0B'.search(x[0])+(x[1]=='#'|-(x[1]=='b')))).slice(1).map((n,i)=>(b=n-l[i])<0?2:b)+""=='2,2,1,2,2,2'

Pruébalo en línea!

-19 bytes gracias a Luis felipe
-6 bytes gracias a Shaggy

Sin golf:

function isMajor(l) {
    // Get tone index of each entry
    let array = l.map(function (x) {
        // Use this to get indices of each note, using 0s as spacers for sharp keys
        let tones = 'C0D0EF0G0A0B';
        // Get the index of the letter component. EG D = 2, F = 5
        let tone = tones.search(x[0]);
        // Add 1 semitone if note is sharp
        // Use bool to number coercion to make this shorter
        tone += x[1] == '#' | -(x[1]=='b');
    });
    // Calculate deltas
    let deltas = array.slice(1).map(function (n,i) {
        // If delta is negative, replace it with 2
        // This accounts for octaves
        if (n - array[i] < 0) return 2;
        // Otherwise return the delta
        return n - array[i];
    });
    // Pseudo array-comparison
    return deltas+"" == '2,2,1,2,2,2';
}
Skidsdev
fuente
1
[...'C0D0EF0G0A0B']en lugar de 'C0D0EF0G0A0B'.split('')y en +""lugar de .toString()guardar algunos bytes
Luis felipe De jesus Munoz
x[1]=='#'|-(x[1]=='b')en lugar de x[1]=='#'?1:(x[1]=='b'?-1:0)guardar algunos bytes también
Luis felipe De jesus Munoz
@LuisfelipeDejesusMunoz ¡Oh, gracias! No puedo creer que me había olvidado de la expansión del array y la adición de una cadena vacía
Skidsdev
"Si delta es negativo, reemplácelo con 2" suena mal. Creo que debes tomar la diferencia módulo 12.
nwellnhof
@nwellnhof En mis pruebas, todas las escalas principales tenían los deltas correctos para comenzar o, si abarcaban una octava, tenían un delta a -10 en lugar de 2. Reemplazar los deltas negativos corrige eso. No creo -10 % 12 == 2. Aunque ahora que lo pienso, esto podría fallar en algunos casos ...
Skidsdev
3

Dart , 198 197196 189 bytes

f(l){var i=0,j='',k,n=l.map((m){k=m.runes.first*2-130;k-=k>3?k>9?2:1:0;return m.length<2?k:m[1]=='#'?k+1:m[1]=='b'?k-1:k;}).toList();for(;++i<7;j+='${(n[i]-n[i-1])%12}');return'221222'==j;}

Pruébalo en línea!

Puerto suelto de la antigua respuesta de Perl 6 /codegolf//a/175522/64722

f(l){
  var i=0,j='',k,
  n=l.map((m){
    k=m.runes.first*2-130;
    k-=k>3?k>9?2:1:0;
    return m.length<2?k:m[1]=='#'?k+1:m[1]=='b'?k-1:k;
  }).toList();
  for(;++i<7;j+='${(n[i]-n[i-1])%12}');
  return'221222'==j;
}
  • -1 byte utilizando operadores ternarios para # / b
  • -1 byte usando ifs en lugar de ternaries para los cambios de escala
  • -7 bytes gracias a @Kevin Cruijssen

Versión antigua :

Dart , 210 bytes

f(l){var i=0,k=0,n={'C':0,'D':2,'E':4,'F':5,'G':7,'A':9,'B':11,'b':-1,'#':1},j='',y=[0,0];for(;++i<7;j+='${(y[0]-y[1])%12}')for(k=0;k<2;k++)y[k]=n[l[i-k][0]]+(l[i-k].length>1?n[l[i-k][1]]:0);return'221222'==j;}

Pruébalo en línea!

Sin golf:

f(l){
  var i=0,k=0,n={'C':0,'D':2,'E':4,'F':5,'G':7,'A':9,'B':11,'b':-1,'#':1},j='',y=[0,0];
  for(;++i<7;j+='${(y[0]-y[1])%12}')
    for(k=0;k<2;k++)
      y[k]=n[l[i-k][0]]+(l[i-k].length>1?n[l[i-k][1]]:0);

  return'221222'==j;
}

Un paso completo es 2, un cuarto es 1. Mod 12 en caso de que saltes a una octava más alta. Itera a través de todas las notas y calcula la diferencia entre la nota i-ésima y la nota i-1. Concatena el resultado y debe esperar 221222 (2 enteros, 1 mitad, 3 enteros).

  • -2 bytes al no asignar 0 a k
  • -4 bytes usando j como una cadena y no una lista
  • -6 bytes gracias a @Kevin Cruijssen al eliminar el desorden innecesario en los bucles
Elcan
fuente
No sé Dart, pero las partes son similares a Java. Por lo tanto: cambiar i=1a i=0puede reducir un byte cambiando for(;i<7;i++)a for(;++i<7;). Además, los soportes {}pueden retirarse alrededor de ese bucle, poniendo el j+=...interior de la tercera parte del bucle: for(;++i<7;j+='${(y[0]-y[1])%12}'). Y una última cosa está cambiando return j=='221222';para return'221222'==j;deshacerse del espacio. -6 ( 210 bytes ) después de estas modificaciones.
Kevin Cruijssen
Gracias, no sabía sobre esos trucos para los bucles
Elcan
Notario público. En su nueva versión de 196 bytes, también puede jugar golf a 189 bytes cambiando if(k>9)k--;if(k>3)k--;a k-=k>3?k>9?2:1:0;y k+=m.length<2?0:m[1]=='#'?1:m[1]=='b'?-1:0;return k;para return m.length<2?k:m[1]=='#'?k+1:m[1]=='b'?k-1:k;. :)
Kevin Cruijssen
Maldita sea, todavía tengo mucho que aprender parece, ¡gracias!
Elcan
Bueno, he estado jugando golf durante 2.5 años, e incluso recibo consejos sobre cosas para jugar golf todo el tiempo. :) Es muy fácil perderse algo usted mismo inicialmente, y con el tiempo piensa en diferentes formas de jugar al golf. :) Los consejos para jugar golf en <todos los idiomas> pueden ser interesantes de leer si aún no lo ha hecho. Y algunos de los Consejos para jugar golf en Java también podrían aplicarse en Dart, ya que los campos de golf que hice en sus respuestas se basaron en mi conocimiento de Java, ya que esta es la primera vez que veo a Dart. ;)
Kevin Cruijssen
2

C (gcc) , -DA=a[i]+ 183 = 191 bytes

f(int*a){char s[9],b[9],h=0,i=0,j=0,d;for(;A;A==35?b[i-h++-1]++:A^98?(b[i-h]=A*13>>3):b[i-h++-1]--,i++);for(;j<7;d=(b[j]-b[j-1])%12,d=d<0?d+12:d,s[j++-1]=d+48);a=!strcmp(s,"221222");}

Pruébalo en línea!

Basado en la respuesta de Perl.

Toma la entrada como una cadena ancha.

Sin golf:

int f(int *a){
	char s[9], b[9];
	int h, i, j;
	h = 0;
        for(i = 0; a[i] != NULL; i++){
		if(a[i] == '#'){
			b[i-h-1] += 1;
			h++;
		}
		else if(a[i] == 'b'){
			b[i-1-h] -= 1;
			h++;
		}
		else{
			b[i-h] = (a[i] * 13) >> 3;
		}
	}
	for(j = 1; j < 7; j++){
		int d = (b[j] - b[j-1]) % 12;
		d = d < 0? d + 12: d;
		s[j-1] = d + '0';
	}
	return strcmp(s, "221222") == 0;
}
Logern
fuente
170 bytes
ceilingcat
2

[Paquete Wolfram Language (Mathematica) + Music`], 114 bytes

Me encanta la música y me pareció interesante, pero estaba jugando al golf de verdad cuando esta oportunidad de golf de código surgió, así que mi presentación se retrasa un poco.

Pensé que probaría esto de una manera totalmente diferente, utilizando algunos conocimientos musicales reales. Resulta que el paquete de música de Mathematica conoce la frecuencia fundamental de las notas nombradas. Primero convierto la cadena de entrada en una secuencia de notas con nombre. A continuación, tomo las proporciones de cada nota sucesiva y doblo las que son menores de 2 (para tener en cuenta el desplazamiento de octava). Luego comparo estas proporciones con las proporciones de la escala jónica, que tiene aproximadamente una diferencia de frecuencia de 6% entre medias notas y 12% entre notas completas.

Más de la mitad de los bytes gastados aquí son para convertir la entrada en símbolos con nombre.

.06{2,2,1,2,2,2}+1==Round[Ratios[Symbol[#~~"0"]&/@StringReplace[# ,{"b"->"flat","#"->"sharp"}]]/.x_/;x<1->2x,.01]&

Pruébalo en línea!

Kelly Lowder
fuente
2

Python 3 , 175 136 134 114 112 bytes

def f(t):r=[ord(x[0])//.6+ord(x[1:]or'"')%13-8for x in t];return[(y-x)%12for x,y in zip(r,r[1:])]==[2,2,1,2,2,2]

Pruébalo en línea!


Una implementación de Python 3 de una sola línea.

Gracias a @Arnauld por la idea de calcular tonos usando división y módulo.
Gracias a @Jo King por -39 bytes.

cobalto
fuente
1
136 bytes
Jo King
1

[Python] 269 202 bytes

Mejoras de Jo King:

p=lambda z:"A BC D EF G".index(z[0])+"b #".index(z[1:]or' ')-1
def d(i,j):f=abs(p(i)-p(j));return min(f,12-f)
q=input().replace(' ','').split(',')
print([d(q[i],q[i+1])for i in range(6)]==[2,2,1,2,2,2])

¡Intentalo!

Sin golfista, con piloto de prueba:

tone = "A BC D EF G"   # tones in "piano" layout
adj = "b #"            # accidentals

def note_pos(note):
    if len(note) == 1:
        note += ' '
    n,a = note
    return tone.index(n) + adj[a]

def note_diff(i, j):
    x, y = note_pos(i), note_pos(j)
    diff = abs(x-y)
    return min(diff, 12-diff)

def is_scale(str):
    seq = str.replace(' ','').split(',')
    div = [note_diff(seq[i], seq[i+1]) for i in (0,1,2,3,4,5)]
    return div == [2,2,1,2,2,2]

case = [
("C, D, E, F, G, A, B", True),
("C#, D#, E#, F#, G#, A#, B#", True),
("Db, Eb, F, Gb, Ab, Bb, C", True),
("D, E, Gb, G, A, Cb, C#", True),
("Eb, E#, G, G#, Bb, B#, D", True),

("C, D#, E, F, G, A, B", False),
("Db, Eb, F, Gb, Ab, B, C", False),
("G#, E, F, A, B, D#, C", False),
("C#, C#, E#, F#, G#, A#, B#", False),
("Eb, E#, Gb, G#, Bb, B#, D", False),
]

for test, result in case:
    print(test + ' '*(30-len(test)), result, '\t',
          "valid" if is_scale(test) == result else "ERROR")
Ciruela pasa
fuente
Sí, veo el espacio en blanco, todavía inculcado con demasiado PEP-8, me temo. Aparentemente me perdí algo; ¿Se requiere un enlace de ejecución aquí?
Poda
1
Sin embargo, si quieres el enlace, 202 bytes con un juego de golf rápido. Definitivamente podría jugar un poco más al cambiar a un formato de entrada diferente
Jo King, el
Ah ... estoy demasiado acostumbrado a que Python devuelva la expresión final como el valor del proceso. Gracias por los consejos y sugerencias.
Pode el
Puede obtener 156 bytes si cambia a una función que toma una lista de cadenas. Además, TIO tiene un formateador automático en la sección de enlaces que puede usar
Jo King
@JoKing, puedes editar esta respuesta o publicar la tuya; comentar con un enlace separa las mejoras en un nivel.
Poda
1

Ruby , 109 bytes

->s{(0..11).any?{|t|s.map{|n|(w="Cef;DXg<E=Fhi>G j8A d9B:")[(w.index(""<<n.sum%107)/2-t)%12]}*''=='CfDX<=h'}}

Pruébalo en línea!

GB
fuente