Gregoryen Kilisesi'nin Müziğini Düzenleyin


19

Yıl 930 ve Gregoryen Kilisesi bir sorun yaşıyor. Binlerce sayfa zikir müziği var, ama sorun şu ki, tüm notalar herhangi bir gerçek organizasyon sistemine sahip olmak yerine bir yığın üzerine atıldı:

Notalar resmi
Görüntü Haritacıları Loncası'nda kullanıcı oyun yazarı tarafından .

Kilise tüm notaları organize etmelidir, bu yüzden onlar için bir program düzenlemek için bir ortaçağ yazılım mühendisi tuttular. İşe alınan yazılım mühendisisiniz. Bununla birlikte, ortaçağ dönemlerinde derleme süreci, programın yavaş İncil yazarlarından oluşan bir ekip tarafından kağıda yazılmasını içerir. Scribler ekibinin kodunuzu derlemesi için geçen süreyi azaltmak için programı olabildiğince küçük hale getirmelisiniz.

Kilise tezahürat müziğinin yazıldığı müzikal skalaya göre düzenlenmesini istiyor. Kilisenin tezahürat müziğinin tamamı Dorian skalalarında yazılıyor . Belirli bir müzik parçasının notları göz önüne alındığında, programınız içinde bulunduğu Dor ölçeğini çıkaracaktır. Burada, tam olarak bir Dor ölçeğinin ne olduğunu açıklayacağım. Zaten biliyorsanız, bu bölümü atlayabilirsiniz.

Herhangi bir melodide 12 olası nota vardır. İşte sırayla:

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

bir yarım ton (a kullanılarak temsil edilir S) etrafa sarılarak bir adım sağa doğru artar (böylece B'den yarım ton C'ye geri döner). Bir ton (a kullanılarak temsil edilir T) iki yarı tondur . Örneğin, F # 'dan bir yarı ton G olur. F #' dan bir ton G # olur.

Bir Dorian ölçeği oluşturmak için listedeki herhangi bir nottan başlıyoruz ve ardından karşılaştığımız notları listeleyen aşağıdaki kalıpta ilerliyoruz:

T, S, T, T, T, S

Bir örnek. A'dan başlıyorum. Dorian ölçeğimin notları şöyle olur:

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)

Ölçek A, B, C, D, E, F # ve G notalarına sahiptir. A'dan başladığım için buna Dor ölçeği . Bu nedenle, her biri başladıkları nottan sonra adlandırılan 12 farklı Dorian ölçeği vardır. Her biri farklı bir konumdan başlayarak aynı tonları ve yarı tonları kullanır. Açıklamam tutarlı değilse Wikipedia'ya da başvurabilirsiniz .

Programın girişi programınız için uygun olan her şeyden verilebilir (örn. STDIN, komut satırı argümanı, raw_input() ). Bir değişkende önceden başlatılmamış olabilir. Giriş, parçanın melodisini temsil eden virgülle ayrılmış notların bir listesi olacaktır. Tekrarlanan notlar olabilir. Girdide her zaman parçanın ölçeğini kesin olarak çıkarabilmek için yeterli sayıda farklı not olacaktır. Örnek bir giriş:

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

Programın çıktısı string olmalıdır Dorian scale in X burada X, ölçeğin başlangıç ​​notudur. Örnek girişin çıktısı:

Dorian scale in B

Bunu B ( B C# D E F# G# A) ' deki Dor ölçeği ile karşılaştırarak melodinin tüm notalarının bu ölçek içinde olduğunu görüyoruz. Bu durumda C # notu kullanılmaz. Bununla birlikte, B Dorian'ı doğru bir anahtar olarak net bir şekilde tanımlamak için yeterli notlar vardır. Başka hiçbir Dorian ölçeği uymuyor, çünkü denediğimiz diğer ölçek ne olursa olsun, ölçeğe ait olmayan melodinin her zaman en az bir notu vardır.

Bu kod golf, bu yüzden en az karakter içeren giriş kazanır. Sorularınız varsa yorumlarda sorun.


Peki, yapmamız gereken sadece ilk tonu / yarı tonu yorumlamak mı?
avall

@Avall Üzgünüm, sorunuzu anlamıyorum. İstediğiniz buysa, giriş her zaman tonikle başlamaz .
Absinthe

Lütfen bize daha fazla örnek verin. Özellikle tonikle başlamayanlar.
avall


1
@David Bu meta soruya göre , meydan okumaya başladığımdan bu yana 12 günlük bir bekleme süresinden sonra en kısa cevabı kabul ettim. Sadece CJam cevap gönderilmiş oldu sağ sonraki en kısa birini kabul edecek zaman.
Absinthe

Yanıtlar:



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'de dizeleri ayrıştırmak o kadar kolay değil, bu yüzden daha matematiksel bir yaklaşıma gittim.

Beşinci Çemberden faydalanıyorum. Notları bir seferde 7 yarı ton saymaya dayalı olarak ("beşinci" olarak bilinir) aşağıdaki sırada düzenlersek, herhangi bir ölçekte izin verilen tüm notların ardışık 7 nota ve tüm yasak notları oluşturduğunu tespit ederiz. 5 notadan oluşan ardışık bir blok oluşturur.

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

(bu bir daire, Fsonuna kadar geri sarar .)

Yukarıdaki notta doğal bir notanın konumu olarak hesaplanabilir (ASCII code) * 2 % 7. Sonra bir sonraki karakter garipse ( #virgül, boşluk veya sıfır bayt için geçerlidir ancak geçerli değildir) keskinleştirmek için 7 ekleriz. Kullanılan notların bir bitmap'ini saklarız.

Sayı 243(ikili 11111000), A # Dorian ölçeğinde yasaklanan notlara karşılık gelir. Ben bu çarpılır (1<<12)+1=4097sihirli numarası vermek 1016056. Bu, melodinin sırayla 12 ölçeğin her biri için yasaklanmış notlar içerip içermediğini kontrol etmek (ANDing ile) hakkına sahiptir. Melodi yasaklanmış notlar içermiyorsa, ölçek yazdırılır.

Çıktı için yukarıdaki beşinci döngünün tersi sırada kodlanmış ölçek adını yazdırmamız gerekiyor, unutmayın ki geriye doğru gidiyoruz çünkü hak değiştiriyoruz.) ASCII dizisi ADGCFBEADGCFtarafından üretiliyor 65+i*3%7. Bunların ilk beşinde keskin bir baskı da yapılmalıdır.

Kod çözülmemiş kod

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.
}

