그레고리오 교회 음악 조직


19

올해는 930 년이며 그레고리 교회는 문제가 있습니다. 그들은 수천 페이지의 노래 음악을 가지고 있지만 문제는 모든 악보가 실제 조직 시스템 대신 더미에 던져 졌다는 것입니다.

악보의 이미지
Cartographers 'Guild의 사용자 게이머 프린터 이미지 .

교회는 모든 악보를 정리해야하므로 중세 소프트웨어 엔지니어를 고용하여이를 정리하기위한 프로그램을 작성했습니다. 귀하는 고용 된 소프트웨어 엔지니어입니다. 그러나 중세 시대의 편집 과정에는 느린 성서 필자 팀이 종이에 프로그램을 작성하는 과정이 포함됩니다. 서기관 팀이 코드를 컴파일하는 데 걸리는 시간을 줄이려면 프로그램을 가능한 작게 만들어야합니다.

교회는 성가 음악을 그들이 작곡 한 음계에 기초하여 조직하기를 원합니다. 교회의 성가 음악은 모두 도리안 음표 로 쓰여집니다 . 특정 음악에 대한 음표가 주어지면 프로그램은 도리안 음계를 출력합니다. 여기에서는 도리안 음계가 무엇인지 정확하게 설명하겠습니다. 이미 알고 있다면이 섹션을 건너 뛸 수 있습니다.

모든 멜로디에는 12 가지 음표가 있습니다. 여기 순서대로 있습니다 :

C C# D D# E F F# G G# A A# B

반음 (a를 이용하여 표현되는 S) (B로부터 C 반음 업 다시 될 수 있도록) 감싸 오른쪽으로 한 단계 증가된다. (a를 이용하여 표현되는 T) 두 반음이다. 예를 들어, F #의 반음은 G가됩니다. F #의 음은 G #이됩니다.

Dorian 스케일을 만들려면 목록의 음표에서 시작한 후 다음 패턴으로 올라가서 발생하는 음표를 나열합니다.

T, S, T, T, T, S

예입니다. A에서 시작합니다. Dorian 스케일의 메모는 다음과 같습니다.

A
B  (up a tone)
C  (up a semitone)
D  (up a tone)
E  (up a tone)
F# (up a tone)
G  (up a semitone)

음계에는 A, B, C, D, E, F # 및 G라는 메모가 있습니다. A부터 시작 했으므로이를 도리안 음계를 A라고 합니다. 따라서 12 개의 서로 다른 도리안 저울이 있으며, 각각의 저울은 시작된 음표의 이름을 따서 명명되었습니다. 각기 다른 위치에서 시작하여 동일한 톤과 반음 패턴을 사용합니다. 내 설명이 일관성이 없다면 Wikipedia참조하십시오 .

프로그램의 입력은 프로그램에 적합한 것 (예 : STDIN, 명령 행 인수, raw_input())에서 제공 될 수 있습니다. 변수에서 사전 초기화되지 않았을 수 있습니다. 입력은 곡의 멜로디를 나타내는 쉼표로 구분 된 음표 목록이됩니다. 반복되는 메모가있을 수 있습니다. 입력에 항상 다른 음표가있어 조각의 스케일을 결정적으로 추론 할 수 있습니다. 입력 예 :

B,B,D,E,D,B,A,G#,A,G#,E,D,F#,E,F#,E,F#,G#,A

프로그램의 출력은 string이어야합니다. Dorian scale in X여기서 X는 스케일의 시작 참고입니다. 예제 입력의 출력 :

Dorian scale in B

