Bantu Saya Memainkan Harmonika Saya

8

Kemarin, saya membeli harmonika:

harmonika saya Gambar 1: Harmonika.

Namun, impian saya untuk dapat memainkan harmonika blues yang menggetarkan jiwa yang menggerakkan orang dan menyebabkan seorang pria dewasa menangis dengan cepat hancur oleh dua masalah:

  1. Harmonika hanya dapat memainkan not tertentu;
  2. Saya sangat buruk bermain harmonika.

Terlepas dari kurangnya keterampilan saya di harmonika, masih ada beberapa lagu yang bisa saya mainkan di sana. Namun, tidak segera jelas apakah saya dapat memainkan musik di harmonika atau tidak. Dengan memberikan not pada sebuah karya musik, tulislah sebuah program untuk menentukan apakah saya dapat memutarnya di harmonika atau tidak.

Seperti yang ditunjukkan gambar di atas, harmonika saya memiliki sepuluh lubang di dalamnya. Dengan setiap lubang, saya bisa menghembuskannya atau menghirupnya - lubang yang saya pilih, dan apakah saya menghirup atau menghembuskannya, mengubah nada suara yang dihasilkan. Setiap lubang memiliki nada yang berbeda untuk mengeluarkan dan menghirup, tetapi ada beberapa kombinasi yang menghasilkan nada yang sama. Secara keseluruhan, harmonika saya dapat memainkan 19 nada yang berbeda. Pitch-pitch tersebut disajikan dalam notasi ilmiah musikal - surat itu mewakili not tersebut, dan angka tersebut menunjukkan oktaf mana.

 Hole   Breathing   Note  
 1      Exhale      C4    
 1      Inhale      D4    
 2      Exhale      E4    
 2      Inhale      G4    
 3      Exhale      G4
 3      Inhale      B4
 4      Exhale      C5    
 4      Inhale      D5    
 5      Exhale      E5    
 5      Inhale      F5    
 6      Exhale      G5    
 6      Inhale      A5    
 7      Exhale      C6    
 7      Inhale      B5    
 8      Exhale      E6    
 8      Inhale      D6    
 9      Exhale      G6    
 9      Inhale      F6    
 10     Exhale      C7    
 10     Inhale      A6    

Misalnya, jika saya menghembuskan napas di lubang 3, saya akan mendapat G4catatan. Jika saya menghirup pada lubang 2, saya juga akan mendapatkan G4catatan. Jika saya menghembuskan napas pada lubang 7, saya akan mendapatkan C6.

Ketika saya bernapas ke harmonika, selain menghembuskan napas atau menghirup, saya juga dapat memilih apakah akan bernapas tipis atau luas . Pernapasan tipis menyebabkan hanya satu lubang untuk berbunyi, sedangkan bernapas secara luas menyebabkan satu lubang dan kedua lubang di kedua sisi lubang itu berbunyi. Saya tidak memiliki keterampilan embouchure untuk meniup ke dua lubang - itu salah satu atau tiga.

Sebagai contoh, jika saya mengeluarkan sedikit ke lubang 4, hanya lubang 4 akan terdengar, jadi saya akan mendapatkan suara C5. Jika saya banyak dihembuskan ke lubang 4, lubang 3, 4, dan 5 akan terdengar, dan saya akan mendapatkan kunci G4, C5, E5. Jika saya secara luas menghirup ke lubang 4, lubang 3, 4, dan 5 akan terdengar tetapi mereka akan memainkan nada tarik napas sebagai gantinya, yang menghasilkan akord B4, D5, F5. Perhatikan bahwa untuk lubang di kedua ujungnya, jika saya menarik napas secara luas ke dalamnya, hanya dua lubang yang akan berbunyi (karena tidak ada lubang 0 atau lubang 11).

Namun, saya tidak bisa menghirup dan menghembuskan napas secara bersamaan. Misalnya, saya bisa menghembuskan napas ke dalam lubang 4, 5, dan 6 untuk menghasilkan nada C5, E5, dan G5 yang terdengar bersamaan, membentuk akor. Namun, saya tidak bisa menghirup dan menghembuskan napas pada saat yang sama, jadi tidak mungkin bagi saya untuk memainkan akor C5, F5, A5 karena saya harus entah bagaimana menghembuskan napas di lubang 4 dan menghirup di lubang 5 dan 6. Jika ini masih belum jelas, utas komentar ini mungkin berguna.

Masukan adalah catatan musik. Catatan tersebut dinotasikan dengan cara yang sama seperti yang disebutkan di atas dalam tabel, dan dipisahkan dengan koma. Catatan yang dibungkus dengan kurung keriting mewakili akor Contohnya:

C4,D4,G4,{D5,F5,A5},B5

Ini berarti, "C4, lalu D4, lalu G4, lalu D5, F5, dan A5 pada saat yang sama, lalu B5." Program Anda akan mengambil string dalam format ini sebagai input dan output Truejika mungkin bagi saya untuk memainkan musik pada harmonika saya, atau Falsesebaliknya. Untuk input dan output sampel, contoh di atas harus berupa output True. Input {C5,F5,A5}di sisi lain akan ditampilkan False.

