Esta é uma escala maior (ou equivalente)?

16

Caixa de areia

A escala maior (ou escala jônica) é uma das escalas musicais mais usadas, principalmente na música ocidental. É uma das escalas diatônicas. Como muitas escalas musicais, é composta por sete notas: a oitava duplica a primeira com o dobro de sua frequência, de modo que é chamada de oitava mais alta da mesma nota.

As sete notas musicais são:

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

Uma escala maior é uma escala diatônica. Tome a sucessão anterior de notas como uma escala maior (na verdade, é a escala C Maior) . A sequência de intervalos entre as notas de uma escala maior é:

inteiro, inteiro, meio, inteiro, inteiro, inteiro, meio

onde "inteiro" representa um tom inteiro (uma curva vermelha em forma de u na figura) e "metade" representa um semitom (uma linha vermelha quebrada na figura).

insira a descrição da imagem aqui

Nesse caso, de C a D existe um tom inteiro , de D a E existe um tom inteiro , de E a F existe meio tom, etc ...

Temos dois componentes que afetam a distância do som entre as notas. Estes são o símbolo Sharp (♯) e o símbolo plano (♭).

O símbolo Sharp (♯) adiciona meio-tom à nota. Exemplo. De C a D mencionamos que existe um tom inteiro; se usarmos C♯ em vez de C, então de C♯ a D existe meio-tom.

O símbolo Flat (♭) faz o oposto do símbolo Sharp, subtrai o meio-tom da nota. Exemplo: De D a E mencionamos que existe um tom inteiro, se usarmos Db em vez de D, então de Db a E existe um tom e meio.

Por padrão, de nota a nota existir um tom inteiro, exceto E to Fe B to Cna qual existe apenas meio tom.

Observe que, em alguns casos, o uso de arremessos enarmônicos pode criar um equivalente a uma Escala maior. Um exemplo disso é C#, D#, E#, F#, G#, A#, B#, C#onde E#e B#é enarmônico, mas a escala segue a sequência de uma Escala Maior.


Desafio

Dada uma escala, emita um valor verdadeiro se for uma Escala Maior ou equivalente, caso contrário, emita um valor de falsey.

Regras

  • Método de E / S padrão permitido
  • Aplicam-se regras de padrão
  • Você não precisa levar em consideração a oitava nota. Suponha que a entrada seja composta apenas por 7 notas
  • Suponha que o duplo plano (♭♭), o dobro agudo (♯♯) ou o sinal natural (♮) não existam

Casos de teste

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
fonte
@ Abigail Basicamente, sim. Eles têm o mesmo tom, embora sejam notas diferentes.
Luis felipe De jesus Munoz
1
e Cx (ou C ##) = D
SaggingRufus
1
Aliás, as escalas pentatônicas não possuem uma de cada letra: v
Luis felipe De jesus Munoz
1
Escalas cromáticas @Neil não têm letras únicas e tenho certeza que há um tipo de escala que não segue uma ordem ascendente
Luis Felipe de Jesus Munoz
1
Vou ter que upvote isso porque @Neil downvoted-lo muito obrigado
David Conrad

Respostas:

11

Perl 6 , 76 65 63 59 bytes

-4 bytes graças a Phil H

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

Experimente online!

Explicação

*>>.&{ ... }  # 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
fonte
Se você deseja fazer uma diferença pareada e o módulo 12, não precisa subtrair 105; é apenas um deslocamento. -4 caracteres: tio.run/…
Phil H #
@ Philh Sim, claro. Obrigado!
Nwellnhof
Essa é uma maneira muito inteligente de mapear as notas para seus valores relativos, +1 de mim!
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)

Experimente online!

Quão?

Cada nota n é convertida em um número negativo em [-118,-71] com:

[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

Que dá:

  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 as diferenças aos pares módulo 12 entre esses valores.

A menor diferença possível entre duas notas é -47 , portanto basta adicionar 4×12=48. antes de aplicar o módulo para garantir um resultado positivo.

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

umaNaN

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

Eu12

Arnauld
fonte
Ótima abordagem, muito mais interessante do que a minha resposta #
2119 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'

Experimente online!

-19 bytes graças a Luis felipe
-6 bytes graças a Shaggy

Ungolfed:

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
fonte
1
[...'C0D0EF0G0A0B']em vez de 'C0D0EF0G0A0B'.split('')e +""em vez de .toString()salvar alguns bytes
Luis Felipe de Jesus Munoz
x[1]=='#'|-(x[1]=='b')em vez de x[1]=='#'?1:(x[1]=='b'?-1:0)salvar alguns bytes também
Luis Felipe de Jesus Munoz
@LuisfelipeDejesusMunoz Oh nice thanks! Eu não posso acreditar que esqueci a expansão da matriz e a adição de uma string vazia #
Skidsdev
"Se delta for negativo, substitua-o por 2" soa errado. Eu acho que você precisa ter o modulo diferença 12.
nwellnhof
@nwellnhof Nos meus testes, todas as escalas principais tinham os deltas corretos para começar, ou, se mediam uma oitava, tinham um delta em -10 em vez de 2. A substituição de deltas negativos corrige isso. Eu não acho -10 % 12 == 2. Embora chegou a pensar que este pode falhar em alguns casos ...
Skidsdev
3

Dart , 198197196189 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;}

