Animer l'échelle ASCII de Jacob

23

Vous avez peut-être vu l'échelle de Jacob dans les musées de sciences pour enfants. Si vous ne savez pas à quoi ils ressemblent, il existe plusieurs images et exemples de vidéos sur Wikimedia Commons . Le défi aujourd'hui est de créer une version ASCII animée du gadget électrique. En fin de compte, cela devrait ressembler à ceci:

LadderGIFExample


Construction d'échelle

Voici la forme de base d'une échelle d'une hauteur ( H ) de 6:

6   \            /
5    \          /
4     \        /
3      \      /
2       \    /
1        \  /
0         ¯¯

Les chiffres à gauche indiquent simplement le numéro de ligne pour cet exemple et ne doivent pas être inclus dans la sortie. Nous ferons référence à une ligne donnée par son numéro ( R ). La ligne 0 est le bas ¯¯. Chaque ligne 1 à H comprend quatre parties:

  • Un espace (U + 0020) répété ( H - R ) fois
  • Une barre oblique \inverse (U + 005C)
  • Un espace (U + 0020) répété (2 * R ) fois
  • Une barre oblique /(U + 002F)

La ligne 0 est identique, sauf que les deux barres obliques sont remplacées par un macron ¯(U + 00AF). L'espace de fuite à la fin de chaque ligne ou en dessous de l'échelle est OK. Les espaces blancs de premier plan ne le sont pas.


Construction d'arc

Une fois l'échelle construite, vous pouvez créer des arcs entre le côté gauche et le côté droit. Un arc est entièrement dans une rangée et remplace les espaces entre le début \et la fin /. Par conséquent, la ligne 2 aura 4 caractères dans son arc, la ligne 3 aura 6, et ainsi de suite. Chaque arc est composé en utilisant les règles suivantes:

  • Les seuls caractères autorisés sont _/¯\(U + 005F, U + 002F, U + 00AF, U + 005C)
  • Afin d'assurer un aspect lisse, tout ¯ou /doit être suivi d'un ¯ou\
  • Afin d'assurer un aspect lisse, tout _ou \doit être suivi d'un _ou/
  • Les deux règles ci-dessus s'appliquent également aux bords de l'échelle
  • Les trois règles ci-dessus signifient effectivement que le premier caractère de l'arc doit être _ou /et le dernier caractère doit être _ou \( \¯\_//n'est pas valide aux deux extrémités mais \_/¯\/est OK)
  • Il doit y avoir une chance non nulle que chaque caractère autorisé se produise à un point donné
  • Chaque arc est indépendant de tout autre arc

Animation

La durée de vie d'un seul arc est créée en le commençant à la ligne 1 et en le «déplaçant» d'une ligne à la fois jusqu'à ce qu'il atteigne le sommet. IE, générez d'abord un arc à la ligne 1, puis réglez-le sur des espaces et générez un arc à la ligne 2, et ainsi de suite. Étant donné le nombre d'arcs à afficher ( N ), affichez la durée de vie complète de ce nombre d'arcs un à la fois en utilisant les directives suivantes:

  • Un seul arc doit être "vivant" à la fois. L'arc suivant ne peut pas démarrer jusqu'à ce que l'arc actuel atteigne le sommet puis s'éteigne.
  • Chaque ligne de la durée de vie de l'arc doit être affichée pour exactement une image
  • Il doit y avoir une seule image de l'échelle de base (sans arcs) avant le début d'un nouvel arc (facultatif avant le premier arc)
  • L'animation doit montrer la durée de vie complète de N arcs. Si N = 0, il devrait animer des arcs aléatoires pour toujours jusqu'à l'arrêt.
  • Si N > 0, vous pouvez toujours boucler l'animation pour toujours mais ce doit être une boucle des mêmes arcs encore et encore. (L'exemple GIF en haut de ce post a H = 6 et N = 3 mais il boucle pour toujours.)
  • L'animation doit se produire sur place. Autrement dit, chaque image doit remplacer complètement l'image suivante et être au même emplacement.
  • La longueur de chaque image peut être celle que vous voulez, mais la rendre visible par un humain (IE, utilisez votre bon sens: 0,01 s / image et 30 s / image sont tous deux inacceptables.)

