¡Haz un BackFlip para ais523!

16

Este desafío es un premio para ais523 por ganar la categoría " Novato del año " en " Lo mejor de PPCG 2016 ". ¡Felicidades!


BackFlip es un lenguaje de programación esotérico creado por el usuario ais523 , que ha creado más de 30 interesantes esolangs .

BackFlip es un lenguaje 2D como Befunge o > <> donde el puntero de instrucción atraviesa una cuadrícula de texto (el programa), moviéndose hacia arriba, hacia abajo, hacia la izquierda y hacia la derecha, cambiando de dirección según el carácter en el que se encuentre. Críticamente, la cuadrícula en un programa BackFlip cambia a medida que se atraviesa, un poco como la hormiga de Langton .

Para este desafío, puede suponer que un programa BackFlip es siempre una cuadrícula de texto rectangular (todas las líneas tienen la misma longitud), 1 × 1 de tamaño mínimo, que solo contiene los caracteres ./\<>^V. ( .se usa para visibilidad en lugar de espacio). Semánticamente, el BackFlip que usaremos aquí es idéntico a la especificación original .

El puntero de instrucción (IP) en BackFlip siempre comienza justo a la izquierda de la esquina superior izquierda del programa, hacia la derecha. Hay tres tipos de comandos que puede encontrar:

  1. .es un no-op. La IP continúa en la dirección en que se dirigía. El no-op sigue siendo un no-op.

  2. /Y \son espejos. Reflejan la IP en la dirección indicada por su ángulo, luego cambian al otro tipo de espejo .

    • Por ejemplo, si la IP se dirige hacia la izquierda \, comienza a moverse hacia arriba en lugar de hacia la izquierda y se \convierte en a /.
  3. <, >, ^, Y Vson flechas. Redirigen la IP a la dirección en la que apuntan, luego cambian a una flecha que apunta en la dirección de la que proviene la IP (opuesta a la dirección en que se movía la IP) .

    • Por ejemplo, si la IP se dirige hacia abajo >, comienza a moverse hacia la derecha en lugar de hacia abajo y se >convierte en una ^porque esa es la dirección de la que proviene la IP.

Un programa BackFlip finaliza cuando la IP se sale de los límites, es decir, se desconecta de la red. Resulta que todos los programas BackFlip finalmente terminan porque los bucles infinitos son imposibles. (Puede suponer que esto es cierto).

Su objetivo en este desafío es escribir un programa o función que tome un programa BackFlip y genere el número de movimientos que realiza el puntero de instrucción antes de que finalice el programa. Es decir, ¿cuántos pasos toma la IP en el curso de la ejecución de un programa? Esto incluye el paso inicial en la cuadrícula y el paso final fuera de ella.

Por ejemplo, el puntero de instrucciones toma 5 pasos en la cuadrícula trivial ....:

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

Entonces la salida a ....es 5.

En la cuadrícula 4 × 2 más compleja

\...
\.><

la IP sale de la cuadrícula en su noveno paso, por lo que la salida es 9:

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

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

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

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

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

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

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

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

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

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

El código más corto en bytes gana.

Puede tomar la entrada como una matriz de líneas o matriz de caracteres en lugar de una cadena de varias líneas si lo desea, pero debe usar los caracteres ./\<>^V(no los códigos de operación enteros). Puede usar espacio en lugar de .si lo prefiere. Está bien si se \necesita escapar caracteres como en la entrada. La salida es siempre un entero más de uno.

Casos de prueba

....
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
Pasatiempos de Calvin
fuente
1
Es una pena que no puedas hacer una solución BackFlip para esto ...
HyperNeutrino
Confundido acerca de los espejos ... ¿hace / voltea las direcciones como izquierda => arriba y arriba => izquierda ,?
officialaimm
1
@officialaimm Dirigirse desde la izquierda hacia /la IP hará que suba y hacia arriba /hará que la IP vaya hacia la derecha, como si fuera una pelota que rebota en una pared. (Pero recuerde los /cambios en la barra invertida después de que la IP lo toque).
Calvin's Hobbies
¿Por qué '\\' <LF> '\ /' es 7 en lugar de 6?
tsh

Respuestas:

3

