Это мажорная шкала (или эквивалент)?

16

песочница

Основная шкала (или ионийская шкала) является одной из наиболее часто используемых музыкальных шкал, особенно в западной музыке. Это одна из диатонических шкал. Как и многие музыкальные гаммы, он состоит из семи нот: восьмая дублирует первую на удвоенной частоте, так что она называется высшей октавой той же ноты.

Семь музыкальных нот:

C, D, E, F, G, A, B , C (повторяется для примера)

Основная шкала - это диатоническая шкала. Возьмите предыдущую последовательность нот в качестве основной шкалы (на самом деле, это шкала до мажор) . Последовательность интервалов между нотами большой шкалы:

целое, целое, половина, целое, целое, целое, половина

где «целый» обозначает полный тон (красная U-образная кривая на рисунке), а «половина» обозначает полутон (красная пунктирная линия на рисунке).

введите описание изображения здесь

В этом случае от C до D существует целый тон, от D до E существует целый тон, от E до F существует половина тон, и т.д. ...

У нас есть 2 компонента, которые влияют на тональное расстояние между нотами. Это острый символ (♯) и плоский символ (♭).

Острый символ (♯) добавляет полутона к ноте. Пример. От C до D мы упомянули, что существует целый тон, если мы используем C♯ вместо C, то от C♯ до D существует полутон.

Плоский символ (♭) противоположен острому символу, он вычитает полутон из ноты. Пример: от D до E мы упоминали, что существует целый тон, если мы используем Db вместо D, то от Db до E существует тон с половиной.

По умолчанию от Note до Note существует целый тон, кроме E to FиB to C в котором только половина тон существует.

Обратите внимание, что в некоторых случаях использование энгармонических тонов может создать эквивалент для Major Scale. Примером этого является C#, D#, E#, F#, G#, A#, B#, C#где E#и B#являются энгармоническими, но шкала следует за последовательностью мажорной шкалы.


Вызов

Учитывая масштаб, выведите истинное значение, если оно является мажорным или эквивалентным, в противном случае выведите значение Фальси.

правила

  • Стандартный метод ввода / вывода разрешен
  • Применяются стандартные правила
  • Вам не нужно принимать во внимание восьмую ноту. Предположим, что вход будет состоять только из 7 заметок
  • Предположим, что двойного плоского (♭♭), двойного острого (♯♯) или натурального знака (♮) не существует

Контрольные примеры

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
Луис Фелипе Де Иисус Муньос
источник
@ Абигейл. В основном, да. У них одинаковый тон, хотя они разные ноты.
Луис Фелипе Де Иисус Муньос
1
и Cx (или C ##) = D
SaggingRufus
1
Кстати, в пентатонических шкалах нет по одной букве: v
Луис Фелипе Де Иисус Муньос,
1
@Neil Хроматические весы не имеют уникальных букв, и я уверен, что есть тип весов, которые не следуют по возрастанию
Луис Фелипе Де Иисус Муньос
1
Я собираюсь поддержать это, потому что @Neil понизил это, спасибо большое
Дэвид Конрад

Ответы:

11

Perl 6 , 76 65 63 59 байт

-4 байта благодаря Филу Н

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

Попробуйте онлайн!

объяснение

*>>.&{ ... }  # 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
источник
Если вы собираетесь сделать попарную разницу и по модулю 12, вам не нужно вычитать 105; это просто смещение. -4 символа
Фил Х
@PhilH Да, конечно. Благодарность!
nwellnhof
Это действительно умный способ сопоставить примечания с их относительными значениями, +1 от меня!
Сок
10

Node.js v10.9.0 , 78 76 71 69 байт

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

Попробуйте онлайн!

Как?

Каждая нота n преобразуется в отрицательное число в [118,71] с помощью:

[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

Который дает:

  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

Мы вычисляем попарные разности по модулю 12 между этими значениями.

Наименьшая возможная разница между 2 нотами 47 , поэтому достаточно добавить 4×12=48 перед применением по модулю, чтобы убедиться, что мы получаем положительный результат.

Поскольку мы применяем модуль 12 , смещение, полученное с помощью a, '#'на самом деле составляет 36mod12=0 полутонов, тогда как смещение, полученное с помощью a, 'b'составляет 38mod12=2 полутона.

aNaN

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

i12

Arnauld
источник
Отличный подход, намного интереснее моего ответа
Skidsdev
4

JavaScript (Node.js) , 150 131 125 байт

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'

Попробуйте онлайн!

-19 байт благодаря Луису Фелипе
-6 байт благодаря Шегги

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
источник
1
[...'C0D0EF0G0A0B']вместо 'C0D0EF0G0A0B'.split('')и +""вместо того, .toString()чтобы сохранить некоторые байты
Луис Фелипе Де Иисус Муньос
x[1]=='#'|-(x[1]=='b')вместо того, чтобы x[1]=='#'?1:(x[1]=='b'?-1:0)сохранить некоторые байты тоже
Луис Фелипе Де Иисус Муньос
@LuisfelipeDejesusMunoz О, хорошо, спасибо! Я не могу поверить, что я забыл о расширении массива и добавлении пустой строки
Skidsdev
«Если дельта отрицательна, заменить ее на 2» звучит неправильно. Я думаю, что вы должны принять разницу по модулю 12.
Nwellnhof
@nwellnhof В моих тестах все основные шкалы либо имели правильные дельты для начала, либо, если они охватывали октаву, имели одну дельту в -10, а не 2. Замена отрицательных дельт исправляет это. Я не думаю -10 % 12 == 2. Хотя если подумать, в некоторых случаях это может не сработать ...
Скидсдев
3

Дротик , 198 197 196 189 байт

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

Попробуйте онлайн!

Свободный порт старого 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 байт с использованием троичных операторов для # / b
  • -1 байт с использованием ifs вместо троичных для масштабных сдвигов
  • -7 байт благодаря @Kevin Cruijssen

Старая версия :

Дротик , 210 байт

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

Попробуйте онлайн!

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

Целый шаг - 2, четверть - 1. Мод 12, если вы прыгаете на более высокую октаву. Перебирает все заметки и вычисляет разницу между i-ой и i-ой нотой. Объединяет результат и должен ожидать 221222 (2 целых, 1 половина, 3 целых).

  • -2 байта, не присваивая 0 к k
  • -4 байта, используя j в качестве строки, а не список
  • -6 байт благодаря @Kevin Cruijssen, удаляя ненужные помехи в циклах
Elcan
источник
Я не знаю Дарт, но части похожи на Java. Следовательно: изменение i=1на i=0может уменьшить байт путем изменения for(;i<7;i++)на for(;++i<7;). Кроме того, кронштейны {}могут быть удалены вокруг этого цикла,, поместив j+=...внутри третьей части цикла: for(;++i<7;j+='${(y[0]-y[1])%12}'). И последнее, что меняется, return j=='221222';чтобы return'221222'==j;избавиться от пространства. -6 ( 210 байт ) после этих модификаций.
Кевин Круйссен
Спасибо, не знал об этих
уловках
Np. В вашей новой 196-байт версии вы можете также поле для его 189 байт путем изменения if(k>9)k--;if(k>3)k--;в k-=k>3?k>9?2:1:0;и k+=m.length<2?0:m[1]=='#'?1:m[1]=='b'?-1:0;return k;к return m.length<2?k:m[1]=='#'?k+1:m[1]=='b'?k-1:k;. :)
Кевин Круйссен
Блин, мне еще многое предстоит узнать, похоже, спасибо!
Elcan
Ну, я играю в гольф уже 2,5 года, и даже я все время получаю советы о том, как играть в гольф. :) Поначалу довольно легко что-то пропустить самостоятельно, и со временем вы думаете о разных способах игры в гольф. :) Советы по игре в гольф на <все языки> могут быть интересными для чтения, если вы еще этого не сделали. И некоторые из советов по игре в гольф на Java могут быть применимы и к дартсу, так как игра в гольф, которую я сделал в ваших ответах, основывалась на моих знаниях Java, так как я впервые вижу Дарт. ;)
Кевин Круйссен
2

