Sinüsoidal ASCII-art animasyonlu metin


11

İ3, i5 ve i7 yerine x86 çağrıldığında bilgisayarların yeteneklerini gösteren eski demoları bir şekilde özlüyorum. 386'mda ilk izlediğim şeylerden biri, gelecek yılını kutlayan Future Crew'un Unreal demosuydu . At dakikada 00:43 demo ilk bölümü başlar ve bir sinüs yolunu takip eden bir kaydırma metni görüyoruz. ASCII sanatında bu etkiyi taklit etmeye çalışalım!

Meydan okuma

Bu yol göz önüne alındığında:

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

ve bir giriş metni, bu yolu izleyen metni aşağıdaki gibi çizin:

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

Boşlukların yoldaki karakterler olarak sayıldığını ve metin örnekten daha uzunsa yolun kendini tekrarladığını unutmayın.

Animasyon bölümü

Metni çizdikten sonra, 100 ms bekleyin (yaklaşık 10 fps'lik bir animasyon oluşturmak için) ve metni yeniden çizin, ancak yolun bir sonraki konumundan başlayarak. Bu nedenle, çerçeve için #n, n modulo 40metin her zaman tuvalin soluna hizalanmış olarak yolun aşağıdaki konumunda hesaplayın ve çizmeye başlayın:

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

Yani çerçeve 10 için sahip olacağız:

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

notlar

  • Giriş, canlandırılacak metne sahip tek bir string(veya chardizi) olacaktır ve her zaman en az 1 karakter içerecektir.
  • Canlandırılacak geçerli karakterler, yazdırılabilir ASCII kümesindeki karakterlerdir .
  • İzlenecek yol tam olarak verildiği gibi olacaktır.
  • Metin her zaman tuvalin soluna hizalanacaktır, bu nedenle efekt, metin yer değiştirmesi olmadan bayrak gibi sallanan metin olacaktır. Ve tuval ile ekran ya da metni göstermek için ne kullanacağınızı kastediyorum . ;-)
  • Karakter / piksel her iki karede de aynı değilse, kareler önceki karelerdeki karakterlerden / piksellerden temizlenmelidir.
  • Animasyonun hızı, cihazınızın sorunsuz veya hızlı çalıştığı sürece önemli değildir (minimum 5 fps ayarlayabiliriz, ancak bu bir gereklilik değildir). Sadece akıcı hale getirmek için hızı ayarlayın ve bekleme süreleri tamamen aynı değilse endişelenmeyin.
  • Animasyon durmadan dönecek.

Bu , bu yüzden metin kazanmak animasyon yeteneğine sahip en kısa program veya işlev olabilir!



1
40 yerine 38 sütun sayabilirim.
Arnauld

1
@Onayna göre sütunlar değil, yoldaki konumlar önemlidir.
Charlie

Ah anlıyorum. Mantıklı.
Arnauld

bu çıktı olarak tamam mı? Girişi sinüzoidal bir dalga şeklinde görüntüler ve durmadan döngüler. Elbette, video Grafik Değişim biçiminde olduğundan, gerçekte daha hızlıdır.
R. Kap

Yanıtlar:


9

HTML + ES6, 241 244 237 bayt

Yıkmak:

  • HTML: 16 bayt
  • JS işlevi: 221 bayt

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>

Nasıl?

Yolu oluşturma

Aşağıdaki kod yolu oluşturur:

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

Bu diziler içeren bir dizi verir j konumu modülo 20, y bu konumda y-koordinatı ve z (sadece bazı bayt kurtarmak için hesaplanabilir olur), daha sonra kullanılmaz.[j, y, z]

Yol simetrik olduğundan, sadece 20 ilk konumu kodlamamız gerekir. Bunu, her 1bitin y'nin güncellenmesi gerektiği anlamına gelen bir ikili sayı kullanarak yaparız (ilk yarı için +1, ikinci yarı için -1).

001
   001
      01
        1
         1
         1
          1
           01
             001
                000

İlk konum en az anlamlı bit ile eşlendiğinde, bu aşağıdakileri sağlar:

00010010111110100100 as binary = 77732 as decimal

Bu ikili sayının kendisi de simetrik olduğundan, ikinci yarı için aynı sırayla okuyabiliriz.

Dolayısıyla formül:

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

ayrıca şu şekilde de yazılabilir:

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

ki burada k pozisyonu ve j pozisyon modülo 20'dir.

Güncellenmesi x çok daha kolaydır: sadece 9 ile pozisyon modulo 20 karşılaştırarak tespit etmek için özel bir durum var.

Metin çizme

Aşağıdaki kodda, yukarıda açıklanan yol oluşturma kodu, pathokunabilirlik için bir değişkenle değiştirilmiştir .

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

Bu harika ve istenen yola oldukça yakın, ama yol tam olarak çizdiğim yol değil. Dikeyde iki içeren iki sütun *hizalanmamış (aynı yükseklikte) ve başka bir küçük nitpick. Ama yine de kodunuzun dalga efekti nasıl yarattığını bilmiyorum söylemeliyim (ne yapar y+=155464?). Tebrikler!
Charlie

@CarlosAlejo Sanırım yol şimdi düzeltilmelidir. Lütfen tekrar kontrol eder misiniz? Kullanılan yöntemin bir açıklamasını ekleyeceğim.
Arnauld

1
Yol kontrol edildi ve açıklama için çok teşekkür ederim!
Charlie
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.