Faites un BackFlip pour ais523!

16

Ce défi est un prix pour ais523 pour avoir remporté la catégorie " Recrue de l'année " dans " Best of PPCG 2016 ". Toutes nos félicitations!


BackFlip est un langage de programmation ésotérique créé par l'utilisateur ais523 , qui a créé bien plus de 30 autres esolangs intéressants .

BackFlip est un langage 2D comme Befunge ou > <> où le pointeur d'instruction traverse une grille de texte (le programme), se déplaçant vers le haut, le bas, la gauche et la droite, changeant de direction en fonction du caractère sur lequel il se trouve. De manière critique, la grille d'un programme BackFlip change au fur et à mesure de sa traversée, un peu comme la fourmi de Langton .

Pour ce défi, vous pouvez supposer qu'un programme BackFlip est toujours une grille rectangulaire de texte (toutes les lignes de la même longueur), de taille 1 × 1 au minimum, contenant uniquement les caractères ./\<>^V. ( .est utilisé pour la visibilité plutôt que pour l'espace.) Sémantiquement, le BackFlip que nous utiliserons ici est identique à la spécification d'origine .

Le pointeur d'instruction (IP) dans BackFlip commence toujours juste à gauche du coin supérieur gauche du programme, se dirigeant vers la droite. Il existe trois types de commandes qu'il peut rencontrer:

  1. .est un no-op. L'IP continue dans la direction où il allait. Le no-op reste un no-op.

  2. /et \sont des miroirs. Ils reflètent l'IP dans la direction indiquée par leur angle, puis ils se transforment en l'autre type de miroir .

    • Par exemple, si les têtes IP sont laissées dans un \, il commence à se déplacer vers le haut au lieu de gauche et le \devient a /.
  3. <, >, ^Et Vsont des flèches. Ils redirigent l'IP vers la direction dans laquelle ils pointent, puis ils se transforment en une flèche qui pointe dans la direction d'où provient l'IP (opposée à la direction dans laquelle l'IP se déplaçait) .

    • Par exemple, si l'IP se dirige vers le bas >, il commence à se déplacer vers la droite plutôt que vers le bas et >devient un ^car c'est la direction d'où provient l'IP.

Un programme BackFlip se termine lorsque l'IP sort des limites, c'est-à-dire sort du réseau. Il s'avère que tous les programmes BackFlip finissent par se terminer car les boucles infinies sont impossibles. (Vous pouvez supposer que c'est vrai.)

Votre objectif dans ce défi est d'écrire un programme ou une fonction qui prend un programme BackFlip et génère le nombre de mouvements que le pointeur d'instruction prend avant la fin du programme. Autrement dit, combien d'étapes l'IP prend-il au cours de l'exécution d'un programme? Cela comprend l'étape initiale sur la grille et l'étape finale hors de celle-ci.

Par exemple, le pointeur d'instruction prend 5 étapes dans la grille triviale ....:

 ....  <- empty 4×1 grid
012345 <- step number of the IP

Donc, la sortie ....est 5.

Dans la grille 4 × 2 plus complexe

\...
\.><

l'IP quitte la grille à sa 9e étape, donc la sortie est 9:

step  grid  IP position (@)
0     \...  @....
      \.><   ....

1     \...   @...
      \.><   ....

2     /...   ....
      \.><   @...

3     /...   ....
      /.><   .@..

4     /...   ....
      /.><   ..@.

5     /...   ....
      /.<<   ...@

6     /...   ....
      /.<<   ..@.

7     /...   ....
      /.><   .@..

8     /...   ....
      /.><   @...

9     /...   ....
      \.><   ....
             @

Le code le plus court en octets gagne.

Vous pouvez prendre l'entrée comme un tableau de lignes ou une matrice de caractères au lieu d'une chaîne multiligne si vous le souhaitez, mais vous devez utiliser les caractères ./\<>^V(pas les opcodes entiers). Vous pouvez utiliser l'espace au lieu de .si vous préférez. C'est bien si des caractères comme \doivent être échappés en entrée. La sortie est toujours un entier plus d'un.

Cas de test

....
5

\...
\.><
9

.
2

..
3

.
.
2

\
2

^
2

.^.
3

<.
2

\\
\/
7

>V
^<
6

>\
>/
6

\><
2

\><
\><
7

\><
\><
\><
12

\.V.
\.\<
5

\.V.
\./<
9

V./\
V./\
>./<
..\/
14

\V..
.^..
\/><
.V..
.^..
20

\.V.V.
\./.\<
.>\<..
..^.^.
31

\.V.V.V.
\./>/.\<
.>\>\<..
..^.^.^.
69

\.V.V.V.V.
\./>/>/.\<
.>\>\>\<..
..^.^.^.^.
145