Entrée sortie

  • L'entrée et la sortie peuvent être dans n'importe quel format standard
  • Vous pouvez exporter un GIF, écrire du texte à l'écran, produire un seul fichier pour chaque image ou tout autre moyen raisonnable
  • Les failles standard sont interdites
  • La hauteur de l'échelle H sera un entier positif
  • Le nombre d'arcs pour afficher N sera un entier non négatif
  • Les deux H et N sont prises comme entrées dans l'ordre que vous choisissez (S'il vous plaît inclure l'ordre dans votre réponse)

Condition gagnante

C'est le donc le code le plus court l'emporte.

bac à sable

Ingénieur Toast
la source
1
L'arc peut-il être généré symétriquement par son centre? Je ne vois aucune restriction à cela dans les règles
Dead Possum
Puis-je imprimer chaque image l'une après l'autre sur la console?
TFeld
@DeadPossum Je pensais que vous aviez raison malgré le fait que cela n'aurait pas l'air très éclair, mais c'est en fait interdit par la combinaison de deux règles: the first character in the arc must be _ or / and the last character must be _ or \ et There must be a non-zero chance for each allowable character to occur at a given point. Pour être symétrique, le premier et le dernier caractère doivent être à _chaque fois, ce qui signifie qu'il n'y a aucune chance que l'un /ou l' autre se produise.
Engineer Toast
@TFeld Tant que chaque image apparaît au même endroit sur l'écran, oui. Cela signifie que vous devrez effacer la console (ou peut-être faire défiler vers le bas, si c'est possible) à chaque fois.
Engineer Toast
2
L'exigence macron signifie-t-elle que QBasic ne peut pas rivaliser? Il utilise CP437 , dans lequel se 0xAFtrouve le point de code ».
DLosc

Réponses:

5

Python 2 , 287 271 270 276 275 octets

import time,random
r,n=input()
c=n*-~r or-r
while c:
 c-=1;L=[list(' '*i+'\\'+'  '*(r-i)+'/')for i in range(r)];x=c%-~r;time.sleep(1);y=x+1;exec"L[x][y]=random.choice('\xaf/\_'[L[x][y-1]in'\_'::2][y==2*r-x:]);y+=1;"*2*(r-x)
 for l in['']*99+L+[' '*r+'\xaf'*2]:print''.join(l)

Essayez-le en ligne!

N'efface pas l'écran sur tio, mais fonctionne dans une console.

Gif de fonctionnement:

entrez la description de l'image ici

TFeld
la source
Un peu sournois mais vous pourriez utiliser à la print'\n'*99place de os.system('cls')et perdre l' osimportation. Ne fonctionne toujours pas sur TIO mais fonctionne sur les consoles Windows et Linux.
ElPedro
1
Il ne devrait [y avoir] qu'une seule image de l'échelle de base (sans arcs) avant le début d'un nouvel arc (facultatif avant le premier arc)
wastl
5
Je pense que vous utilisez des tirets (U + 002D) au lieu de macrons (U + 00AF). Je ne pense pas que cela augmentera votre nombre d'octets pour le réparer. De plus, comme l'a souligné @wastl, il n'y a pas de cadre d'échelle vide entre les arcs.
Engineer Toast
La rangée du bas utilise des macrons mais pas les arcs
Engineer Toast
1
@EngineerToast Fixé maintenant :)
TFeld
4

JavaScript (ES6), 245 octets

f=(o,h,n,i=0)=>(o.innerText=[...Array(h+1)].map((_,j)=>` `.repeat(j)+(j<h?`\\${[...Array(w--*2)].map((_,k)=>h+~j-i?` `:k>w*2|Math.random()<.5?s[s=t,1]:s[s=`¯\\`,0],s=t=`/_`).join``}/`:`¯¯`),w=h).join`
`,(++i<h||--n)&&setTimeout(f,250,o,h,n,i%h))
Height: <input type=number min=1 value=6 id=h><br>Arcs: <input type=number min=0 value=3 id=n><br><input type=button value=Go! onclick=f(o,+h.value,+n.value)><pre id=o></pre>

