tło
W muzyce zachodniej każda nuta ma przypisaną nazwę. W każdej oktawie jest dwanaście unikalnych nut w następującej kolejności: „CC # / Db DD # / Eb EFF # / Gb GG # / Ab AA # / Bb B C”, gdzie końcowe C jest o jedną oktawę powyżej pierwszej.
Aby odróżnić nuty różnych oktaw, na końcu nazwy nuty dołączana jest liczba (dla tego wyzwania ograniczona do jednej cyfry). Zatem C5 jest nutą o jedną oktawę powyżej C4. Bb6 jest powyżej B5.
Ważnym faktem jest to, że B5 i C6 to nuty, które są tuż obok siebie, a C0 i B9 to najniższe i najwyższe nuty.
Między dowolnymi dwiema nutami znajduje się odległość, która jest liczbą półtonów między nimi. Bb4 to jeden półton poniżej B4, który sam jest jednym półtonem poniżej C5. W oktawie jest dwanaście półtonów, więc Bb4 to odległość 12 od A # 3, ponieważ jest to oktawa nad nim (zauważ, jak jedna nuta może mieć do dwóch nazw).
Wyzwanie
Twoim wyzwaniem jest napisanie możliwie najkrótszego programu, który może pobrać listę nut z STDIN i wydrukować listę zmian interwałów w STDOUT.
Dane wejściowe będą oddzieloną spacjami listą nut. Każda nuta będzie składać się z dużej litery AG, opcjonalnego znaku b lub # oraz cyfry jednocyfrowej. Nie będziesz musiał radzić sobie z E # / Fb lub B # / Cb. Przykładowe dane wejściowe:
C4 D4 E4 F4 G4 A4 B4 C5 C4
Wyjściem będzie oddzielona spacjami lista liczb całkowitych, które reprezentują odległość między kolejnymi nutami, zawsze poprzedzona znakiem + lub -, aby pokazać, czy notka rosła, czy opadała w stosunku do poprzedniej. Zawsze będzie wypisywana jedna liczba mniejsza niż wprowadzane nuty. Przykładowe dane wyjściowe dla powyższego wejścia:
+2 +2 +1 +2 +2 +2 +1 -12
Kilka innych przykładowych danych wejściowych:
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
I odpowiadające im wyniki:
-1 +1 -5 +5 +2 -2 -5
+11 +11 +11 +11 +11 +11 +11
+1 -2 +3 -4 +5
Zasady i ograniczenia
Zwycięzca zależy od liczby znaków w kodzie źródłowym
Twój program powinien składać się wyłącznie z drukowalnych znaków ASCII
Nie wolno używać żadnych wbudowanych funkcji związanych z muzyką lub dźwiękiem
Poza tym obowiązują standardowe zasady gry w golfa
źródło
+0
czy-0
może0
dla dwóch identycznych notatek?Odpowiedzi:
GolfScript, 61
źródło
Haskell, 161 znaków
źródło
Perl, 103
źródło
C, 123 znaki
Oparty na rozwiązaniu po lewej stronie, z pewnymi ulepszeniami.
Niektóre sztuczki, które moim zdaniem są warte wspomnienia:
1.
argv[0]
(tutaj nazywaneb
) to wskaźnik do nazwy programu, ale używany tutaj jako bufor scratch. Potrzebujemy tylko 4 bajtów (np.C#2\0
), Więc mamy dość.2.
c
jest liczbą argumentów, więc zaczyna się od 1 (gdy działa bez argumentów). Używamy go, aby zapobiec drukowaniu w pierwszej rundzie.Możliwy problem -
c+=b[..c+=..]
jest dość dziwny. Nie sądzę, że jest to niezdefiniowane zachowanie, ponieważ?:
jest to punkt sekwencyjny, ale może się mylę.źródło
c = c + b[..c+=..]
, to jest to dość wyraźnie niezdefiniowane zachowanie. Bez względu na sekwencjonowanie wewnątrz[..]
, nie wiesz, czy zewnętrznac
jest pobierana przed, w trakcie czy pob[..]
.REG=c;REG+=b[..c+=..];c=REG
. Będę jednak zaskoczony, widząc coś takiego w praktyce. Ale to wciąż UB.scanf
bez prototypu, i to jest w porządku. Po prostu dobrze wiedzieć, co jest, a co nie jest legalne w prawdziwym życiu :)DO,
241229183źródło
printf("%+d ",c-d)
.F(*b-65)
zamiastc-=65;
,b[1]<36&&++c||b[1]>97&&c--?2:1
->b[1]&16?1:(c+=b[1]%2*2-1,2)
, nadużywaj argumentu przez:main(e,b,c,d)char*b{
(Użyj pierwszego wskaźnika argumentu jako buforu roboczego).c=F(*b)%12
można go zastąpićc=-~*b*1.6;c%=12
. Dlaczego?sin
w oryginaleF
można zastąpić 9.6.c*1.6+9.6
jest(c+6)*1.6
,c-=65
i(c+6)
staje sięc-59
, a następniec+1
(60 * 96% 12 == 0).Współczynnik, 303 znaków
Z komentarzami
W tym skrypcie „lista rozdzielona spacjami” może zawierać 1 lub więcej spacji między elementami oraz 0 lub więcej spacji na początku lub na końcu. Ten skrypt drukuje dodatkową spację na końcu danych wyjściowych, ale akceptuje również dodatkową spację (lub znak nowej linii) na końcu danych wejściowych.
Jeśli przyjąłbym bardziej rygorystyczną definicję, w której „lista rozdzielona spacjami” ma dokładnie 1 spację między elementami i 0 spacji na początku lub na końcu, to mogę skrócić
contents R/ [#-b]+/ all-matching-slices
docontents " " split
(używającsplitting
, nieregexp
). Musiałbym jednak dodać więcej kodu, aby zapobiec dodatkowej przestrzeni na końcu danych wyjściowych.Jeśli używam przestarzałej słowo
dupd
, mogę skrócićover [ - "%+d " printf ] dip
dodupd - "%+d " printf
, oszczędzając 8 znaków. Nie używam przestarzałych słów, ponieważ „mają zostać wkrótce usunięte”.źródło