\.V.V.V.V.V.V.V.V.V.V.
\./>/>/>/>/>/>/>/>/.\<
.>\>\>\>\>\>\>\>\>\<..
..^.^.^.^.^.^.^.^.^.^.
9721
Loisirs de Calvin
la source
1
C'est vraiment dommage que vous ne puissiez pas faire une solution BackFlip à cela ...
HyperNeutrino
Confus au sujet des miroirs ... fait / retourne les directions comme gauche => haut et haut => gauche ,?
officialaimm
1
@officialaimm Si vous vous dirigez de gauche à droite /, l'IP montera et que vous vous dirigerez vers l'intérieur, /l'IP ira à droite, comme s'il s'agissait d'une balle rebondissant sur un mur. (Mais souvenez-vous des /changements apportés à la barre oblique inversée après que l'IP le touche.)
Hobbies de Calvin le
pourquoi '\\' <LF> '\ /' vaut 7 au lieu de 6?
tsh

Réponses:

3

JavaScript (ES6), 158 octets

f=(a,x=0,y=0,d=3)=>a[x]&&(c=a[x][y])?(a[x][y]=c=='.'?c:c=='/'?(d^=3,'\\'):c=='\\'?(d^=1,'/'):'v>^<'[d][d='^<v>'.search(c),0],f(a,d<3?x+d-1:x,d?y+d-2:y,d)+1):1

Développé indépendamment de la réponse de @ tsh bien que remarquablement similaire.

Le mappage des directions ^<v>aux entiers 0-3 est régi par le fait que .search('^')renvoie 0 car il ^s'agit d'un métacaractère d'expression régulière.

Neil
la source
Je me sens tellement battu. J'étais assez confus à la fin là-bas jusqu'à ce que je réalise que x et y étaient inversés par rapport à ce que j'attendais.
Ørjan Johansen
@ ØrjanJohansen C'est un bon point; peut-être que je devrais échanger x avec y partout pour le rendre plus facile à comprendre.
Neil
2

Haskell , 333 325 octets

ÉDITER:

  • -8 octets: rendu sans fpoint et fusionné b.

bprend une liste de Strings et retourne un Integer.

data C a=C{c::a->(a,C a)}
b g=[0,0]#([0,1],map(maybe(C$m 1)C.(`lookup`zip"./^>V<"[n,m(-1),a[-1,0],a[0,1],a[1,0],a[0,-1]]))<$>g)
[y,x]#(d,g)|g&y||g!!0&x=1|n@([f,e],_)<-(($d).c)?x?y$g=1+[y+f,x+e]#n
l&i=i<0||i>=length l
(f?i)l|(p,a:r)<-splitAt i l=(p++).(:r)<$>f a
n d=(d,C n)
a v d=(v,C$a$(0-)<$>d)
m s[d,e]=([s*e,s*d],C$m(-s))

Essayez-le en ligne!

Comment ça fonctionne

  • C aest un type de données utilisé car Haskell ne permet pas qu'un type soit récursif sans le déclarer explicitement. Cest également un constructeur d'encapsulation et csa fonction de dépliage correspondante. Il n'est utilisé qu'avec a=[Int].
    • Le type C [Int]représente une commande de cellule, en tant que fonction qui prend un [Int]argument direction ( ) et renvoie une paire d'une nouvelle direction et une nouvelle C [Int]valeur.
  • best la fonction principale. Il convertit chaque caractère en Cvaleur, puis il appelle #.
    • g est la grille sous forme de liste de chaînes.
    • Étant donné qu'il \doit être échappé et qu'il s'agit du caractère le plus long à mentionner, son résultat est plutôt utilisé comme valeur par défaut pour la recherche de liste.
  • #exécute la simulation principale, vérifie les limites &et génère de nouvelles grilles avec ?. [y,x]est la position actuelle, dla direction actuelle et gla grille actuelle. [f,e]est la prochaine direction, et nest une paire de celle-ci et la prochaine grille.
  • l&ivérifie si l'index iest hors limites pour la liste l. (Il revient Truepour hors des limites, car cela évite une condition de garde factice dans #.)
  • Quand f(l!!i)==(d,x), (f?i)l==(d,m)mest la liste lavec le ie élément remplacé par x.
    • Techniquement, (?i)c'est un objectif plus général, se concentrant sur le ième élément d'une liste, dans ce cas utilisé avec l' (,) [Int]instance de foncteur.
  • n est la fonction représentant un point.
  • a vest une fonction représentant une flèche dans le sens v.
  • m sest une fonction représentant un miroir; s==1pour \\et s==-1pour /.
Ørjan Johansen
la source
1

JavaScript, 172 octets

f=(a,d=3,x=0,y=0,n=1)=>(p=a[y]||[],q=p[x])?(p[x]=~(t='^<V>'.indexOf(q))?'^<V>'[d^2]:q=='/'?(t=3-d,'\\'):q=='\\'?(t=d^1,'/'):(t=d,q),f(a,t,x+(t&1&&t-2),y+(~t&1&&t-1),n+1)):n

Mais je ne peux pas tester le dernier testcase car j'ai eu un débordement de pile sur ma machine. (devrait fonctionner s'il existe une machine avec un vérin plus grand)

