Мажор-минорная дихотомия

15

Учитывая список аккордов, пометьте их как «Major» или «Minor».

вход

Ввод будет список аккордов, по одному на строку, состоящий из 3 нот, разделенных пробелом. Каждая заметка будет состоять из имени заметки в верхнем регистре ( A- G) и необязательного случайного ( #или b). Аккорды могут быть в любой инверсии (т.е. ноты могут быть в любом порядке).

Выход

Если аккорд мажорный, выведите «Major». Если аккорд минорный, выведите «Minor». Если аккорд не является мажорным или минорным, выведите пустую строку.

пример

вход

C E G
F Ab C
C Eb Gb
E G B
Db F Ab
Bb G D
D A Gb

Выход

Major
Minor

Minor
Major
Minor
Major

Тестовые сценарии

Как и в некоторых из моих прошлых вопросов, я еще раз вырезал некоторые тестовые сценарии, изначально созданные Джои и Вентеро, чтобы предоставить несколько тестовых примеров для этого вопроса:

Использование: ./test [your program and its arguments]

Награды

Каждая заявка, которую я могу проверить, которая соответствует спецификации, проходит тесты и, очевидно, была попытка сыграть в гольф, получит от меня отклик (поэтому, пожалуйста, предоставьте инструкции по использованию вместе с вашим ответом). Самое короткое решение к концу 13/10/2012 будет принято победителем.

Немного теории

Для тех из вас, у кого нет знания музыкальной теории, здесь достаточно информации, чтобы вы могли соревноваться.

Мажорный или минорный аккорд состоит из трех нот, которые разделены определенным рисунком полутонов. Если мы считаем, что корень (нижняя нота) аккорда равен 0, то мажорный аккорд - это паттерн 0-4-7, а минорный аккорд - это паттерн 0-3-7. Вещи становятся более неловкими из-за того, что некоторые ноты разделены полутоном, а некоторые - тоном. Распространение полутонов из Ab- G#выглядит следующим образом:

G#/Ab A A#/Bb B/Cb B#/C C#/Db D D#/Eb E/Fb E#/F F#/Gb G G#/Ab
  0   1   2    3     4    5   6   7    8     9    10  11  12

G#/Abозначает, что G#это то же самое примечание, что и Ab. Из этого мы можем видеть, что аккорд Ab C Eb- это основной аккорд, а это Ab Cb Ebминор.

Мудрить дальше, аккорд Eb Cb Abсчитается таким же , как Ab Cb Eb, Cb Eb Abи Cb Ab Ebтак далее. Каждый из этих вариантов по-прежнему второстепенный аккорд.

Gareth
источник
2
Я думаю, что ваш bash-тестер нуждается во вводе данных и ожидаемых ответах.
Flodel
@flodel Да, ты прав. Извините, я исправил это сейчас. Мне нужно убедиться, что у тестового скрипта Powershell нет такой же проблемы.
Гарет

Ответы:

3

GolfScript, 83 символа

n%{' '%{1\{'A#BC D EF G'?+}/.}%$(+2/{~- 12%}%.(+.(+]$0=.$]10,7>?'MMaijnoorr

'>2%}%

Это быстрое первое решение; Я уверен, что это может быть дальше. Проходит набор тестов bash, после исправления ошибки, указанной flodel в комментариях.

Редактировать 1: Сохранены 5 символов с более коротким способом распознавания канонизированных паттернов мажорных и минорных аккордов.

Редактировать 2: Сохранено еще 2 символа с более компактной кодировкой вывода, основанной на решении grc. (Спасибо!) Как побочный эффект, код теперь печатает дополнительную пустую строку после вывода, но тестовый жгут, кажется, принимает это, так что я думаю, что все в порядке. :)

Вот как это работает:

  • Внешний цикл n%{ }%n*просто разбивает входные данные на строки, запускает код внутри фигурных скобок для каждой строки и объединяет результаты с новыми строками.

  • ' '%разбивает каждую строку на массив заметок. Для каждой из этих заметок 1\{'A#BC D EF G'?+}/затем преобразует эту заметку в число полутонов путем поиска каждого из ее символов в строке 'A#BC D EF G'и суммирования позиций (что будет равно -1 для любого символа, не найденного в строке, особенно включая b). (Я уверен, что я видел этот трюк, использованный ранее.) Наконец, .дублирует каждое число, так что в конце цикла, например, вход F Ab Cбыл превращен [9 9 0 0 4 4].

  • Затем мы сортируем заметки с помощью $, перемещаем первую заметку в конец (+и разделяем массив на пары 2/, чтобы он теперь выглядел, например, так [[9 0] [0 4] [4 9]]. Затем {~- 12%}%сопоставляет каждую пару нот по разности по модулю 12, превращая наш примерный массив в [9 8 7].

  • Далее .(+делает копию массива и поворачивает его элементы влево на одну позицию. Мы делаем это дважды и собираем копии в массив ], так что наш пример теперь выглядит так [[9 8 7] [8 7 9] [7 9 8]].

  • Затем мы сортируем этот массив массивов с $помощью первого элемента - в данном случае [7 9 8]- с помощью 0=. Затем мы создаем копию этого array ( .), сортируем его ( $), собираем как несортированный, так и несортированный массив в другой массив arrays ( ]), и ищем первое вхождение массива [7 8 9](которое написано так, 10,7>чтобы сохранить два символа) ) в этом.

  • Это дает нам либо 0(если несортированный массив был [7 8 9], и, следовательно, аккорд мажорный), 1(если несортированный массив был перестановкой [7 8 9], что, учитывая, что его первый элемент должен быть наименьшим, может быть только [7 9 8], делая аккорд второстепенным), или -1(если даже отсортированный массив не равен [7 8 9]).

  • Затем это число используется в качестве начального индекса в строке "MMaijnoorr\n\n"(где \ns задаются как фактические переводы строки в коде), из которого мы берем этот символ и каждый второй последующий в качестве вывода. Если индекс равен -1, мы начинаем с последнего символа строки, который является просто переводом строки.

Илмари Каронен
источник
Хорошее объяснение. У меня та же самая проблема, с которой я всегда сталкиваюсь с GolfScript - я могу вызвать строку для тестирования, echo "G# B# Eb" | ruby golfscript.rb ilmari.gsно как мне запустить на ней тестовый скрипт? Я пытался, ./test ruby golfscript.rb ilmari.gsно ничего не получалось. (Я уже дал вам +1, потому что это, очевидно, работает, но мне просто любопытно)
Гарет
1
@Gareth: похоже, это ошибка в скрипте bash test - он не обрабатывает несколько аргументов правильно. Чтобы исправить это, замените args="$@"на args=("$@")и got=$("$cmd" "$args")с got=$("$cmd" "${args[@]}"). (Или просто сделайте golfscript.rbисполняемый файл и запустите его как ./test ./golfscript.rb chords.gs.)
Илмари Каронен
4

Питон, 160

f='A#BC D EF G3453543'.find
try:
 while 1:x,y,z=sorted(map(lambda x:f(x[0])+f(x[1:])+1,raw_input().split()));print'MMianjoorrr'[f(`y-x`+`z-y`)/14:-1:2]
except:0
GRC
источник