Teks animasi Sinusoidal ASCII

11

Saya agak ketinggalan demo-demo lama yang menunjukkan kemampuan komputer ketika mereka dipanggil x86 bukan i3, i5 dan i7. Salah satu yang pertama saya tonton di 386 saya adalah demo Unreal dari Future Crew yang sekarang merayakan ulang tahun ke 25. Pada menit 0:43 bagian pertama dari demo dimulai dan kami melihat teks bergulir mengikuti jalur sinusoidal. Mari kita coba meniru efek itu dalam seni ASCII!

Tantangan

Diberikan jalur ini:

***                                ***
   ***                          ***
      **                      **
        *                    *
         *                  *
         *                  *
          *                *
           **            **
             ***      ***
                ******

dan teks input, gambar teks mengikuti jalur itu, seperti ini:

Thi                                Golf! 
   s i                          de       Yay
      s                       Co            !
        P                     
         r                  d
         o                  n
          g                a
           ra            s 
             mmi      zle
                ng Puz

Perhatikan bahwa spasi dihitung sebagai karakter di jalur, dan bahwa jalur berulang dengan sendirinya jika teks lebih panjang dari sampel.

Bagian animasi

Setelah Anda menggambar teks, tunggu 100 ms (untuk membuat animasi sekitar 10 fps) dan gambar lagi tetapi mulai dari posisi jalan selanjutnya. Jadi, untuk bingkai #n, hitung n modulo 40dan mulailah menggambar di posisi jalur berikut dengan teks selalu sejajar di sebelah kiri kanvas:

***                                ***
|  ***                          ***  |
|     **                      **     |
|       *                    *       |
|        *                  *        |
|        *                  *        |
|         *                *         |
|          **            **          |
|            ***      ***            |
|               ******               |
Position 0                 Position 39

Jadi untuk frame 10 kita akan memiliki:

                           and Co
                        es       de 
                      zl            Go
                     z                l
                    u                  f
T                   P                  !
 h                                       
  is             ng                       Ya
     is       mmi                           y!
        Progra

Catatan

  • Input akan berupa satu string(atau charlarik, apa pun) dengan teks untuk menghidupkan, dan akan selalu memiliki setidaknya 1 karakter.
  • Karakter yang valid untuk menghidupkan adalah karakter dalam set ASCII yang dapat dicetak .
  • Jalan untuk mengikuti akan persis seperti yang diberikan.
  • Teks akan selalu disejajarkan ke kiri kanvas, sehingga efeknya akan berupa teks yang melambai seperti bendera, tanpa perpindahan teks. Dan dengan kanvas yang saya maksud adalah layar atau apa pun yang akan Anda gunakan untuk menampilkan teks . ;-)
  • Bingkai harus bersih dari karakter / piksel dari bingkai sebelumnya kecuali karakter / pikselnya sama di kedua bingkai.
  • Kecepatan animasi tidak masalah asalkan berjalan dengan lancar atau secepat perangkat Anda (kami dapat mengatur minimal 5 fps, tetapi ini bukan keharusan). Cukup sesuaikan kecepatan untuk membuatnya lancar dan jangan khawatir jika waktu tunggu tidak persis sama.
  • Animasi akan berulang tanpa henti.

Ini adalah , jadi semoga program atau fungsi terpendek yang mampu menggerakkan teks akan menang!

Charlie
sumber
Terkait . Kotak pasir .
Charlie
1
Saya bisa menghitung 38 kolom daripada 40.
Arnauld
1
@Arnauld itu karena yang penting adalah posisi di jalan, bukan kolom.
Charlie
Oh begitu. Masuk akal.
Arnauld
Apakah ini oke sebagai output? Ini menampilkan input dalam bentuk gelombang sinusoidal dan loop tanpa henti. Tentu saja, karena video dalam format Graphics Interchange, itu lebih cepat dalam kenyataannya.
R. Kap

Jawaban:

