<#; "#: ={},>
}=}(.);("@
Otra colabo con @ MartinBüttner, que en realidad hizo más casi todo el golf para éste. ¡Al renovar el algoritmo, hemos logrado reducir el tamaño del programa bastante!
Pruébalo en línea!
Explicación
Una cartilla rápida de Labrinth:
Labyrinth es un lenguaje 2D basado en pila. Hay dos pilas, una pila principal y una pila auxiliar, y el estallido de una pila vacía produce cero.
En cada cruce, donde hay múltiples rutas para que el puntero de instrucciones se mueva hacia abajo, se comprueba la parte superior de la pila principal para ver a dónde ir después. Negativo es girar a la izquierda, cero es recto y positivo es girar a la derecha.
Las dos pilas de enteros de precisión arbitraria no tienen mucha flexibilidad en términos de opciones de memoria. Para realizar el recuento, este programa en realidad usa las dos pilas como una cinta, con el cambio de un valor de una pila a otra es similar a mover un puntero de memoria hacia la izquierda / derecha por una celda. Sin embargo, no es exactamente lo mismo, ya que necesitamos arrastrar un contador de bucle con nosotros en el camino hacia arriba.
En primer lugar, el <
y >
en cada extremo muestra un desplazamiento y gira la fila de código que se desplaza por uno hacia la izquierda o hacia la derecha. Este mecanismo se utiliza para hacer que el código se ejecute en un bucle: <
aparece un cero y gira la fila actual hacia la izquierda, colocando la IP a la derecha del código, y >
aparece otro cero y repara la fila.
Esto es lo que sucede cada iteración, en relación con el diagrama anterior:
[Section 1]
,} Read char of input and shift to aux - the char will be used as a counter
to determine how many elements to shift
[Section 2 - shift loop]
{ Shift counter from aux
" No-op at a junction: turn left to [Section 3] if char was EOF (-1), otherwise
turn right
( Decrement counter; go forward to [Section 4] if zero, otherwise turn right
= Swap tops of main and aux - we've pulled a value from aux and moved the
decremented counter to aux, ready for the next loop iteration
[Section 3]
@ Terminate
[Section 4]
; Pop the zeroed counter
) Increment the top of the main stack, updating the count of the number of times
we've seen the read char
: Copy the count, to determine how many chars to output
[Section 5 - output loop]
#. Output (number of elements on stack) as a char
( Decrement the count of how many chars to output; go forward to [Section 6]
if zero, otherwise turn right
" No-op
[Section 6]
} Shift the zeroed counter to aux
[Section 7a]
This section is meant to shift one element at a time from main to aux until the main
stack is empty, but the first iteration actually traverses the loop the wrong way!
Suppose the stack state is [... a b c | 0 d e ...].
= Swap tops of main and aux [... a b 0 | c d e ...]
} Move top of main to aux [... a b | 0 c d e ...]
#; Push stack depth and pop it (no-op)
= Swap tops of main and aux [... a 0 | b c d e ...]
Top is 0 at a junction - can't move
forwards so we bounce back
; Pop the top 0 [... a | b c d e ... ]
The net result is that we've shifted two chars from main to aux and popped the
extraneous zero. From here the loop is traversed anticlockwise as intended.
[Section 7b - unshift loop]
# Push stack depth; if zero, move forward to the <, else turn left
}= Move to aux and swap main and aux, thus moving the char below (stack depth)
to aux
; Pop the stack depth