C (gcc) , -DA=a[i]+ 183 = 191 байт

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

Попробуйте онлайн!

На основании ответа Perl.

Принимает ввод в виде широкой строки.

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
источник
170 байт
floorcat
2

[Wolfram Language (Mathematica) + пакет Music`], 114 байт

Я люблю музыку и нашел это интересным, но я играл в настоящий гольф, когда появилась возможность играть в гольф с кодом, так что мое представление немного запоздало.

Я подумал, что попробую это совершенно по-другому, используя некоторые реальные музыкальные знания. Оказывается, музыкальный пакет Mathematica знает основную частоту названных нот. Сначала я преобразую входную строку в последовательность именованных заметок. Затем я беру отношения каждой последовательной ноты и удваиваю все, которые меньше 2 (для учета октавного сдвига). Затем я сравниваю эти соотношения с соотношениями ионной шкалы, которая имеет примерно 6% разности частот между половинными нотами и 12% между полными нотами.

Более половины байтов, потраченных здесь, предназначены для преобразования входных данных в именованные символы.

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

Попробуйте онлайн!

Келли Лоудер
источник
2

Python 3 , 175 136 134 114 112 байт

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]

Попробуйте онлайн!


Однострочная реализация Python 3.

Спасибо @Arnauld за идею расчета тонов с использованием деления и по модулю.
Спасибо @Jo King за -39 байтов.

cobaltp
источник
1
136 байт
Джо Кинг,
1

[Python] 269 202 байта

Улучшения от 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])

Попытайся!

Ungolfed, с тестовым водителем:

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")
Чернослив
источник
Да, я вижу пустое пространство - боюсь, все еще слишком много PEP-8. Я явно что-то пропустил; здесь требуется ссылка на исполнение?
чернослив
1
Хотя, если вы хотите ссылку, 202 байта с некоторым быстрым гольфом. Вы можете определенно поиграть в гольф, перейдя на другой формат ввода
Джо Кинг,
Ах ... Я слишком привык к тому, что Python возвращает окончательное выражение в качестве значения процесса. Спасибо за указатели и подсказки.
чернослив
Вы можете получить 156 байт, если переключитесь на функцию, принимающую список строк. Кроме того, у TIO есть автоформатер в разделе ссылок, который вы можете использовать
Джо Кинг,
@JoKing, вы можете редактировать этот ответ или опубликовать свой собственный; комментирование с помощью ссылки разделяет улучшения на один уровень.
чернослив