Faça um BackFlip para ais523!

16

Este desafio é um prêmio para ais523 por vencer a categoria " Novato do ano " em " Melhores do PPCG 2016 ". Parabéns!


O BackFlip é uma linguagem de programação esotérica criada pelo usuário ais523 , que criou mais de 30 outros esolangs interessantes .

O BackFlip é uma linguagem 2D como o Befunge ou > <>, onde o ponteiro da instrução percorre uma grade de texto (o programa), movendo-se para cima, para baixo, para a esquerda e para a direita, mudando de direção dependendo do caractere em que está. Criticamente, a grade em um programa BackFlip muda à medida que ela é atravessada, um pouco como a Ant de Langton .

Para esse desafio, você pode assumir que um programa BackFlip é sempre uma grade retangular de texto (todas as linhas do mesmo comprimento), tamanho 1 × 1 no mínimo, contendo apenas os caracteres ./\<>^V. ( .é usado para mais visibilidade do que espaço). Semanticamente, o BackFlip que usaremos aqui é idêntico à especificação original .

O ponteiro de instrução (IP) no BackFlip sempre inicia logo à esquerda do canto superior esquerdo do programa, indo para a direita. Existem três tipos de comandos que podem ser encontrados:

  1. .é um não-op. O IP continua na direção em que estava indo. O no-op permanece no-op.

  2. /e \são espelhos. Eles refletem o IP na direção indicada pelo ângulo e depois mudam para o outro tipo de espelho .

    • Por exemplo, se o IP for deixado em a \, ele começará a se mover para cima em vez de para a esquerda e \se tornará a /.
  3. <, >, ^, E Vsão setas. Eles redirecionam o IP para a direção em que apontam e depois mudam para uma seta que aponta na direção em que o IP veio (oposto à direção em que o IP estava se movendo) .

    • Por exemplo, se o IP for direcionado para baixo >, ele começa a se mover para a direita em vez de para baixo e >torna-se um ^porque é essa a direção da qual o IP veio.

Um programa BackFlip termina quando o IP sai dos limites, ou seja, sai da grade. Acontece tudo programas BackFlip eventualmente terminam porque loops infinitos são impossíveis. (Você pode assumir que isso é verdade.)

Seu objetivo neste desafio é escrever um programa ou função que receba um programa BackFlip e produza o número de movimentos que o ponteiro de instruções realiza antes que o programa termine. Ou seja, quantas etapas o IP executa no decorrer da execução de um programa? Isso inclui a etapa inicial na grade e a etapa final dela.

Por exemplo, o ponteiro de instruções executa 5 etapas na grade trivial ....:

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

Então a saída para ....é 5.

Na grade 4 × 2 mais complexa

\...
\.><

o IP sai da grade na sua 9a etapa, portanto a saída é 9:

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

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

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

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

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

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

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

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

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

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

O código mais curto em bytes vence.

Você pode receber a entrada como uma matriz de linhas ou matriz de caracteres, em vez de uma sequência de múltiplas linhas, se desejar, mas você deve usar os caracteres ./\<>^V(não os códigos de operação inteiros). Você pode usar espaço em vez de. se preferir. Tudo bem se personagens como\ precisam ser escapados na entrada. A saída é sempre um número inteiro mais de um.

Casos de teste

....
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
Passatempos de Calvin
fonte
1
É uma pena que você não pode fazer uma solução backflip a esta ...
HyperNeutrino
Confuso sobre os espelhos ... faz / vira as direções como esquerda => cima e cima => esquerda ,?
officialaimm
1
@officialaimm Dirigir da esquerda para a esquerda /fará o IP subir e subir para /a direita fará a direita, como se fosse uma bola quicando na parede. (Mas lembre-se as /alterações à barra invertida após o IP toca.)
de Calvino Hobbies
por que '\\' <LF> '\ /' é 7 em vez de 6?
tsh

Respostas:

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

