<#; "#: ={},>
}=}(.);("@
Другой сотрудни с @ MartinBüttner, который на самом деле сделал большинство почти все игры в гольф для этого. Переработав алгоритм, нам удалось значительно сократить размер программы!
Попробуйте онлайн!
объяснение
Быстрый лабринтный учебник:
Лабиринт - это двумерный язык на основе стека. Есть два стека, основной и вспомогательный, и выталкивание из пустого стека дает ноль.
На каждом перекрестке, где есть несколько путей перемещения указателя инструкции вниз, проверяется вершина основного стека, чтобы увидеть, куда идти дальше. Отрицательный - поворот налево, ноль - прямой, а положительный поворот направо.
Два стека целых чисел произвольной точности не очень гибки с точки зрения параметров памяти. Чтобы выполнить подсчет, эта программа фактически использует два стека в качестве ленты, смещая значение из одного стека в другой, сродни перемещению указателя памяти влево / вправо по ячейке. Это не совсем то же самое, поскольку нам нужно тащить счетчик петель с собой по пути вверх.
Во-первых, <
и >
на каждом конце вставьте смещение и поверните строку кода, которая смещена на единицу влево или вправо. Этот механизм используется для того, чтобы код выполнялся в цикле - он <
выталкивает ноль и поворачивает текущую строку влево, помещая IP-адрес справа от кода, а >
выталкивает еще один ноль и фиксирует строку обратно.
Вот что происходит на каждой итерации по отношению к диаграмме выше:
[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