<#; "#: ={},>
}=}(.);("@
Outra colaboração com @ MartinBüttner, que realmente fez mais quase todo o golfe para este. Renovando o algoritmo, conseguimos reduzir bastante o tamanho do programa!
Experimente online!
Explicação
Uma rápida cartilha Labrinth:
Labirinto é uma linguagem 2D baseada em pilha. Existem duas pilhas, uma pilha principal e auxiliar, e o surgimento de uma pilha vazia produz zero.
Em cada junção, onde há vários caminhos para o ponteiro da instrução se mover para baixo, a parte superior da pilha principal é verificada para ver para onde ir. Negativo é virar à esquerda, zero é reto e positivo é virar à direita.
As duas pilhas de números inteiros de precisão arbitrária não são muita flexibilidade em termos de opções de memória. Para realizar a contagem, esse programa realmente usa as duas pilhas como uma fita, com a mudança de um valor de uma pilha para outra sendo semelhante a mover um ponteiro de memória para a esquerda / direita por uma célula. Não é exatamente o mesmo que isso, pois precisamos arrastar um contador de loop conosco no caminho para cima.
Primeiro, as extremidades <
e, >
em cada extremidade, exibem um deslocamento e giram a linha de código que é deslocada para um lado esquerdo ou direito. Esse mecanismo é usado para fazer o código rodar em um loop - o valor <
é zero e gira a linha atual para a esquerda, colocando o IP à direita do código, e o valor >
zero e corrige a linha de volta.
Aqui está o que acontece a cada iteração, em relação ao diagrama acima:
[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