Nous utilisons un nombre pour la direction:

  • 0: ^
  • 1: <
  • 2: V
  • 3:>

Soit dle numéro de direction ...

  • si nous rencontrons un '/', nous avons besoin de d = 3 - d;
  • si nous rencontrons un «\», nous avons besoin de d = d ^ 1;
  • si nous rencontrons un '^ <V>' nous avons besoin de d = '^ <V>' .indexOf (note)

Laissez - (x, y)être la position actuelle, la position suivante est: x+(t&1&&t-2),y+(~t&1&&t-1)

Remarque:

La fonction prend un paramètre au format suivant:

[ [ '\\', '.', 'V', '.', 'V', '.', 'V', '.', 'V', '.' ],
  [ '\\', '.', '/', '>', '/', '>', '/', '.', '\\', '<' ],
  [ '.', '>', '\\', '>', '\\', '>', '\\', '<', '.', '.' ],
  [ '.', '.', '^', '.', '^', '.', '^', '.', '^', '.' ] ]

Testez-le ici

f=(a,d=3,x=0,y=0,n=1)=>(p=a[y]||[],q=p[x])?(p[x]=~(t='^<V>'.indexOf(q))?'^<V>'[d^2]:q=='/'?(t=3-d,'\\'):q=='\\'?(t=d^1,'/'):(t=d,q),f(a,t,x+(t&1&&t-2),y+(~t&1&&t-1),n+1)):n

    ;k=x=>x.split('\n').map(t=>t.split(''));
<textarea id=v>\.V.V.V.V.
\./>/>/.\<
.>\>\>\<..
..^.^.^.^.</textarea><br/><button onclick="r.textContent=f(k(v.value))">Solve</button>
<p>Result: <output id=r></output></p>

tsh
la source
Juste pour documenter, je reçois Uncaught RangeError: Maximum call stack size exceededavec 16 Go de RAM.
Zeb McCorkle
1
@ZebMcCorkle aha, il suffit de découvrir que "use strict" et certaines vardéclarations lui font passer le dernier testcase (l'interpréteur js optimise les appels en mode strict)
tsh
1

C, 232 221 octets

d,n,t,m[4]={1,-1};char*w="><^V/\\.",*P;main(o,v)char**v;{for(P=v[1],m[2]=-(m[3]=strchr(P,10)-P+1);P>=v[1]&&P<strchr(v[1],0)&&*P^10;++n)*P=w[((o=d,t=strchr(w,*P)-w)<4)?d=t,o^1:(t<6)?d^=t-2,9-t:6],P+=m[d];printf("%d",n+1);}

Prend l'entrée dans le premier argument, imprime le résultat. Nécessite que l'entrée contienne au moins 1 nouvelle ligne (donc s'il n'y a qu'une seule ligne, elle doit se terminer par une nouvelle ligne)

Exemple d'utilisation:

./backflip '....
';

Panne:

d,                                          // Direction
n,                                          // Step counter
t,
m[4]={1,-1};                                // Movement offsets
char*w="><^V/\\.",                          // Command lookup
*P;                                         // Cursor location
main(o,v)char**v;{
    for(P=v[1],                             // Begin at 0,0
        m[2]=-(m[3]=strchr(P,10)-P+1);      // Find width of grid
        P>=v[1]&&P<strchr(v[1],0)&&*P^10;   // While inside grid:
        ++n)                                //  Increment step
        *P=w[                               //  Update the current cell
            ((o=d,t=strchr(w,*P)-w)         //  (store current direction & command)
              <4)?d=t,o^1:                  //   If <>^V, write backflip & set dir
            (t<6)?d^=t-2,9-t:               //   If / or \, write flip & bounce
            6],                             //   If ., write unchanged & continue
        P+=m[d];                            //  Move
    printf("%d",n+1);                       // Print result
}
Dave
la source
1

Python 3 , 286 octets

[f () prend l'entrée sous la forme de {(0,0):'/',(0,1):'.'}donc j'ai également écrit une fonction g () pour convertir un tableau de lignes dans cette forme]

def f(r):
 x=y=0;d='>';s=1
 while 1:
  try:c=r[y,x];m='>^<V'.find(d)
  except:break
  if(c=="\\"):d='V<^>'[m];r[y,x]="/"
  elif(c=="/"):d='^>V<'[m];r[y,x]="\\"
  elif(c!="."):r[y,x]='<V>^'[m];d=c
  x+=1if(d=='>')else-1if(d=='<')else 0;y+=1if(d=='V')else-1if(d=='^')else 0;s+=1
 return s

Essayez-le en ligne!

officialaimm
la source