Le nombre d'octets suppose un codage ISO-8859-1.

Neil
la source
Il est possible de le réduire à 242 en le définissant A=x=>[...Array(x)].map;au début et en remplaçant les deux usages.
Bary12
@ Bary12 Vous ne pouvez pas revenir map, c'est juste une propriété Array.prototypeet aucune utilité en soi. J'ai essayé des versions de travail, mais elles sortaient toutes plus de 245 octets.
Neil
3

C (gcc) , 406 octets

#define p(X) printf(X),usleep(999)
#define x(X) do{s[X]=0;p(s);s[X]=' ';}while(0)
char c[2][2]={95,47,92,'¯'};R;i;j;k;a(){char s[2]={92,0};for(j=0;j<2*R-1;++j,p(s))*s=c[*s<50][rand()%2];*s=c[*s<50][0];p(s);}f(H,N){char s[99];for(i=0;i<99;++i)s[i]=' ';p("\e[s");for(i=0;;++i){i%=(N?N:i+1);srand(i^H^N);for(k=1;k<H;++k){for(R=H;--R;){x(H-R+1);p("\\");if(R==k)a();else x(2*R);p("/\n");}x(H);p(" ¯¯\n\e[u");}}}

Essayez-le en ligne!

La description:

#define p(X) printf(X),usleep(999)              // Define p to printf(p) + delay
#define x(X) do{s[X]=0;p(s);s[X]=' ';}while(0)  // Define x(X) to print X spaces
                                                // This uses a string s full of
                                                // spaces and adds the null
                                                // terminator where approrpiate
char c[2][2]={95,47,92,'¯'};                    // 2d array of 'next arc' options
R;i;j;k;                                        // Variables
a(){                                            // a() -> print arc for row R
    char s[2]={92,0};                           // s is a string of next char
                                                // initialize to backslash
    for(j=0;j<2*R-1;++j                         // loop over each character
            ,p(s))                              // printing s each time
        *s=c[*s<50][rand()%2];                  // set s to the next arc char
    *s=c[*s<50][0];                             // set s to the 'first' arc char
                                                // note that in definition of c
                                                // first means appropriate as
                                                // final character before /
    p(s);}                                      // print the last character
f(H,N){                                         // f(H,N) -> print jacob ladder
    char s[99];for(i=0;i<99;++i)s[i]=' ';       // this is the space string for x
    p("\e[s");                                  // ANSI terminal save position
    for(i=0;;++i){i%=(N?N:i+1);                 // loop i->N (or i->INT_MAX if N=0)
        srand(i^H^N);                           // seed random with i XOR H XOR N
        for(k=1;k<H;++k){                       // for each row (bottom to top)
            for(R=H;--R;){                      // for each row (top to bottom)
                x(H-R+1);p("\\");               // print left "    \"
                if(R==k)                        // if on the arc row
                    a();                        // print the arc
                else x(2*R);                    // otherwise print spaces
                p("/\n");}                      // finish off the row
            x(H);p(" ¯¯\n\e[u");}}}             // print bottom line and move back
LambdaBeta
la source
Remarque: ne fonctionne vraiment que dans Xterm ... de nombreux émulateurs de terminaux ne prennent tout simplement pas en charge la position de sauvegarde / restauration.
LambdaBeta
La rangée du bas est la rangée 0 et n'a que deux macrons. Ce n'est pas le cas \--/. C'est probablement une solution facile. Pouvez-vous capturer et publier un GIF de celui-ci en travaillant dans Xterm?
Engineer Toast
Malheureusement, je n'ai pas les outils pour le faire (juste jouer pendant les temps de construction au travail). Je mettrai à jour avec la ligne 0 correcte cependant, c'est une solution facile.
LambdaBeta
Invalide: Il ne devrait [y avoir] qu'une seule image de l'échelle de base (sans arcs) avant le début d'un nouvel arc (facultatif avant le premier arc)
wastl
changer k = 1 en k = 0 corrige le coût de ... 0 octet. Mettra à jour bientôt.
LambdaBeta
2

