Фортепианные аккорды на белых клавишах

9

Предыстория [что не соответствует действительности]

Фортепиано настроено так:

! [Http://www.piano-lessons-made-simple.com/images/2-Octave-Labled.gif

Однако на моем пианино все черные клавиши сломаны!

Я все еще хочу иметь возможность сыграть несколько аккордов на своем сломанном пианино.

В музыке аккорд - это группа нот, которые играются вместе. Чтобы учесть ввод аккордов, я сначала определю, что такое полутон.

Что такое полутон?

Полутон - самое маленькое расстояние в западной музыке. Если вы посмотрите на верхнюю часть пианино, вы увидите, что обычно вы можете перейти от черной клавиши к белой или наоборот; однако между Bи Cи Eи Fнет черного ключа.

Что такое аккорд?

Для целей этой задачи мы определяем аккорд как набор нот с определенным количеством полутонов между ними. Например, давайте возьмем 4-3-3аккорд, начиная с аккорда C(для музыкальных людей это аккорд V 7 фа мажор). Мы начинаем с C. Мы рассчитываем на 4 полутона: C#, D, D#, E. Следующее замечание E, и мы рассчитываем 3 полутона вверх после этого: F, F#, G. Следующее замечание G, и мы рассчитываем 3 полутона вверх после этого: G#, A, Bb. Итак, мы получаем C-E-G-Bb. Ура! Но подождите ... Bbэто черный ключ, и они сломаны ... Однако, если мы начнем G, мы получим G-B-D-F! Ура!

вход

Входные данные даны как список целых чисел в любом разумном формате. Это представляет аккорд, как описано выше.

Вывод

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

Тестовые случаи

input -> output // comments
4 3 -> C F G // this is a major triad
3 4 -> D E A // this is a minor triad
4 3 3 -> G // this is the major-minor seventh chord
3 3 3 -> [empty output] // this is the diminished-diminished seventh chord. All of them use black keys
4 4 -> [empty output] // this is an augmented triad
3 3 -> B // this is a diminished triad
1 -> B E // this is just a minor second
11 -> C F // this is just a major seventh

Другие характеристики

  • Стандартные лазейки запрещены
  • Вы можете предположить, что на входе есть хотя бы одно целое число
  • Вы можете предположить, что все целые числа неотрицательны и меньше 12 (потому что фортепиано повторяет каждые 12 нот)
  • Вывод может быть в любом порядке

Критерии победы

Самое короткое действительное представление по состоянию на 15 апреля будет принято.

HyperNeutrino
источник
Мы можем предположить, что «неотрицательно и меньше 12» - разве это не должно быть «положительно и меньше или равно 12»?
Джонатан Аллан
@JonathanAllan Принципиально нет никакой разницы; мой метод допускает идеальный унисон, но не идеальную октаву; твой наоборот. Теоретически, ваше ограничение может иметь больше смысла, но я думаю, что мне, вероятно, не следует его менять, потому что уже есть ответы, и это не меняет проблему принципиально.
HyperNeutrino

Ответы:

3

Желе , 25 байт

236ḃ2ṙЀ7+\€Ṭ
+\ịþ¢Ạ€TịØA

Попробуйте онлайн! или посмотрите набор тестов

Как?

236ḃ2ṙЀ7+\€Ṭ - Link 1, white-note-offsets: no arguments
236ḃ2         - 236 in bijective base 2 [2, 2, 1, 2, 2, 1, 2] - semitones G->A, A->B ...
     ṙЀ7     - rotate left by, mapped over [1,2,3,4,5,6,7] - i.e. as above for each
                    starting white key (1st one A->B,B->C,...; 2nd B->C,C->D,...; etc)
         +\€  - reduce €ach with addition - i.e. absolute number of semitones: [[2,3,5,7,8,10,12],[1,3,5,6,8,10,12],[2,4,5,7,9,11,12],[2,3,5,7,9,10,12],[1,3,5,7,8,10,12],[2,4,6,7,9,11,12],[2,4,5,7,9,10,12]]
            Ṭ - untruth (vectorises) - make lists with 1s at those indexes: [[0,1,1,0,1,0,1,1,0,1,0,1],[1,0,1,0,1,1,0,1,0,1,0,1],[0,1,0,1,1,0,1,0,1,0,1,1],[0,1,1,0,1,0,1,0,1,1,0,1],[1,0,1,0,1,0,1,1,0,1,0,1],[0,1,0,1,0,1,1,0,1,0,1,1],[0,1,0,1,1,0,1,0,1,1,0,1]]

+\ịþ¢Ạ€TịØA - Main link: list of semitone gap integers (even negatives will work)
+\          - reduce by addition - gets the absolute semitone offsets needed
    ¢       - last link (1) as a nilad
   þ        - outer product with:
  ị         -     index into - 7 lists, each with 1s for white and 0s for black keys hit
                      note that indexing is modular and all the lists are length 12
                      so any integer is a valid absolute offset, not just 0-11 inclusive
     Ạ€     - all truthy for €ach - for each get a 1 if all keys are white ones, else 0
       T    - truthy indexes - get the valid starting white keys as numbers from 1 to 7
        ị   - index into:
         ØA -     the uppercase alphabet
Джонатан Аллан
источник
6

MATL , 31 байт

Спасибо Джонатану Аллану за исправление.

'BAGFEDC'"GYs12X\110BQX@YSYsm?@

Попробуйте онлайн! Или проверьте все тестовые случаи .

объяснение

Шаблон 2 2 1 2 2 2 1определяет интервалы между последовательными белыми клавишами. Программа использует цикл, который применяет все циклические сдвиги к этому базовому шаблону, чтобы проверить каждую клавишу как потенциальную нижнюю ноту входного аккорда. Для каждого сдвига получается совокупная сумма шаблона. Например, для Bпотенциальной нижней ноты шаблон был смещен, 1 2 2 1 2 2 2а его кумулятивная сумма равна 1 3 5 6 8 10 12.

Теперь, чтобы увидеть , если это может поддержать 4 3 3аккорд вычислит совокупную сумму интервалов аккордов, которая 4 7 10; уменьшить его с помощью 1 по модулю 12 (интервал 14даст 2); и проверьте, все ли числа являются членами допустимых значений 1 3 5 6 8 10 12. Это не тот случай в этом примере. Если бы это было так, мы бы вывели письмо B.

Соответствие между циклическими сдвигами и выходными буквами определяется строкой 'BAGFEDC'. Это указывает на то, что 'B'(первый символ) соответствует циклическому сдвигу на 1; 'A'(второй символ) соответствует циклическому сдвигу и 2т. д.

'BAGFEDC'  % Push this string
"          % For each character from the string
  G        %   Push input array
  Ys       %   Cumulative sum
  12X\     %   1-based modulo 12, element-wise (1,12,13,14 respectively give 1,12,1,2)
  110BQ    %   Push 110, convert to binary, add 1 element-wise: gives [2 2 1 2 2 2 1]
  X@       %   Push current iteration index, starting at 1
  YS       %   Cyclic shift to the right by that amount
  Ys       %   Cumulative sum
  m        %   Ismember. Gives an array of true of false entries
  ?        %   If all true
    @      %     Push current character
           %   End (implicit)
           % End (implicit)
           % Display (implicit)
Луис Мендо
источник
5

Mathematica, 110 байт (кодировка ISO 8859-1)

±i_:=#&@@@Select["A#BC#D#EF#G#"~StringTake~{Mod[#,12,1]}&/@#&/@(Accumulate[i~Prepend~#]&/@Range@12),FreeQ@"#"]

Определяет унарную функцию, ±принимающую список целых чисел в качестве входных данных (фактически, без ограничений на размер или знаки целых чисел) и возвращает список односимвольных строк. Например, ±{3,4}возвращает {"A","D","E"}.

"A#BC#D#EF#G#"~StringTake~{Mod[#,12,1]}&/@#это функция, которая превращает список целых чисел в соответствующие имена заметок, за исключением того, что #обозначает любой черный ключ. Это применяется к каждому элементу Accumulate[i~Prepend~#]&/@Range@12, который формирует список значений примечаний из списка ввода списка интервалов примечаний, начиная с каждой возможной примечания от 1 до 12. Мы отфильтровываем все такие списки имен примечаний, которые содержат "#"использование Select[...,FreeQ@"#"], а затем вернуть первое примечание в каждом оставшемся списке, используя #&@@@.

Грег Мартин
источник
Хорошая подача!
HyperNeutrino
Вопрос: Mathematica использует свою собственную систему байтов? Это 110 символов, но в UTF-8 это 111 байтов из-за +/-символа.
HyperNeutrino
Вы можете полностью удалить назначение и просто «неявно вернуть» функцию.
wizzwizz4
@ wizzwizz4: я обнаружил, что должен был назвать переменную, Accumulate[i~Prepend~#]&потому что иначе было бы столкновение карри. Не стесняйтесь найти обходной путь, хотя!
Грег Мартин
@HyperNeutrino: вы правы в том, что UTF-8 является стандартной кодировкой, но Mathematica может (обычно) функционировать и в кодировке ISO 8859-1. Я отметил это в посте.
Грег Мартин
3

Python 2, 159 155 байт

(Публикация этого после проверки того, что есть действительное представление, которое короче этого)

import numpy
s='C.D.EF.G.A.B'
def k(y):return lambda x:s[(x+y)%12]
for i in range(12):
    if s[i]!='.'and'.'not in map(k(i),numpy.cumsum(input())):print s[i]

Почти тривиальное решение. Входные данные в виде списка целых чисел и выходных данных с каждым символом в отдельной строке.

-4 байта, удалив ненужную переменную

HyperNeutrino
источник
3

JavaScript (ES6), 72 71 68 байт

a=>[..."C1D1EF1G1A1B"].filter((c,i,b)=>!+c>a.some(e=>+b[i+=e,i%12]))

Проходит по каждой клавише, пропуская черные клавиши, а затем проверяет, что кумулятивная сумма полутонов никогда не попадает на черную клавишу.

Изменить: Сохранено 3 байта благодаря @Arnauld.

Нил
источник
4
Читаемость ?! Вы уверены, что находитесь на правильном сайте? :-)
wizzwizz4