Texte animé sinusoïdal en art ASCII

11

Ces vieilles démos me manquent un peu, montrant les capacités des ordinateurs lorsqu'ils s'appelaient x86 au lieu de i3, i5 et i7. L'une des premières que j'ai regardées dans mon 386 était la démo Unreal de Future Crew qui fête maintenant son 25e anniversaire. À la minute 0:43, la première partie de la démo commence et nous voyons un texte défilant suivant un chemin sinusoïdal. Essayons d'imiter cet effet dans l'art ASCII!

Le défi

Compte tenu de ce chemin:

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

et un texte d'entrée, dessinez le texte suivant ce chemin, comme ceci:

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

Notez que les espaces comptent comme des caractères dans le chemin d'accès et que le chemin d'accès se répète si le texte est plus long que l'exemple.

La partie animation

Une fois que vous avez dessiné le texte, attendez 100 ms (pour créer une animation d'environ 10 ips) et dessinez à nouveau le texte mais en commençant à la position suivante du chemin. Donc, pour le cadre #n, calculez n modulo 40et commencez à dessiner à la position suivante du chemin avec le texte toujours aligné à gauche du canevas:

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

Donc, pour l'image 10, nous aurons:

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

Remarques

  • L'entrée sera un simple string(ou chartableau, peu importe) avec le texte à animer, et aura toujours au moins 1 caractère.
  • Les caractères valides à animer sont ceux du jeu ASCII imprimable .
  • Le chemin à suivre sera exactement comme indiqué.
  • Le texte sera toujours aligné à gauche du canevas, donc l'effet sera le texte ondulant comme un drapeau, sans déplacement de texte. Et par toile, je veux dire écran ou tout ce que vous utiliserez pour afficher le texte . ;-)
  • Les cadres doivent être exempts de tout caractère / pixel des images précédentes, sauf si le caractère / pixel est le même dans les deux images.
  • La vitesse de l'animation n'a pas d'importance tant qu'elle se déroule correctement ou aussi vite que votre appareil le peut (nous pouvons définir un minimum de 5 ips, mais ce n'est pas une exigence). Ajustez simplement la vitesse pour la rendre fluide et ne vous inquiétez pas si les temps d'attente ne sont pas exactement les mêmes.
  • L'animation va boucler sans fin.

C'est , donc le programme ou la fonction la plus courte capable d'animer le texte peut gagner!

Charlie
la source
Connexes . Sandbox .
Charlie
1
Je peux compter 38 colonnes au lieu de 40.
Arnauld
1
@Arnauld c'est parce que ce qui compte, ce sont les positions dans le chemin, pas les colonnes.
Charlie
Oh je vois. Logique.
Arnauld
Est- ce correct en sortie? Il affiche l'entrée sous la forme d'une onde sinusoïdale et boucle indéfiniment. Bien sûr, puisque la vidéo est au format Graphics Interchange, elle est plus rapide en réalité.
R. Kap

Réponses:

9

HTML + ES6, 241 244 237 octets

Panne:

  • HTML: 16 octets
  • Fonction JS: 221 octets

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>

Comment?

Construire le chemin

Le code suivant crée le chemin:

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

Cela donne un tableau de tableaux [j, y, z]j est la position modulo 20, y est la coordonnée y à cette position et z n'est pas utilisé plus tard (il se trouve qu'il est juste calculé ici pour économiser quelques octets).

Le chemin étant symétrique, il suffit de coder les 20 premières positions. Nous faisons cela en utilisant un nombre binaire où chaque 1bit signifie que y doit être mis à jour (+1 pour la première moitié, -1 pour la seconde moitié).

001
   001
      01
        1
         1
         1
          1
           01
             001
                000

La première position étant mappée sur le bit le moins significatif, cela donne:

00010010111110100100 as binary = 77732 as decimal

Parce que ce nombre binaire est lui aussi symétrique, on peut le lire dans le même ordre pour la 2ème moitié.

D'où la formule:

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

qui peut aussi s'écrire:

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

k est la position et j est la position modulo 20.

La mise à jour de x est beaucoup plus facile: nous n'avons qu'un seul cas particulier à détecter en comparant la position modulo 20 à 9.

Dessiner le texte

Dans le code suivant, le code de construction de chemin décrit ci-dessus a été remplacé par une pathvariable de lisibilité.

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
la source
C'est génial, et assez proche du chemin demandé, mais le chemin n'est pas exactement celui que j'ai tracé. Les deux colonnes qui en contiennent deux *verticales ne sont pas alignées (à la même hauteur), et un autre petit nitpick. Mais je dois dire que je ne sais toujours pas comment votre code crée l'effet d'onde (que fait- y+=155464il?). Toutes nos félicitations!
Charlie
@CarlosAlejo Je pense que le chemin devrait maintenant être corrigé. Pourriez-vous s'il vous plaît revérifier? J'ajouterai une explication de la méthode utilisée.
Arnauld
1
Chemin vérifié, et merci beaucoup pour l'explication!
Charlie