9

HTML + ES6, 241 244 237 byte

Kerusakan:

  • HTML: 16 byte
  • Fungsi JS: 221 byte

let f =

s=>setInterval(_=>o.innerHTML=[...s].map((c,i)=>([j,y]=[...Array(40)].map((_,k)=>[j=k%20,y,y+=77732>>j&1?k<20||-1:0],y=0)[(i+p)%40],a[y]=a[y]||[...s].fill` `)[x]=(x+=j!=9,c),x=0,a=[],p++)&&a.map(r=>r.join``).join`
`,p=30)

f("This is Programming Puzzles and Code Golf! Yay!")
<pre id=o></pre>

Bagaimana?

Membangun jalan

Kode berikut membangun jalur:

[...Array(40)].map((_, k) =>
  [
    j = k % 20,
    y,
    y += 77732 >> j & 1 ? k < 20 || -1 : 0
  ],
  y = 0
)

Ini memberikan array array di [j, y, z]mana j adalah modulo posisi 20, y adalah koordinat y pada posisi ini dan z tidak digunakan kemudian (kebetulan dihitung di sini untuk menghemat beberapa byte).

Karena jalurnya simetris, kita hanya perlu menyandikan 20 posisi pertama. Kami melakukannya dengan menggunakan angka biner di mana setiap 1bit berarti y harus diperbarui (+1 untuk paruh pertama, -1 untuk paruh kedua).

001
   001
      01
        1
         1
         1
          1
           01
             001
                000

Dengan posisi pertama dipetakan ke bagian paling tidak signifikan, ini memberikan:

00010010111110100100 as binary = 77732 as decimal

Karena bilangan biner ini sendiri juga simetris, kita dapat membacanya dengan urutan yang sama untuk paruh kedua.

Maka rumusnya:

y += (77732 >> j) & 1 ? (k < 20 ? 1 : -1) : 0

yang juga dapat ditulis sebagai:

y += (77732 >> j) & 1 ? k < 20 || -1 : 0

di mana k adalah posisi dan j adalah modulo posisi 20.

Memperbarui x jauh lebih mudah: kami hanya memiliki satu kasus khusus untuk dideteksi dengan membandingkan posisi modulo 20 dengan 9.

Menggambar teks

Dalam kode berikut, kode pembangunan jalur yang dijelaskan di atas telah digantikan oleh pathvariabel untuk keterbacaan.

s => setInterval(                       // set a periodic timer:
  _ =>                                  //   with an anonymous callback
    o.innerHTML =                       //   which updates the content of 'o'
      [...s].map((c, i) => (            //   for each character c of the string s
          [j, y] = path[(i + p) % 40],  //     retrieve j and y from the path
          a[y] = a[y] || [...s].fill` ` //     initialize a[y] if it's undefined
        )[x] = (x += j! = 9, c),        //     update a[y][x] / update x
        x = 0,                          //     initialize x
        a = [],                         //     initialize a[]
        p++                             //     increment the phase
      ) &&                              //   end of map()
      a.map(r => r.join``).join`\n`,    //   join everything together
  p = 30                                //   initial phase = interval period = 30
)                                       // end of timer definition
Arnauld
sumber
Ini brilian, dan cukup dekat dengan jalan yang diminta, tetapi jalan itu tidak persis yang saya gambar. Dua kolom yang berisi dua *secara vertikal tidak sejajar (pada ketinggian yang sama), dan nitpick kecil lainnya. Tetapi saya harus mengatakan saya masih tidak tahu bagaimana kode Anda menciptakan efek gelombang (apa fungsinya y+=155464?). Selamat!
Charlie
@CarlosAlejo Saya pikir jalannya sekarang harus diperbaiki. Bisakah Anda periksa ulang? Saya akan menambahkan penjelasan tentang metode yang digunakan.
Arnauld
1
Path memeriksa, dan terima kasih banyak atas penjelasannya!
Charlie