<#; "#: ={},>
}=}(.);("@
Un autre collab avec @ MartinBüttner, qui a effectivement fait plus la quasi - totalité du golf pour celui - ci. En réaménageant l'algorithme, nous avons réussi à réduire de beaucoup la taille du programme!
Essayez-le en ligne!
Explication
Un rapide apprêt de Labrinth:
Labyrinth est un langage 2D basé sur des piles. Il y a deux piles, une pile principale et une pile auxiliaire, et le décompression d'une pile vide donne zéro.
À chaque jonction, où il existe plusieurs chemins pour le pointeur d'instruction à déplacer vers le bas, le haut de la pile principale est vérifié pour voir où aller ensuite. Le négatif est à gauche, le zéro est droit et le positif à droite.
Les deux piles d'entiers de précision arbitraire ne sont pas très flexibles en termes d'options de mémoire. Pour effectuer le comptage, ce programme utilise en fait les deux piles en tant que bande, le déplacement d’une valeur d’une pile à l’autre revenant à déplacer un pointeur de mémoire vers la gauche ou la droite d’une cellule. Ce n’est pas tout à fait la même chose, car nous devons faire glisser un compteur de boucles avec nous vers le haut.
Tout d’abord, les boutons <
et >
à chaque extrémité créent un décalage et font pivoter la ligne de code qui est décalée d’un côté à l’autre. Ce mécanisme est utilisé pour que le code soit exécuté en boucle: le <
zéro s'affiche et la ligne actuelle est pivotée à gauche, en plaçant l'adresse IP à droite du code, puis >
un autre zéro et la ligne est corrigée.
Voici ce qui se passe à chaque itération, par rapport au diagramme ci-dessus:
[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