Experimente online!

Porta frouxa do Perl antigo 6 respostas /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 usando operadores ternários para # / b
  • -1 byte usando ifs em vez de ternários para as mudanças de escala
  • -7 bytes graças a @Kevin Cruijssen

Versão antiga :

Dardo , 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;}

Experimente online!

Ungolfed:

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

Um passo inteiro é 2, um quarto é 1. Mod 12, caso você pule para uma oitava mais alta. Repete todas as notas e calcula a diferença entre a i-ésima nota e a décima-primeira nota. Concatena o resultado e deve esperar 221222 (2 inteiros, 1 metade, 3 total).

  • -2 bytes por não atribuir 0 a k
  • -4 bytes usando j como uma String e não uma Lista
  • -6 bytes graças a @Kevin Cruijssen removendo desordens desnecessárias em loops
Elcan
fonte
Não conheço o Dart, mas as partes são semelhantes às do Java. Portanto: alterar i=1para i=0pode reduzir um byte, alterando for(;i<7;i++)para for(;++i<7;). Além disso, os suportes {}podem ser removidos em torno desse circuito, ao colocar o j+=...interior da terceira parte do circuito: for(;++i<7;j+='${(y[0]-y[1])%12}'). E uma última coisa está mudando return j=='221222';para return'221222'==j;se livrar do espaço. -6 ( 210 bytes ) após essas modificações.
Kevin Cruijssen
Obrigado, não sabia sobre esses truques para os loops
Elcan
Np. Na sua nova versão de 196 bytes, você também pode aumentar para 189 bytes , alterando if(k>9)k--;if(k>3)k--;para k-=k>3?k>9?2:1:0;e 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
Porra, ainda tenho muito o que aprender, parece!
Elcan
Bem, jogo golfe há 2,5 anos e até recebo dicas sobre coisas para jogar golfe o tempo todo. :) É muito fácil perder algo inicialmente, e com o tempo você pensa em diferentes maneiras de jogar golfe. :) Dicas para jogar golfe em <todos os idiomas> podem ser interessantes para ler, se você ainda não o fez. E algumas das dicas para jogar golfe em Java também podem ser aplicáveis ​​no Dart, pois os jogos que fiz nas suas respostas foram baseados no meu conhecimento de Java, pois é a primeira vez que vejo o Dart. ;)
Kevin Cruijssen 8/11
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");}

Experimente online!

Baseado na resposta Perl.

Recebe a entrada como uma sequência larga.

Ungolfed:

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
fonte
170 bytes
ceilingcat 24/07/19
2

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

Adoro música e achei isso interessante, mas eu estava jogando golfe de verdade quando essa oportunidade de código surgiu, então minha apresentação é um pouco atrasada.

Imaginei que tentaria isso de uma maneira totalmente diferente, utilizando algum conhecimento musical real. Acontece que o pacote de músicas do Mathematica conhece a frequência fundamental das notas nomeadas. Primeiro eu converto a string de entrada em sequência de notas nomeadas. Em seguida, tomo as proporções de cada nota sucessiva e duplico as que são menores que 2 (para dar conta da mudança de oitava). Em seguida, comparo essas proporções com as proporções da escala jônica, que tem aproximadamente uma diferença de frequência de 6% entre as notas de meia nota e 12% entre as notas completas.

Mais da metade dos bytes gastos aqui é para converter a entrada em símbolos nomeados.

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

Experimente online!

Kelly Lowder
fonte
2

Python 3 , 175 136 134 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]

Experimente online!


Uma implementação de Python 3 de uma linha.

Obrigado a @Arnauld pela ideia de calcular tons usando divisão e módulo.
Graças a @Jo King por -39 bytes.

cobaltp
fonte
1
136 bytes
Jo Rei
1

[Python] 269 202 bytes

Melhorias 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])

Tente!

Ungolfed, com driver de teste:

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")
Ameixa seca
fonte
Sim, eu vejo o espaço em branco - ainda inculcado com muito PEP-8, receio. Eu aparentemente perdi alguma coisa; é necessário um link de execução aqui?
Poda
1
No entanto, se você quiser o link, 202 bytes com algum jogo rápido. Você poderia definitivamente golf um pouco mais por mudar para um formato de entrada diferente
Jo rei
Ah ... Estou muito acostumado a Python retornando a expressão final como o valor do processo. Obrigado pelas dicas e sugestões.
Prune
Você pode obter 156 bytes se alternar para uma função que faz uma lista de strings. Além disso, TIO tem um formatador auto na seção de links que você pode usar
Jo rei
@JoKing, você é perfeitamente bem-vindo para editar esta resposta ou postar a sua própria; comentar com um link separa as melhorias em um nível.
Prune
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'}}

Experimente online!

GB
fonte