Testo animato di arte ASCII sinusoidale


11

Mi manca un po 'quelle vecchie demo che mostrano le capacità dei computer quando venivano chiamate x86 invece di i3, i5 e i7. Uno dei primi che ho visto nel mio 386 è stata la demo di Unreal di Future Crew che ora celebra il suo 25 ° anniversario. Al minuto 0:43 inizia la prima parte della demo e vediamo un testo scorrevole che segue un percorso sinusoidale. Proviamo a imitare quell'effetto nell'arte ASCII!

La sfida

Dato questo percorso:

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

e un testo di input, disegna il testo seguendo quel percorso, in questo modo:

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

Si noti che gli spazi contano come caratteri nel percorso e che il percorso si ripete se il testo è più lungo del campione.

La parte animata

Dopo aver disegnato il testo, attendere 100 ms (per creare un'animazione di circa 10 fps) e disegnare di nuovo il testo, ma a partire dalla posizione successiva del percorso. Quindi, per la cornice #n, calcola n modulo 40e inizia a disegnare nella seguente posizione del tracciato con il testo sempre allineato a sinistra della tela:

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

Quindi per il frame 10 avremo:

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

Appunti

  • L'input sarà un singolo string(o chararray, qualunque sia) con il testo da animare e avrà sempre almeno 1 carattere.
  • I caratteri validi da animare sono quelli nel set ASCII stampabile .
  • Il percorso da seguire sarà esattamente come indicato.
  • Il testo sarà sempre allineato a sinistra della tela, quindi l'effetto sarà il testo che ondeggia come una bandiera, senza spostamento del testo. E per tela intendo schermo o qualunque cosa tu usi per mostrare il testo . ;-)
  • I frame devono essere liberi da qualsiasi carattere / pixel dei frame precedenti a meno che il carattere / pixel sia lo stesso in entrambi i frame.
  • La velocità dell'animazione non ha importanza fino a quando scorre senza intoppi o con la massima velocità del tuo dispositivo (possiamo impostare un minimo di 5 fps, ma questo non è un requisito). Basta regolare la velocità per renderla fluida e non preoccuparti se i tempi di attesa non sono esattamente gli stessi.
  • L'animazione si ripeterà all'infinito.

Questo è , quindi può vincere il programma o la funzione più breve in grado di animare il testo!



1
Posso contare 38 colonne anziché 40.
Arnauld,

1
@Arnauld è perché ciò che conta sono le posizioni nel percorso, non le colonne.
Charlie

Oh, capisco. Ha senso.
Arnauld,

È questo va bene come uscita? Visualizza l'input sotto forma di un'onda sinusoidale e scorre all'infinito. Naturalmente, poiché il video è in formato di interscambio di grafica, è più veloce in realtà.
R. Kap

Risposte:


9

HTML + ES6, 241 244 237 byte

Abbattersi:

  • HTML: 16 byte
  • Funzione 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>

Come?

Costruire il percorso

Il codice seguente crea il percorso:

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

Ciò fornisce una matrice di matrici in [j, y, z]cui j è la posizione modulo 20, y è la coordinata y in questa posizione e z non viene utilizzata in seguito (viene semplicemente calcolata qui per salvare alcuni byte).

Poiché il percorso è simmetrico, dobbiamo solo codificare le prime 20 posizioni. Lo facciamo usando un numero binario in cui ogni 1bit significa che y deve essere aggiornato (+1 per la prima metà, -1 per la seconda metà).

001
   001
      01
        1
         1
         1
          1
           01
             001
                000

Con la prima posizione mappata al bit meno significativo, questo dà:

00010010111110100100 as binary = 77732 as decimal

Poiché questo numero binario è anch'esso simmetrico, possiamo leggerlo nello stesso ordine per la seconda metà.

Da qui la formula:

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

che può anche essere scritto come:

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

dove k è la posizione e j è la posizione modulo 20.

Aggiornare x è molto più semplice: abbiamo solo un caso speciale da rilevare confrontando la posizione modulo 20 con 9.

Disegnare il testo

Nel codice seguente, il codice di creazione del percorso sopra descritto è stato sostituito da una pathvariabile per la leggibilità.

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

Questo è geniale, e abbastanza vicino al percorso richiesto, ma il percorso non è esattamente quello che ho disegnato. Le due colonne che ne contengono due *in verticale non sono allineate (alla stessa altezza) e un altro piccolo nitpick. Ma devo dire che ancora non so come il tuo codice crei l'effetto wave (cosa fa y+=155464?). Congratulazioni!
Charlie

@CarlosAlejo Penso che il percorso dovrebbe ora essere risolto. Potresti per favore ricontrollare? Aggiungerò una spiegazione del metodo utilizzato.
Arnauld,

1
Path controllato, e grazie mille per la spiegazione!
Charlie
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.