Ini kode golf, jadi entri terpendek menang.

Berikut ini beberapa kasus uji:

Input (skala AC Mayor):

C4,D4,E4,F4,G4,A4,B4,C5

Keluaran:

False

(karena harmonika tidak dapat memainkan F4 atau A4)

Input (2 bilah pembuka dari Let It Go ):

E6,F6,A5,E6,F6,F6,E6,A5,F6,E6

Keluaran:

True

Memasukkan:

{E6,G6,F6}

Keluaran:

False

Memasukkan:

{G4,C5,E5},{F5,A5,B5}

Keluaran:

True

Anda dapat mengasumsikan bahwa akor akan datang dalam urutan nada yang lebih rendah ke yang lebih tinggi.

Absinth
sumber
2
Apakah Anda harus mengganti napas dan menghirup secara bergantian dari satu catatan ke catatan lainnya?
COTO
1
@COTO No. Asumsikan saya memiliki kapasitas napas yang tak terbatas.
absinthe
tautan utas komentar yang dirujuk tidak berfungsi untuk saya. ini bekerja untuk saya: meta.codegolf.stackexchange.com/a/2149/3348
ardnew
apakah Anda memiliki satu set kasus uji yang dapat kami gunakan?
ardnew
4
Saya BISA memainkan bluesharp (Richter tuned harmonica), tetapi saya hanya memainkan blues saja. Lubang 7 dengan C6 akan BAWAH ke B5 terlihat aneh tetapi sudah benar. Anda memiliki dua solusi: membeli harmonika yang lebih canggih dengan penyetelan yang berbeda, atau belajar menekuk not (jika Anda bisa menekuk, Anda MASIH tidak akan dapat memainkan semua not, tetapi Anda dapat memainkan blues melolong untuk mengekspresikan frustrasi Anda. .) Aturan tentang hanya bisa memainkan 1 atau 3 nada cukup akurat. Berikut ini representasi yang bagus dari penyetelan Richter: en.wikipedia.org/wiki/Richter-tuned_harmonica . Bagian pada kunci yang berbeda juga menarik secara musikal
Level River St

Jawaban:

2

Python - 218 209 189 karakter

Minimal:

def t(s):from re import sub as r;exec('l=bool([x for x in['+r('"{','("',r('}"','")',r(',','","','"'+s+'"')))+']if"".join(x)not in"C4E4G4C5E5G5C6E6G6C7|D4G4B4D5F5A5B5D6F6A6"])');return not l

Untuk kemudahan membaca:

def t(s):
    from re import sub as r
    exec('l=bool([x for x in'
         ' [' + r( '"{' , '("' ,
                  r( '}"' , '")' , 
                    r( ',' , '","' , '"' + s + '"' ))) +
         ']'
         ' if "".join(x) not in "C4E4G4C5E5G5C6E6G6C7|D4G4B4D5F5A5B5D6F6A6"])')
    return not l

Diberikan string yang diformat seperti dalam deskripsi masalah, tkembali Truejika urutan dimainkan pada harmonika yang dijelaskan, dan Falsejika tidak.

Tidak ada tanda cek untuk urutan not di akord. Kecuali dikatakan sebaliknya, saya percaya ini sudah cukup karena itu tidak ada dalam pernyataan masalah, dan itu lolos semua tes yang diberikan di:

assert not t("C4,D4,E4,F4,G4,A4,B4,C5")
assert t("E6,F6,A5,E6,F6,F6,E6,A5,F6,E6")
assert not t("{E6,G6,F6}")
assert t("{G4,C5,E5},{F5,A5,B5}")
Poik
sumber
Anda dapat menghapus banyak ruang: ] if "".join(x) not-> ]if"".join(x)notKata kunci dapat berdekatan dengan string sehingga "and"benar.
Bakuriu
Golf kode pertama di sini jadi saya pikir saya kehilangan sesuatu. Terima kasih!
Poik
1

Javascript - 245 243 karakter

Diperkecil:

function p(s){function f(s){s=s.replace(/\W/g,'');l=s.length;return((l-6)*(l-2)?l-4?'':'C4E4 G6C7 D4G4 F6A6':'C4E4G4C5E5G5C6E6G6C7 D4G4B4D5F5A5B5D6F6A6').indexOf(s)<0?0:''}return s.replace(/{.*?}/g,f).split(',').map(f).join('')?'False':'True'}

Dan diperluas:

function p(s) {
    function f(s) {
        s = s.replace( /\W/g, '' );
        l = s.length;
        return ( (l-6)*(l-2) ? ( (l-4) ? '' : 'C4E4 G6C7 D4G4 F6A6' ) : 'C4E4G4C5E5G5C6E6G6C7 D4G4B4D5F5A5B5D6F6A6' ).
            indexOf( s ) < 0 ? 0 : ''
    }
    return s.replace( /{.*?}/g, f ).split( ',' ).map( f ).join( '' ) ? 'False' : 'True'
}

Fungsi pmenerima string sebagai input dan kembali Truejika urutan not / chord dimainkan, Falsejika tidak. Ini mengembalikan hasil yang tidak ditentukan jika input tidak valid secara sintaksis.