Geçersiz giriş davranışı: Ölçeği net bir şekilde belirlemek için yeterli not yoksa, olası tüm ölçeklerin çıktısını alır. İmkansız bir not kombinasyonu sağlanırsa, hiçbir şey çıktılamaz. Notlar bir virgülle (veya eşit ASCII kodu <= 64 olan boşluk olmayan bir karakterle) sınırlandırılmalıdır. İlk boşluktan sonraki her şey farklı bir argüman olarak değerlendirileceğinden boşluklar kullanılamaz. ASCII kodları> 64, açıklanan şekilde notlar olarak yorumlanacaktır.


Beşinci çemberin bu özelliğe sahip olması beni şok etti! Belki biraz daha golf oynamak için kullanabilirsiniz.
Ray

1
@Ray Aslında bu yüzden sahip olduğumuz not setine sahibiz. Oktavın frekans oranı 2: 1'dir. Pisagor tarafından tanımlanan beşinci oran 3: 2'dir ve oktavdan sonraki en önemli müzikal aralıktır. 1.5 ^ 12, 2 ^ 7'ye yakın fakat eşit olmadığından, modern eşit temperli beşinci 1.4983'e kadar sıkıştırılır, böylece 7 oktav'a tam olarak 12 beşinci sığar. Eski moda çözüm, mevcut 12 kağıttan sadece 7 nota kullanmaktı. Bu nedenle, düzensiz aralıklı 7 nota dayalı bir ölçeğimiz var. Bu rastgele bir ibadet değil, arkasında sağlam matematik var.
Level River St

Kolaylık nedenleriyle beşinci olarak notalar düzenleyen bir dizi enstrüman vardır (keman bu şekilde ayarlanır ve bas gitar dördüncü olarak ayarlanır, bu da 4: 3 oranıdır). En çarpıcı örnek (ve iyi akustik tasarım için beşinci bir daireye yerleştirilmiş notaları olduğunu bildiğim tek enstrüman) steelpan: google.es/patents/US7696421 . Bu düzende, vurduğunuz notun yanındaki notanın biraz çalması önemli değildir.
Level River St

4

Haskell - 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

Ungolfed

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 karakter

O kadar kısa değil, ama golfde değilken bile, bir satırda döngüler için çoklu iç içe yazmanın Python'un sevincini buluyorum. Ne yazık ki, giriş deyimini birden fazla yürütmek için ayrı bir satıra koymak zorunda kaldım.

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 kullanmıyorum, ancak baskı ifadesinin daha fazla karaktere ihtiyaç duymadığı zaman bunun nadir bir örnek olduğuna inanıyorum. Yana printbir fonksiyon vardır, ben kullanımıyla parantez ihtiyacını dengelemek mümkün olacaktır *son yerine operatörü açma listede [0].


2
Ayrıca yerine mümkün olurdu inputiçin raw_inputPython 3'te 4 karakter ve kaydedin
comperendinous

"Python'un döngüler için bir satırda birden çok yuva yazmanın sevincini buluyorum": ama onları okurken neşe duyuyor musunuz?
Caleb Paul

@Wideshanks Elbette hayır ... her şey salt yazılan kodla ilgili!
feersum

3

Yakut - 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}

Komut satırı değişkenlerinden giriş.
Örneğinruby dorianscale.rb B,B,D,E,D,B,A,G#,A,G#,E,D,F#,E,F#,E,F#,G#,A

Deneyin: ideone


3

Haskell - 140

@Steveverrill tarafından sunulan Circle of Fifths özelliğinden yararlanın. Biz izin verirsek circle0 = words "C G D A E B F# C# G# D# A# F"ve circle = circle0 ++ circle0o zaman içinde birbirini izleyen 7 notlar alarak tüm ölçekler oluşturabilirsiniz circle.

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

Bu şekilde oluşturulan her ölçekte scale !! 3, 4. element ölçek adıdır.

kod

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

Ungolfed

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

Beşinci daire yöntemini kullanma. Komut satırı argümanlarından girdi yani

scala dorianscale.scala B,B,D,E,D,B,A,G#,A,G#,E,D,F#,E,F#,E,F#,G#,A
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.