이것을 B ( B C# D E F# G# A) 의 도리안 스케일과 비교하면 멜로디의 모든 음이이 스케일 내에 있음을 알 수 있습니다. 이 경우 메모 C #은 사용되지 않습니다. 그러나 B Dorian을 올바른 키로 명확하게 식별하기에 충분한 메모가 있습니다. 우리가 시도하는 다른 스케일에 관계없이 스케일에 속하지 않는 멜로디에 대해 적어도 하나의 음표가 항상 있기 때문에 다른 Dorian 스케일은 맞지 않습니다.

이것은 코드 골프이므로 문자 수가 가장 적은 항목이 승리합니다. 질문이 있으면 의견을 물어보십시오.


우리가해야 할 일은 첫 번째 톤 / 세미 톤 만 해석하는 것입니까?
avall

죄송합니다. 귀하의 질문을 이해하지 못합니다. 입력이 항상 토닉으로 시작 되는 것은 아닙니다 .
absinthe

더 많은 예제를 제공해주세요. 특히 강장제로 시작하지 않는 것들.
avall


1
@David 이 메타 질문에 따르면, 나는 도전을 시작한 후 12 일 동안 기다린 후에 가장 짧은 답변을 수락했습니다. 단지 CJam 답변이 게시 된 일이 바로 내가 다음 짧은 하나를 받아 갈 때.
압생트

답변:



8

C, 171 146

i,b;main(int c,char**v){for(;c=v[1][i];)b|=c/65<<c*2%7+v[1][++i]%2*7;for(i=12;i--;)b&(1016056>>i)||printf("Dorian scale in %c%c",65+i*3%7,(i<5)*35);}

C에서 문자열을 파싱하는 것은 쉽지 않으므로 더 수학적 접근 방식을 사용했습니다.

나는 Circle of Fifths를 활용합니다. 한 번에 7 개의 반음을 세는 것에 따라 다음 순서로 음표를 배열하면 ( "제 5"), 주어진 음계에서 허용 된 모든 음표는 7 개의 음표와 금지 된 음표의 연속 블록을 형성합니다. 5 개 음표의 연속적인 블록을 형성합니다.

F C G D A E B F# C# G# D# A#

(원으로 F끝까지 다시 감 쌉니다 .)

위 순서에서 자연 음의 위치는로 계산할 수 있습니다 (ASCII code) * 2 % 7. 다음 문자가 홀수이면 ( #쉼표, 공백 또는 0 바이트에는 적용 되지 않음) 7을 더해 선명하게 만듭니다. 사용 된 메모의 비트 맵을 저장합니다.

243(이진11111000 )는 A # Dorian 규모로 금지 된 메모에 해당합니다. 나는 이것을 (1<<12)+1=4097매직 넘버를주기 위해 곱했다 1016056. 멜로디에 12 개 음계 각각에 대해 금지 된 음표가 차례대로 포함되어 있는지 확인하기 위해 오른쪽으로 이동합니다 (AND 링으로). 멜로디에 금지 된 음표가없는 경우 음계가 인쇄됩니다.

출력의 경우, 위의 5 분의 1의 순서로 역순으로 인코딩 된 스케일 이름을 인쇄해야합니다. 오른쪽으로 이동하기 때문에 뒤로 가고 있음을 기억하십시오.) ASCII 시퀀스 ADGCFBEADGCF 는로 생성됩니다 65+i*3%7. 이 중 첫 5 개를 위해서는 샤프도 인쇄해야합니다.

Ungolfed 코드

i,b;
main(int c,char**v){
  for(;c=v[1][i];)                          //for each character in first commanline argument v[1]
                                               //if it is a letter (assume uppercase, ASCII 65 or over)
   b|=c/65<<c*2%7+v[1][++i]%2*7;               //convert to position in the circle of fifths. 
                                               //Add 7 if the next character is odd (ASCII'#')
                                               //leftshift 1 by this number and OR this with the contents of b.

  for(i=12;i--;)b&(1016056>>i)||printf         //if melody includes no prohibited notes for the scale i, print
   ("Dorian scale in %c%c",65+i*3%7,(i<5)*35); //the scale letter, and a # (ASCII 35) if required, otherwise an ASCII 0.
}

유효하지 않은 입력 동작 : 음표를 불명확하게 결정하기에 불충분 한 음표가 제공되면 가능한 모든 음계가 출력됩니다. 불가능한 음표 조합이 제공되면 아무 것도 출력하지 않습니다. 메모는 쉼표로 구분해야합니다 (또는 ASCII 코드 <= 64 인 다른 비 공백 문자). 공백은 첫 번째 공백이 다른 인수로 간주 된 후 모든 문자로 사용될 수 없습니다. ASCII 코드> 64는 설명 된 방식으로 메모로 해석됩니다.


5 분의 1의 원이이 속성을 가지고 있다는 사실에 충격을 받았습니다! 어쩌면 나는 좀 더 골프를 치기 위해 그것을 사용할 수 있습니다.
Ray

1
@Ray 이것이 실제로 우리가 가지고있는 노트 세트가있는 이유입니다. 옥타브의 주파수 비율은 2 : 1입니다. 피타고라스가 정의한 다섯 번째는 3 : 2의 비율을 가지며 옥타브 다음으로 가장 중요한 음악 간격입니다. 1.5 ^ 12는 2 ^ 7에 가깝지만 같지 않기 때문에 현대의 동일 강화 다섯 번째는 1.4983로 압축되어 정확히 12 개의 다섯 번째가 7 옥타브에 맞습니다. 구식 솔루션은 서클에서 사용 가능한 12 개 중 7 개의 노트 만 사용하는 것이 었습니다. 그렇기 때문에 우리는 7 개의 고르지 않은 음표를 기준으로 음계를 갖게됩니다. 그것은 임의의 규칙이 아니며, 그 뒤에 확실한 수학이 있습니다.
Level River St

편의상 5 분 안에 음표를 배열하는 많은 악기가 있습니다 (바이올린은 이런 방식으로 조정되고베이스 기타는 4 분의 4로 조정되며 4 : 3의 비율입니다). 가장 눈에 띄는 예는 (그리고 좋은 음향 설계를 위해 5 분의 1의 음표로 메모 한 노트가있는 유일한 도구) steel.google.es/patents/US7696421 입니다. 이 레이아웃을 사용하면 타격하는 음표 옆의 음표가 약간 울리는 지 중요하지 않습니다.
Level River St

4

하스켈-152

w=words
n=w"C C# D D# E F F# G G# A A# B"
f s="Dorian scale in "++[n!!i|i<-[0..11],all(`elem`[(n++n)!!(i+j)|j<-[0,2,3,5,7,9,10]])s]!!0
main=interact$f.w

언 골프

type Note = String
type Scale = [Note]

notes :: [Note]
notes = words "C C# D D# E F F# G G# A A# B"

isScale :: Scale -> [Note] -> Bool
isScale scale notes = all (`elem` scale) notes

takeScale :: Int -> Scale
takeScale i = [(notes ++ notes) !! (i + j) | j <- [0, 2, 3, 5, 7, 9, 10]]

findScale :: [Note] -> Note
findScale xs = head [notes !! i | i <- [0..11], isScale (takeScale i) xs]

main = interact (("Dorian scale in "++) . findScale . words)

3

파이썬 2-177 자

그렇게 짧지는 않지만 골프를하지 않을 때조차도 한 줄에 여러 개의 중첩 된 for 루프를 작성하는 것이 Python의 기쁨입니다. 불행히도 입력 명령문을 별도의 줄에 넣어 두 번 이상 실행되지 않도록해야했습니다.

j=set(raw_input().split(','))
print"Dorian Scale in",[x for x in[["A A# B C C# D D# E F F# G G#".split()[(b+n)%12]for n in[0,2,3,5,7,9,10]]for b in range(12)]if j<set(x)][0][0]

Python 3을 사용하지 않지만 print 문에 더 많은 문자가 필요하지 않은 경우는 드문 경우라고 생각합니다. print거기에 함수가 있기 때문에 *list unpacking operator를 사용하여 마지막을 대체하여 괄호의 필요성을 상쇄 할 수 있습니다 [0].


2
또한 대체 할 수있을 것 input를위한 raw_input파이썬 3에서 4 개 문자를 저장
comperendinous

"한 줄에 여러 개의 중첩 된 for 루프를 작성하는 것이 파이썬의 기쁨이라고 생각합니다.하지만 읽을 때 기쁨이 있습니까?
Caleb Paul

@Wideshanks 물론 아닙니다 ... 쓰기 전용 코드에 관한 것입니다!
feersum

3

루비-132

12.times{|i|$*[0].split(?,)-(g=(0..6).map{|j|%w{C C# D D# E F F# G G# A A# B}[-i+=~(58>>j&1)]})==[]?(puts"Dorain scale in "+g[0]):g}

명령 행 인수에서 입력
예 :ruby dorianscale.rb B,B,D,E,D,B,A,G#,A,G#,E,D,F#,E,F#,E,F#,G#,A

그것을보십시오 : ideone


3

하스켈-140

@steveverrill이 소개 한 Circle of Fifths 속성을 활용하십시오. 우리가 할 수있는 경우 circle0 = words "C G D A E B F# C# G# D# A# F"circle = circle0 ++ circle0, 우리는에서 연속 7 개 메모를 모든 스케일을 구성 할 수 있습니다 circle.

scales = [take 7 . drop i $ circle | i <- [0..11]]

이 방법으로 구성된 각 스케일 scale !! 3에서, 네 번째 요소는 스케일 이름입니다.

암호

w=words
n=w"C G D A E B F# C# G# D# A# F"
f s="Dorian scale in "++[x!!3|x<-[take 7.drop i$n++n|i<-[0..]],all(`elem`x)s]!!0
main=interact$f.w

언 골프

type Note = String
type Scale = [Note]

notes :: [Note]
notes = words "C G D A E B F# C# G# D# A# F"

scales :: [Scale]
scales = [take 7 . drop i $ notes ++ notes | i <- [0..11]]

findScale :: [Note] -> Note
findScale xs = head [scale !! 3 | scale <- scales, all (`elem` scale) xs]

main = interact (("Dorian scale in "++) . findScale . words)

2

스칼라, 130 128 127

print("Dorian scale in "+(".#?".r findAllIn "FCGDAEBF#C#G#D#A#"*2 sliding(7)find{l=>args(0)split','forall(l contains _)}get 3))

5의 원을 사용하는 방법. 명령 행 인수 입력

scala dorianscale.scala B,B,D,E,D,B,A,G#,A,G#,E,D,F#,E,F#,E,F#,G#,A
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.