<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
A entrada é N
seguida pela sequência, separada por qualquer caractere não numérico.
Experimente online!
Isso foi escrito em colaboração com o Sp3000 (o que significa que eu não me incomodei em descobrir um algoritmo, então ele começou a trabalhar nele, veio com uma solução de 118 bytes, mas não se incomodou em jogar golfe, então fiz o golfe. .. sim pelo trabalho em equipe).
Explicação
Primário usual de Sp (como de costume ligeiramente modificado):
- Labyrinth é uma linguagem 2D baseada em pilha com duas pilhas, principal e auxiliar. Praticamente tudo acontece na pilha principal, mas você pode mudar os valores para a outra, por exemplo, para revertê-los ou salvá-los para mais tarde.
- As pilhas não têm fundo e são preenchidas com zeros, portanto, saltar de uma pilha vazia não é um erro.
- A execução começa a partir do primeiro caractere válido (aqui, no canto superior esquerdo). Em cada junção, onde há dois ou mais caminhos possíveis para o ponteiro de instrução (IP) seguir, a parte superior da pilha é verificada para determinar para onde seguir. Negativo é virar à esquerda, zero é avançar e positivo é virar à direita. Embora isso tenha o objetivo de fazer o código parecer passagens sinuosas e sinuosas, não há nada que o impeça de criar "salas" onde essas condições são verificadas em todas as células. Aqueles podem produzir um comportamento bastante imprevisível, mas são ótimos para jogar golfe.
- O código fonte (e, portanto, o layout do labirinto) pode ser modificado em tempo de execução usando o
<>^v
que alterna ciclicamente uma linha ou coluna ou a grade.
"
são no-ops.
Aqui vamos nós.
O código começa no <
, que é um truque de golfe que eu usei algumas vezes ao começar com um longo pedaço de código linear. Ele desloca a primeira linha ciclicamente para a esquerda, com o IP , para que a fonte fique assim:
<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
Mas agora o IP não pode ser movido para lugar algum, portanto, ele executa <
novamente. Isso continua até chegarmos a este estado:
<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
Nesse ponto, o IP pode deixar a célula e começar a executar a segunda linha começando no ?
. Então aqui está o código linear dividido:
? # Read the first integer on STDIN, i.e. N.
:} # Duplicate it and move one copy over to the auxiliary stack.
, # Read the separator character.
,. # Read the first character of the input string and directly print it.
O IP agora entra nesta sala 3x2, que na verdade é dois loops 2x2 no sentido horário compactados (sobrepostos). O primeiro loop lê e descarta N-1
caracteres de STDIN.
; # Discard the top of the stack. On the first iteration, this is the
# separator we've already read. On subsequent iterations this will be
# one of the N-1 characters from the input string.
( # Decrement N. If this hits zero, we leave the loop, otherwise we continue.
, # Read the next character from STDIN to be discarded.
Agora entramos no segundo loop que lê o restante da string de entrada. Podemos detectar o EOF porque ,
retornará -1
nesse caso, fazendo com que o IP vire à esquerda.
, # Read a character. Exit the loop if EOF.
( # Decrement it.
Esse decremento não é realmente útil, mas podemos desfazê-lo mais tarde de graça e aqui nos permite sobrepor os dois loops.
Se tomarmos a 5 ABCDEFGHIJKLMNOP
entrada como exemplo, a pilha será assim:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' -1 | 5 ... ] Auxiliary
Observe que eles realmente correspondem aos caracteres de entrada FGHIJKLMNOP
(porque os diminuímos) e que na verdade não queremos imprimir o primeiro deles (apenas descartamos os N-1
caracteres, mas queremos pular N
).
Agora há um pequeno bit linear que prepara a pilha para o próximo loop:
; # Discard the -1.
= # Swap the tops of the stacks, i.e. N with the last character.
# By putting the last character on the auxiliary stack, we ensure that
# it doesn't get discarded in the next loop.
} # Move N over to the auxiliary stack as well.
As pilhas agora se parecem com:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' | 5 'O' ... ] Auxiliary
Entramos em outro loop 2x2 no sentido horário. Isso descarta os principais N
caracteres da pilha principal:
; # Discard the top of the main stack.
{ # Pull N over from the auxiliary stack.
( # Decrement it. It it's 0 we leave the loop.
} # Push N back to the auxiliary stack.
Quando saímos do loop, =
trocamos esse 0
e o último caractere da string de entrada novamente. Agora as pilhas ficam assim:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'O' | ... ] Auxiliary
Queremos imprimir o conteúdo da pilha principal (exceto o elemento inferior e todos incrementados em 1), a partir da esquerda . Isso significa que precisamos transferi-lo para a pilha auxiliar. É isso que o próximo loop 2x2 (no sentido horário) faz:
{ # Pull an element over from the auxiliary stack. This is necessary so we
# have a 0 on top of the stack when entering the loop, to prevent the IP
# from turning right immediately.
} # Move the top of the main stack back to the auxiliary stack. If this was the
# bottom of the stack, exit the loop.
) # Increment the current character.
} # Move it over to the auxiliary stack.
Pilhas agora:
Main [ ... | 'F' 'G' 'H' 'I' 'J' 'P] ... ] Auxiliary
Movemos o primeiro desses (aquele que não queremos imprimir) de volta para a pilha principal {
. E agora entramos no loop final 2x2 ( sentido anti-horário ), que imprime o restante:
{ # Pull another character over from the auxiliary stack. Exit the loop
# if that's the zero at the bottom of the stack.
. # Print the character.
Finalmente encerramos o programa com @
.
'
o caractere de contagem? Por exemplo''123321
:?