グレゴリオ教会の音楽を整理する


19

年は930年であり、グレゴリオ教会は問題を抱えています。彼らは数千ページの聖歌音楽を持っていますが、問題は実際の組織システムではなく、すべての楽譜が単に山に投げ込まれたことです。

楽譜の画像
Cartographers 'Guildのユーザーgamerprinterによる画像。

教会はすべての楽譜を整理する必要があるため、中世のソフトウェアエンジニアを雇ってプログラムを作成し、彼らのために整理しました。あなたは雇用されたソフトウェアエンジニアです。しかし、中世の編集プロセスでは、遅い聖書の筆記者のチームによってプログラムが紙に書き込まれます。スクライブのチームがコードをコンパイルするのにかかる時間を短縮するには、プログラムをできるだけ小さくする必要があります。

教会は、聖歌音楽が書かれている音階に基づいて編成されることを望んでいます。教会の聖歌音楽はすべてドリアン音階で書かれています。特定の音楽の音符が与えられると、プログラムはそれが入っているドリアン音階を出力します。ここでは、ドリアン音階とは何かを正確に説明します。すでに知っている場合は、このセクションをスキップできます。

どのメロディにも12の音符があります。ここに順序があります:

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

半音は、(使用して表されるS)の周りにラッピング(Bから半音アップバックCすることであろうように)、右に一歩をインクリメントします。トーン(使用して表現はT)2つの半音です。たとえば、F#からの半音はGです。F#からの半音はG#です。

ドリアンスケールを作成するには、リスト内の任意の音符から始めて、次のパターンで上に移動し、検出した音符をリストします。

T, S, T, T, T, S

例。私はAから始めます。ドリアンスケールのノートは次のようになります。

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種類のドリアン音階があり、各音階は、元の音符にちなんで命名されています。それらはそれぞれ、異なる位置から始めて、同じパターンのトーンとセミトーンを使用します。私の説明に一貫性がない場合は、ウィキペディア参照してください

プログラムの入力は、プログラムに適したもの(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を正しいキーとして明確に識別するのに十分な注意事項があります。他のドリアン音階は当てはまりません。他の音階を試しても、音階に属さないメロディーの音が少なくとも1つは常にあるからです。

これはコードゴルフであるため、文字数が最も少ないエントリが優先されます。ご質問がある場合はコメント欄でお尋ねください。


だから、私たちがすべきことは、最初のトーン/セミトーンのみを解釈することですか?
avall 14

avallごめんなさい、あなたの質問がわかりません。入力が常に強壮剤で始まるとは限りません。
アブサン14

他の例を提供してください。特に、強壮剤で始まっていないもの。
avall


1
@David このメタ質問に従って、チャレンジを開始してから12日間の待機期間の後、最短の回答を受け入れました。ちょうどCJamの答えが掲載されましたが起こった私が次に短いものを受け入れるつもりだったとき。
アブサン14

回答:



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での文字列の解析はそれほど簡単ではないので、より数学的なアプローチを採用しました。

5番目のサークルを利用します。一度に7半音のカウントアップ(「5番目」と呼ばれる)に基づいて次の順序で音符を並べると、特定の音階で許可されているすべての音符が7つの音符とすべての禁止音符の連続ブロックを形成していることがわかります5つの音の連続したブロックを形成します。

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

(これは円Fで、最後まで折り返します。)

上記のシーケンスの自然音の位置は、として計算できます(ASCII code) * 2 % 7。次に、次の文字が奇数の場合(#コンマ、スペース、またはゼロバイトには適用されませんが)、7を追加してシャープにします。使用されたメモのビットマップを保存します。

番号243(バイナリ11111000)は、A#ドリアンのスケールで禁止されている音符に対応しています。これを掛け(1<<12)+1=4097てマジックナンバーを出しました1016056。これは、メロディーに12音階の禁止音が順番に含まれているかどうかをチェックするために右シフトされます(ANDによって)。メロディに禁止音が含まれていない場合は、音階が印刷されます。

出力のために我々は我々がrightshiftingされているので、我々は後方に行くのを覚えて、上記の五分ののサイクルとは逆の順序で符号化されたスケールの名前を印刷する必要があります。)ASCIIシーケンスはADGCFBEADGCFによって生成されます65+i*3%7。これらの最初の5つについては、シャープも印刷する必要があります。

未ゴルフコード

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以下のその他の非空白文字)で区切る必要があります。最初のスペースが別の引数と見なされると、スペースをすべて使用できなくなります。64を超えるASCIIコードは、説明されている方法でメモとして解釈されます。


5分の1のサークルにこのプロパティがあることにショックを受けました!たぶんもう少しゴルフに使用できます。
レイ14

1
@Rayこれが実際に、私たちが持っている一連のメモを持っている理由です。オクターブの周波数比は2:1です。ピタゴラスで定義されている5番目は、3:2の比率であり、オクターブの後の最も重要な音楽間隔です。1.5 ^ 12は2 ^ 7に近いが2 ^ 7に等しくないため、現代の平均律の5分の1は1.4983に絞り込まれ、正確に12分の5が7オクターブに収まります。昔ながらの解決策は、サークルから入手可能な12個のノートのうち7個だけを使用することでした。そのため、不等間隔の7つのノートに基づくスケールがあります。ランダムな慣習ではなく、裏には確かな数学があります。
レベルリバーセント14

便宜上、音を5分の1にアレンジする楽器が多数あります(バイオリンはこのように調整され、ベースギターは4分の3に調整されます(比率は4:3です))。最も顕著な例(そして、私が知っている唯一の楽器は、優れた音響設計のために5分の1の円でレイアウトされています)は、steelpangoogle.es/patents/US7696421です。このレイアウトでは、叩く音の隣の音が少し鳴っても問題ありません。
レベルリバーセント14

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

Python 2-177文字

それほど短くはありませんが、ゴルフをしていないときでも、ネストされたforループを1行で複数記述することはPythonの喜びです。残念ながら、入力ステートメントを2行以上実行しないように、別の行に入力ステートメントを配置する必要がありました。

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そこに関数があるので、*リストのアンパック演算子を使用してlastを置き換えることで、括弧の必要性を相殺でき[0]ます。


2
また、Python 3で4文字を置き換えinputraw_input保存することもできます。
14

「ネストされたforループを1行で複数記述するPythonの喜び」:しかし、それらを読むことに喜びを感じていますか?
カレブポール14

@Wideshanksもちろんそうではありません...それはすべて書き込み専用のコードについてです!
feersum 14

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"and を許可するとcircle = circle0 ++ circle0、で連続した7つのノートを取得することで、すべてのスケールを作成できcircleます。

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

この方法で構築された各スケールでscale !! 3は、4番目の要素がスケール名です。

コード

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

Scala、 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))

五分円法を使用します。コマンドライン引数からの入力ie

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.