PowerShell , 347 319 octets

filter c{Param($h,$n)if($n-eq0){$n=-1}for($x=0;$x++-ne$n;){($h..1)|%{$l=(($h..1)|%{"$(" "*($h-$_))\$(" "*$_*2)/"})+"$(" "*$h)¯¯"
$r="Get-Random"
$i=0
$z=-join((0..(($h-$_)*2))|%{$i=switch($i%3){0{&$r 0,1}default{&$r 2,3}}"_/¯\"[$i]})+"_\\_"[$i]
$l[$_-1]=($l[$_-1]).Substring(0,$_)+"$z/"
cls
$l
Sleep -m 250}}}

Essayez-le en ligne! Impossible $argsde jouer correctement, donc le lien appelle la fonction sans effacer la console.

Non golfé

filter c{
    Param($h,$n)
    if($n -eq 0){$n=-1} # inelegant swap to allow for an infinite loop. 
                        # Curse you zero-indexing!
    for($x=0;$x++-ne$n;)
    {
        ($h..1) | % {         
            $l=(($h..1)|%{ # (( double paren is needed to induce each line 
                           # as a new array element
                "$(" "*($h-$_))\$(" "*$_*2)/" # offset by total height. 
                                              # N spaces + rung + N*2 spaces + rung
            })+"$(" "*$h)¯¯" # last line is the floor of the ladder

            $r="Get-Random" # shorter to declare once and execute with & operator

            $i=0 # initialize $i so we choose only _ or / for the first char

            $z=-join( # build an electric ZAP!
                (0..(($h-$_)*2))|%{                    
                    $i = switch($i%3) { # choose next char based on previous selection
                        0{&$r 0,1}
                        default{&$r 2,3}
                    }    
                    "_/¯\"[$i]
                }
            )+"_\\_"[$i] # final char is \ or _ to rejoin the ladder        
            $l[$_-1]=($l[$_-1]).Substring(0,$_)+"$z/" # select one rung of the ladder 
                                                      # append an electric ZAP!                
            cls # clear the console
            $l  # display the ladder
            Sleep -m 250
        }
    }
}
Peter Vandivier
la source
C'est une petite chose, mais la rangée du bas est des tirets au lieu de macrons. C'est un changement de zéro octet$l=(($h..1)|%{"$(" "*($h-$_))\$(" "*$_*2)/"})+"$(" "*$h)¯¯"
Engineer Toast
1
¯ \ (° _o) / ¯ oups! échangé en macrons: p
Peter Vandivier
1
Je ne connais pas trop bien PowerShell, mais vous pouvez supprimer la plupart des nouvelles lignes. En plus for($x=0;$x-ne$n;$x++)peut être for($x=0;$x++-ne$n;). Je l'ai réduit à 324 octets (321 caractères) . Les conseils pour jouer au golf dans <toutes les langues> et les conseils pour jouer au golf dans PowerShell peuvent également être intéressants à lire.
Kevin Cruijssen
1
sleep 1enregistre un peu (il prend par défaut -secondes) mais est assez lent mais reste raisonnable-ish, sleep -m 99est assez rapide mais aussi raisonnable. Enregistre 5/1 octets selon ce que vous aimez. N'a pas vérifié la tentative de Kevin , mais functionà filterest un octet libre aussi bien.
Veskah
1

Rubis , 293 octets

m={}
"   __/\\_/¯¯\\/¯\\".chars.each_slice(3){|e|u,*v=e;m[u]=v}
a=->l,c{l<1?"/":(d=m[c].sample;c+a[l-1,d])}
n=gets.to_i
h=gets.to_i
o=0
while o<n||n<1
h.times{|i|puts (0...h).map{|j|" "*j+"\\"+a[2*(h-j),i==h-j-1?["_","/"].sample: " "]}*"\n";puts" "*h+"¯¯";sleep(0.3);puts"\n"*99}
o+=1
end

Essayez-le en ligne!

Je suis sur Windows donc il imprime juste beaucoup de "\ n" pour effacer la console. Prend 2 arguments net hdeux lignes sur stdin.

crashoz
la source