Desenvolvido independentemente da resposta do @ tsh, embora surpreendentemente semelhante.

O mapeamento de direções ^<v>para números inteiros 0-3 é governado pelo fato de .search('^')retornar 0, pois ^é um metacaractere de expressão regular.

Neil
fonte
Eu me sinto tão profundamente derrotado. Fiquei bastante confuso no final até perceber que xey foram invertidos em comparação com o que eu esperava.
Ørjan Johansen
@ ØrjanJohansen Esse é um bom ponto; talvez eu devesse trocar x com y em todos os lugares para facilitar a compreensão.
Neil
2

Haskell , 333 325 bytes

EDITAR:

  • -8 bytes: ftornado sem ponto e mesclado b.

bpega uma lista de se Stringretorna um 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))

Experimente online!

Como funciona

  • C aé um tipo de dados usado porque Haskell não permitirá que um tipo seja recursivo sem declará-lo explicitamente. Ctambém é um construtor de quebra cautomática e é sua função de desempacotamento correspondente. É usado apenas com a=[Int].
    • O tipo C [Int]representa um comando de célula, como uma função que usa um [Int]argumento direction ( ) e retorna um par de uma nova direção e um novo C [Int]valor.
  • bé a função principal. Ele converte cada caractere em um Cvalor e chama# .
    • g é a grade como uma lista de cadeias.
    • Como \precisa ser escapado e, portanto, o caractere mais longo a ser mencionado, seu resultado é usado como o valor padrão para a pesquisa da lista.
  • #executa a simulação principal, verificando limites &e gerando novas grades com ?. [y,x]é a posição atual, da direção atual e ga grade atual. [f,e]é a próxima direção, e né um par dela e a próxima grade.
  • l&iverifica se o índice iestá fora dos limites da lista l. (Ele retorna Truepara fora dos limites, pois evita uma condição fictícia de guarda #.)
  • Quando f(l!!i)==(d,x), (f?i)l==(d,m)onde mé a lista lcom o ith elemento substituído por x.
    • Tecnicamente, (?i)é uma lente mais geral, focada no i-ésimo elemento de uma lista, neste caso, usada com a (,) [Int]instância do functor.
  • n é a função que representa um ponto.
  • a vé uma função que representa uma seta na direção v.
  • m sé uma função que representa um espelho; s==1para \\e s==-1para /.
Ørjan Johansen
fonte
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

Mas não consigo testar o último testcase desde que o estouro de pilha na minha máquina. (deve funcionar se houver uma máquina com ram maior)

Usamos um número para direção:

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

Seja do número da direção ...

  • se encontrarmos um '/', precisamos d = 3 - d;
  • se encontrarmos um '\', precisamos d = d ^ 1;
  • se encontrarmos um '^ <V>', precisamos de d = '^ <V>' .indexOf (note)

Vamos (x, y)ser posição actual, a posição seguinte é: x+(t&1&&t-2),y+(~t&1&&t-1)

Nota:

A função usa um parâmetro com o seguinte formato:

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

Teste aqui

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
fonte
Só para documentar, estou conseguindo Uncaught RangeError: Maximum call stack size exceededcom 16 GB de RAM.
Zeb McCorkle
1
@ZebMcCorkle aha, apenas descobrir que "use strict" e alguns vardeclaração fazê-lo passar o último testcase (js intérprete fazer otimizar chamada de cauda no modo estrito)
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);}

Recebe entrada no primeiro argumento, imprime resultado. Requer que a entrada contenha pelo menos 1 nova linha (portanto, se houver apenas 1 linha, ela deverá terminar com uma nova linha)

Exemplo de uso:

./backflip '....
';

Demolir:

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

Python 3 , 286 bytes

[f () recebe entrada na forma de {(0,0):'/',(0,1):'.'}, também escrevi uma função g () para converter uma matriz de linhas para essa 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

Experimente online!

officialaimm
fonte