Фон
В западной музыке каждой музыкальной ноте присвоено имя. Внутри каждой октавы есть двенадцать уникальных нот в следующем порядке: «CC # / Db DD # / Eb EFF # / Gb GG # / Ab AA # / Bb B C», где конечное значение C на одну октаву выше первого.
Чтобы определить разницу между нотами разных октав, к концу имени ноты добавляется число (для этой задачи, ограниченное одной цифрой). Таким образом, C5 - это нота, которая на одну октаву выше C4. Bb6 выше B5.
Важным фактом является то, что B5 и C6 являются нотами, которые находятся рядом друг с другом, и что C0 и B9 являются самыми низкими и самыми высокими нотами.
Между любыми двумя нотами есть расстояние, которое является количеством полутонов между ними. Bb4 - это один полутон ниже B4, который сам на полутон ниже C5. В октаве двенадцать полутонов, поэтому Bb4 на расстоянии 12 от A # 3, так как он выше октавы (обратите внимание, что одна нота может иметь до двух имен).
Соревнование
Ваша задача - написать максимально короткую программу, которая может взять список музыкальных нот из STDIN и распечатать список интервальных изменений в STDOUT.
Ввод будет разделенный пробелами список музыкальных нот. Каждая заметка будет состоять из заглавной буквы AG, необязательного знака b или # и однозначного числа. Вам не придется иметь дело с E # / Fb или B # / Cb. Пример ввода:
C4 D4 E4 F4 G4 A4 B4 C5 C4
Выходными данными будет список целых чисел, разделенных пробелами, которые представляют расстояние между каждой последовательной заметкой, всегда с префиксом + или -, чтобы показать, была ли заметка восходящей или нисходящей относительно предыдущей. Всегда будет выводиться на один номер меньше, чем вводимые заметки. Пример вывода для вышеуказанного ввода:
+2 +2 +1 +2 +2 +2 +1 -12
Еще несколько примеров ввода:
E5 D#5 E5 B4 E5 F#5 E5 B4
C0 B0 Bb1 A2 G#3 G4 F#5 F6
G4 Ab4 Gb4 A4 F4 A#4
И их соответствующие выводы:
-1 +1 -5 +5 +2 -2 -5
+11 +11 +11 +11 +11 +11 +11
+1 -2 +3 -4 +5
Правила и ограничения
Победитель определяется по количеству символов в исходном коде
Ваша программа должна состоять только из печатных символов ASCII
Вам не разрешается использовать какие-либо встроенные функции, связанные с музыкой или звуком.
Кроме этого, применяются стандартные правила игры в гольф.
источник
+0
или-0
или0
для двух одинаковых заметок?Ответы:
GolfScript, 61
источник
Хаскель, 161 персонажа
источник
Perl, 103
источник
C, 123 символа
Основано на решении leftaroundabout, с некоторыми улучшениями.
Некоторые трюки, о которых я думаю, заслуживают упоминания:
1.
argv[0]
(здесь он называетсяb
) - указатель на имя программы, но здесь он используется в качестве чистого буфера. Нам нужно всего 4 байта (напримерC#2\0
), поэтому нам достаточно.2.
c
это число аргументов, поэтому оно начинается с 1 (при запуске без аргументов). Мы используем его для предотвращения печати в первом раунде.Возможная проблема -
c+=b[..c+=..]
довольно странная. Я не думаю, что это неопределенное поведение, потому что?:
это точка последовательности, но, возможно, я ошибаюсь.источник
c = c + b[..c+=..]
, то это довольно явно неопределенное поведение. Независимо от последовательности внутри[..]
, вы не знаете, извлекается ли внешнееc
до, во время или послеb[..]
.REG=c;REG+=b[..c+=..];c=REG
. Тем не менее, я буду удивлен, увидев что-то подобное на практике. Но это все еще UB.scanf
без прототипа, и это нормально. Просто полезно знать, что является и не является законным в реальной жизни :)C,
241229183источник
printf("%+d ",c-d)
.F(*b-65)
вместоc-=65;
,b[1]<36&&++c||b[1]>97&&c--?2:1
->b[1]&16?1:(c+=b[1]%2*2-1,2)
злоупотребьте argv:main(e,b,c,d)char*b{
(используйте первый указатель аргумента в качестве рабочего буфера).c=F(*b)%12
можно заменить наc=-~*b*1.6;c%=12
. Почему?sin
в оригиналеF
можно заменить на 9.6.c*1.6+9.6
это(c+6)*1.6
,c-=65
и(c+6)
сталиc-59
, а затемc+1
(60 * 96% 12 == 0).Фактор, 303 символа
С комментариями,
Для этого сценария «разделенный пробелами список» может содержать 1 или более пробелов между элементами и 0 или более пробелов в начале или конце. Этот скрипт выводит дополнительный пробел в конце вывода, но он также принимает дополнительный пробел (или перевод строки) в конце ввода.
Если бы я принял более строгое определение, где «список, разделенный пробелами», имеет ровно 1 пробел между элементами и 0 пробелов в начале или конце, то я могу сократить
contents R/ [#-b]+/ all-matching-slices
доcontents " " split
(используяsplitting
, а неregexp
). Тем не менее, мне нужно было бы добавить больше кода, чтобы предотвратить дополнительное пространство в конце вывода.Если я использую устаревшее слово
dupd
, я могу сократитьover [ - "%+d " printf ] dip
доdupd - "%+d " printf
8 символов. Я не использую устаревшие слова, потому что они «должны быть удалены в ближайшее время».источник