Menghasilkan ritme Euclidean

8

Tahukah Anda bahwa algoritma Euclidean mampu menghasilkan irama musik tradisional ? Kita akan melihat bagaimana ini bekerja dengan menggambarkan algoritma yang serupa, tetapi sedikit berbeda dengan yang ada di koran.

Pilih bilangan bulat positif n, jumlah ketukan, dan bilangan bulat positif k, jumlah ketukan yang dibunyikan (catatan). Kita dapat menganggap ritme sebagai urutan nbit, kdi antaranya adalah 1s. Ide dari algoritma ini adalah untuk mendistribusikan 1s secara merata di antara 0s.

Misalnya, dengan n = 8dan k = 5, kita mulai dengan 5 yang dan 3 nol, masing-masing dalam urutannya sendiri:

[1] [1] [1] [1] [1] [0] [0] [0]

Pada titik mana pun kita akan memiliki dua jenis urutan - yang pada awalnya adalah urutan "inti" dan yang pada akhirnya adalah urutan "sisa". Di sini inti adalah [1]s dan sisanya adalah [0]s. Selama kami memiliki lebih dari satu urutan sisanya, kami mendistribusikannya di antara inti:

[1 0] [1 0] [1 0] [1] [1]

Sekarang intinya [1 0]dan sisanya [1], dan kami distribusikan lagi:

[1 0 1] [1 0 1] [1 0]

Sekarang intinya adalah [1 0 1]dan sisanya adalah [1 0]. Karena kami hanya memiliki satu urutan sisa, kami berhenti dan mendapatkan string

10110110

Ini adalah apa yang terdengar seperti, diulang 4 kali:

Berikut contoh lain, dengan n = 16dan k = 6:

[1] [1] [1] [1] [1] [1] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0]
[1 0] [1 0] [1 0] [1 0] [1 0] [1 0] [0] [0] [0] [0]
[1 0 0] [1 0 0] [1 0 0] [1 0 0] [1 0] [1 0]
[1 0 0 1 0] [1 0 0 1 0] [1 0 0] [1 0 0]
[1 0 0 1 0 1 0 0] [1 0 0 1 0 1 0 0]
1001010010010100

Perhatikan bagaimana kami mengakhiri pada langkah terakhir dengan dua urutan inti dan tidak ada urutan yang tersisa. Ini dia, diulang dua kali:

Memasukkan

Anda dapat menulis fungsi atau pembacaan program lengkap dari STDIN, baris perintah atau yang serupa. Input akan berupa dua bilangan bulat positif ndan k <= n, yang dapat Anda asumsikan dalam urutan mana pun.

Keluaran

Tugas Anda adalah menampilkan ritme yang dihasilkan sebagai nstring panjang karakter. Anda dapat memilih dua karakter ASCII yang dapat dicetak yang berbeda (0x20 hingga 0x7E) untuk mewakili catatan dan sisanya.

Uji kasus

Kasus uji berikut digunakan xuntuk mewakili catatan dan huruf .s untuk mewakili huruf istirahat. Masukan diberikan dalam urutan n, lalu k.

1 1    ->  x
3 2    ->  xx.
5 5    ->  xxxxx
8 2    ->  x...x...
8 5    ->  x.xx.xx.
8 7    ->  xxxxxxx.
10 1   ->  x.........
11 5   ->  x.x.x.x.x..
12 7   ->  x.xx.x.xx.x.
16 6   ->  x..x.x..x..x.x..
34 21  ->  x.xx.x.xx.xx.x.xx.x.xx.xx.x.xx.x.x
42 13  ->  x...x..x..x..x...x..x..x..x...x..x..x..x..
42 18  ->  x..x.x.x..x.x.x..x.x.x..x.x.x..x.x.x..x.x.

Mencetak gol

Ini adalah kode-golf, sehingga kode dalam byte paling sedikit menang.

Sp3000
sumber

Jawaban:

5

CJam, 37 34 30 27 24 byte

3 byte disimpan oleh user23013.

q~,f>{_(a-W<}{e`:a:e~z}w

Ini mengambil input sebagai yang kpertama, nkedua. Itu menggunakan 1dan 0untuk menunjukkan catatan dan sisanya, masing-masing.

Coba di sini. Atau, di sini adalah test harness yang menjalankan semua test case yang diberikan (menukar urutan input) dan juga memformat ulang output untuk digunakan xdan .untuk perbandingan yang lebih mudah dengan solusi referensi. (Hasil yang muncul dalam input harness uji dibuang sebelum menjalankan kode. Mereka dapat dengan aman dihapus tanpa mempengaruhi program.)

Penjelasan

q~                       e# Read and eval the input, dumping k and n on the stack.
  ,                      e# Create a range [0 .. n-1]
   f>                    e# For each of them, check if it's less than k.
                         e# This gives k 1s and n-k 0s.
     {      }{        }w e# While the first block yields a truthy result, execute
                         e# the second block.
      _                  e# Duplicate the array.
       (a-               e# Remove all instances of core sequences.
          W<             e# Remove one remainder sequence if there is one. This
                         e# gives an empty array (falsy) whenever there are less
                         e# than two remainder sequences.
              e`         e# Run-length encode. I.e. this turns an array into a list
                         e# of pairs of run-length and element.
                :a:e~    e# Wrap each RLE pair in an array and RLD it. This
                         e# partitions the array into cores and remainders.
                     z   e# Zip the two parts, interleaving cores and remainders.

Proses ini array yang sangat mendalam bersarang, tetapi bagian yang penting adalah bahwa semua core (dan semua sisa) selalu memiliki struktur bersarang yang sama, sehingga mereka masih sama satu sama lain. CJam secara otomatis mencetak isi tumpukan di akhir program dan menghilangkan pembatas array sepenuhnya, karenanya struktur ini tidak mempengaruhi output juga.

Martin Ender
sumber
2 atau 3 byte lebih pendek: q~\,f>.
jimmy23013
@ user23013 Oh, itu rapi! Terima kasih. :)
Martin Ender
Untuk 3 byte, maksud saya input bisa dalam urutan apa pun.
jimmy23013
@ user23013 Oh benar, saya lupa tentang itu.
Martin Ender
1

Haskell, 125 byte

r=replicate
g z(a:b)(c:d)=g((a++c):z)b d
g z x y=(z,x++y)
f(x,y)|length y>1=f$g[]x y|1<2=concat$x++y
n#k=f(r k "x",r(n-k)".")

Contoh penggunaan: 42 # 13 -> x...x..x..x..x...x..x..x..x...x..x..x..x...

fmengambil dua parameter: inti dan daftar sisa. Entah ritsleting kedua daftar (via g) dan menyebut dirinya lagi atau berhenti jika sisanya terlalu pendek. Fungsi utama #membuat daftar awal dan panggilan f.

nimi
sumber
1

Python, 85

f=lambda n,k,a='1',b='0':n-k<2and a*k+b*(n-k)or[f(n-k,k,a+b,b),f(k,n-k,a+b,a)][2*k>n]

Solusi rekursif alami. Parameter (n,k,a,b)mewakili inti dari yang k adiikuti oleh sisa dari n-k b'.

Solusi ini tidak efisien karena kedua panggilan rekursif fdievaluasi, menyebabkan jumlah panggilan yang eksponensial.

Saya mencoba untuk mengompresi permintaan bersyarat flike

f(max(n-k,k),min(n-k,k),a+b,[a,b][2*k<n])
f(*[n-k,k,k,n-k,b,a][2*k>n::2]+[a+b])

tapi ternyata tidak ada yang lebih pendek.

Tidak
sumber