<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
La entrada es N
seguida por la cadena, separada por cualquier carácter no numérico.
Pruébalo en línea!
Esto fue escrito en colaboración con Sp3000 (lo que significa que no me molesté en descifrar un algoritmo, por lo que comenzó a trabajar en él, ideó una solución de 118 bytes pero no me molestó jugar al golf, así que hice el golf. .. yay para el trabajo en equipo).
Explicación
Imprimación habitual de Sp (como siempre ligeramente modificada):
- Labyrinth es un lenguaje 2D basado en pila con dos pilas, principal y auxiliar. Casi todo sucede en la pila principal, pero puede cambiar los valores a la otra, por ejemplo, para revertirlos o guardarlos para más adelante.
- Las pilas no tienen fondo y están llenas de ceros, por lo que saltar de una pila vacía no es un error.
- La ejecución comienza desde el primer carácter válido (aquí arriba a la izquierda). En cada cruce, donde hay dos o más rutas posibles para que el puntero de instrucción (IP) tome, la parte superior de la pila se verifica para determinar a dónde ir después. Negativo es girar a la izquierda, cero es avanzar y positivo es girar a la derecha. Si bien esto estaba destinado a hacer que el código pareciera pasajes sinuosos y sinuosos, no hay nada que le impida hacer "habitaciones" donde se verifican estas condiciones en cada celda. Esos pueden producir un comportamiento bastante impredecible, pero son excelentes para jugar al golf.
- El código fuente (y, por lo tanto, el diseño del laberinto) se puede modificar en tiempo de ejecución mediante el
<>^v
cual se desplaza cíclicamente una fila o columna o la cuadrícula.
"
son no-ops.
Aquí vamos.
El código comienza en el <
, que es un truco de golf que he usado varias veces al comenzar con un código lineal largo. Desplaza la primera fila cíclicamente a la izquierda, con la IP en ella , por lo que la fuente se ve así:
<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
Pero ahora la IP no puede moverse a ninguna parte, por lo que se ejecuta <
nuevamente. Esto continúa hasta que alcancemos este estado:
<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
En este punto, la IP puede abandonar la celda y comenzar a ejecutar la segunda línea a partir de ?
. Así que aquí está el código lineal desglosado:
? # 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.
El IP ahora ingresa a esta sala de 3x2, que en realidad son dos bucles 2x2 apretados (superpuestos) en sentido horario. El primer ciclo lee y 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.
Ahora ingresamos al segundo ciclo que lee el resto de la cadena de entrada. Podemos detectar EOF porque ,
volverá -1
en ese caso, haciendo que la IP gire a la izquierda.
, # Read a character. Exit the loop if EOF.
( # Decrement it.
Esa disminución no es realmente útil, pero podemos deshacerla más tarde de forma gratuita y aquí nos permite superponer los dos bucles.
Si tomamos la 5 ABCDEFGHIJKLMNOP
entrada como un ejemplo, la pila se ve así:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' -1 | 5 ... ] Auxiliary
Tenga en cuenta que estos realmente corresponden a los caracteres de entrada FGHIJKLMNOP
(porque los disminuimos), y que en realidad no queremos imprimir el primero de ellos (solo hemos descartado los N-1
caracteres, pero queremos omitirlos N
).
Ahora hay un bit lineal corto que prepara la pila para el siguiente ciclo:
; # 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.
Las pilas ahora se ven así:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' | 5 'O' ... ] Auxiliary
Entramos en otro ciclo de 2x2 en sentido horario. Esto descarta los N
caracteres superiores de la pila 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.
Cuando salimos del bucle, =
intercambiamos eso 0
y el último carácter de la cadena de entrada nuevamente. Ahora las pilas se ven así:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'O' | ... ] Auxiliary
Queremos imprimir el contenido de la pila principal (excepto el elemento inferior y todo incrementado en 1), desde la izquierda . Eso significa que necesitamos llevarlo a la pila auxiliar. Eso es lo que hace el siguiente ciclo 2x2 (en sentido horario):
{ # 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.
Pilas ahora:
Main [ ... | 'F' 'G' 'H' 'I' 'J' 'P] ... ] Auxiliary
Volvemos al primero de ellos (el que no queremos imprimir) de nuevo a la pila principal {
. Y ahora entramos en el ciclo final 2x2 (en sentido antihorario ), que imprime el resto:
{ # 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 terminamos el programa con @
.
'
como el personaje que cuenta? Por ejemplo''123321
:?