JavaScript (ES6), 158 bytes

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

Desarrollado independientemente de la respuesta de @ tsh, aunque sorprendentemente similar.

La asignación de direcciones ^<v>a enteros 0-3 se rige por el hecho de que .search('^')devuelve 0 ya que ^es un metacarácter regexp.

Neil
fuente
Me siento muy golpeado. Estaba bastante confundido al final hasta que me di cuenta de que x e y se voltearon en comparación con lo que esperaba.
Ørjan Johansen el
@ ØrjanJohansen Ese es un buen punto; tal vez debería cambiar x con y en todas partes para que sea más fácil de entender.
Neil
2

Haskell , 333 325 bytes

EDITAR:

  • -8 bytes: hecho sin fpuntos y fusionado b.

btoma una lista de Stringsy devuelve 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))

Pruébalo en línea!

Cómo funciona

  • C aes un tipo de datos utilizado porque Haskell no permitirá que un tipo sea recursivo sin declararlo explícitamente. Ctambién es un constructor de envoltura y ces su función de desenvoltura correspondiente. Solo se usa con a=[Int].
    • El tipo C [Int]representa un comando de celda, como una función que toma un [Int]argumento direction ( ) y devuelve un par de una nueva dirección y un nuevo C [Int]valor.
  • bEs la función principal. Convierte cada carácter en un Cvalor, luego llama #.
    • g es la cuadrícula como una lista de cadenas.
    • Debido a que \necesita ser escapado y también lo es el carácter más largo para mencionar, su resultado se usa como el valor predeterminado para la búsqueda de la lista.
  • #ejecuta la simulación principal, verifica los límites &y genera nuevas cuadrículas con ?. [y,x]es la posición actual, dla dirección actual y gla cuadrícula actual. [f,e]es la siguiente dirección, y nes un par de ella y la siguiente cuadrícula.
  • l&icomprueba si el índice iestá fuera de los límites de la lista l. (Vuelve Truefuera de límites, ya que eso evita una condición de guardia ficticia en #).
  • Cuándo f(l!!i)==(d,x), (f?i)l==(d,m)dónde mestá la lista lcon el ielemento th reemplazado por x.
    • Técnicamente (?i)es una lente más general, que se enfoca en el i-ésimo elemento de una lista, en este caso usado con la (,) [Int]instancia de functor.
  • n es la función que representa un punto.
  • a ves una función que representa una flecha en dirección v.
  • m ses una función que representa un espejo; s==1por \\y s==-1para /.
Ørjan Johansen
fuente
1

JavaScript, 172 bytes

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

Pero no puedo probar el último caso de prueba ya que tuve un desbordamiento de pila en mi máquina. (debería funcionar si hay una máquina con ram más grande)

Usamos un número para la dirección:

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

Deje dser el número de dirección ...

  • si encontramos un '/', necesitamos d = 3 - d;
  • si nos encontramos con un '\' necesitamos d = d ^ 1;
  • si nos encontramos con un '^ <V>' necesitamos d = '^ <V>' .indexOf (nota)

Vamos a (x, y)ser la posición actual, la siguiente posición es: x+(t&1&&t-2),y+(~t&1&&t-1)

Nota:

La función toma un parámetro con el siguiente formato:

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

Pruébalo aquí

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
fuente
Solo para documentar, obtengo Uncaught RangeError: Maximum call stack size exceeded16GB de RAM.
Zeb McCorkle
1
@ZebMcCorkle aha, solo descubre que "usar estricto" y alguna vardeclaración lo hacen pasar el último caso de prueba (el intérprete js optimiza la llamada de cola en modo estricto)
tsh
1

C, 232 221 bytes

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);}

Toma entrada en el primer argumento, imprime el resultado. Requiere que la entrada contenga al menos 1 nueva línea (por lo tanto, si solo hay 1 fila, debe terminar con una nueva línea)

Ejemplo de uso:

./backflip '....
';

Descompostura:

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
fuente
1

Python 3 , 286 bytes

[f () toma la entrada en forma de, {(0,0):'/',(0,1):'.'}así que también he escrito una función g () para convertir una matriz de líneas a esa forma]

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

Pruébalo en línea!

officialaimm
fuente