Ini juga dengan berani mengasumsikan bahwa not akor dimasukkan dalam urutan lubang naik (seperti dalam contoh).

Hitungan karakter dapat dikurangi hingga 14 jika fungsi dibolehkan mengembalikan logika truedan falsebukannya string yang setara.

COTO
sumber
1

JavaScript (ES6), 230

Hanya versi jawaban @ COTO yang ditulis ulang:

f=s=>{s=s.replace(/\W/g,'');l=s.length;return((l-6)*(l-2)?(l-4?'':'C4E4 G6C7 D4G4 F6A6'):'C4E4G4C5E5G5C6E6G6C7 D4G4B4D5F5A5B5D6F6A6').indexOf(s)<0?0:''};p=s=>{return s.replace(/{.*?}/g,f).split(',').map(f).join('')?'False':'True'}

Akan menghargai setiap tips tentang bermain golf ini lebih jauh karena saya mulai belajar ES6! :-)

rink.attendant.6
sumber
1

Scala 178

print(readLine./:(""){(a,c)=>if("..C4E4G4C5E5G5C6E6G6C7...D4G4B4D5F5A5B5D6F6A6...."sliding(6)flatMap(y=>Seq("{"+y.diff("..")+"}",y take 2))contains a+c)""else a+c diff ","}=="")

Tidak Disatukan:

print(
  readLine.foldLeft(""){(a,c)=>                             # loop through the input
    if("..C4E4G4C5E5G5C6E6G6C7...D4G4B4D5F5A5B5D6F6A6...."  # from the harmonica
      .sliding(6)                                     # take 6 at a time
      .flatMap(y=>Seq("{"+y.diff("..")+"}",y take 2)) # chords + single notes     
      .contains(a+c)) ""                              # clear matches
    else a+c diff ","                                 # drop commas
  }==""                                               # did everything match?
)

Perhatikan bahwa input yang cacat ditangani dengan buruk - string apa pun diterima, dan banyak string yang salah mengembalikan benar, misalnya:

{C,7.D}.C

cetakan benar.

paradigma
sumber
1

Rebol - 188

t: func[s][trim/with s ","h: next split n:"C4E4G4C5E5G5C6E6G6C7..D4G4B4D5F5A5B5D6F6A6"2 forskip h 2[i

Tidak Disatukan:

t: func [s] [
    trim/with s ","
    h: next split n: "C4E4G4C5E5G5C6E6G6C7..D4G4B4D5F5A5B5D6F6A6" 2
    forskip h 2 [insert h '|]
    h: head h

    parse s [
        any [
            h | "{" x: copy c to "}" (unless find n c [c: n])
            :x c "}"
        ]
    ]
]

Contoh penggunaan (dalam konsol Rebol):

>> t "C4,D4,G4,{D5,F5,A5},B5"
== true

>> t "{C5,F5,A5}"
== false

>> t "C4,D4,E4,F4,G4,A4,B4,C5"
== false

>> t "E6,F6,A5,E6,F6,F6,E6,A5,F6,E6"
== true

>> t "{E6,G6,F6}"
== false

>> t "{G4,C5,E5},{F5,A5,B5}"
== true

Sementara kode ini akan menangkap omong kosong seperti ini:

>> t "{C,7.D}.C"
== false

Namun itu akan memungkinkan hal-hal seperti ini melalui:

>> t "C,4,D4"
== true

Karena itu parsing sebagai "C4, D4".

Ini versi kode yang lebih ketat:

t: func [s] [
    h: next split n: "C4E4G4C5E5G5C6E6G6C7..D4G4B4D5F5A5B5D6F6A6" 2
    forskip h 2 [insert h '|]
    h: head h
    d: ["," | end]

    parse s [
      any [
            [
                h | "{" x: copy c to "}" (
                    unless all [
                        parse c [any [h d]]
                        find n trim/with copy c ","
                    ] [c: n]
                )
                :x c "}"
            ]
            d
      ]
    ]
]

Golf ini turun hingga 228 karakter dan sekarang kembali falsepada ...

>> t "C,4,D4"
== false
draegtun
sumber
1

JavaScript ES6, 211 209 190 karakter

Saya tahu ini bisa golf lebih lanjut. Saya akan mencoba melakukannya dalam beberapa jam;

Jalankan kode ini di Web Console Firefox Terbaru, Anda akan mendapatkan metode bernama Cyang kemudian dapat Anda panggil C("{G4,C5,E5},{F5,A5,B5}")dan akan kembali Trueatau Falsesesuai.

C=n=>(s='D4G4D5F5A5B5D6F6A6,C4E4G4C5E5G5C6E6G6C7',n.split(/[,}{]/g).some(a=>a&&!~s.search(a))||(m=n.match(/{[^}]+/g))&&m.some(a=>a.length!=9|!~s.search(a.replace(/{|,/g,"")))?'False':'True')

Saya mengasumsikan input yang valid secara sintaksis.

EDIT : Sederhana regex dan cek panjang.

Pengoptimal
sumber