<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
За вводом N
следует строка, отделенная любым нечисловым символом.
Попробуйте онлайн!
Это было написано в сотрудничестве с Sp3000 (что означает, что я не мог разобраться с алгоритмом, поэтому он начал работать над ним, придумал 118-байтовое решение, но не мог быть обеспокоен игрой в гольф, поэтому я занялся гольфом. .. ура для совместной работы).
объяснение
Обычный праймер Sp (как обычно, немного модифицированный):
- Лабиринт - это двумерный язык на основе стека с двумя стеками: основным и вспомогательным. Практически все происходит в основном стеке, но вы можете перенести значения в другое, например, чтобы изменить их или сохранить на потом.
- Стеки бездонные и заполнены нулями, поэтому выталкивание из пустого стека не является ошибкой.
- Выполнение начинается с первого действительного символа (здесь вверху слева). В каждом соединении, где есть два или более возможных путей для указателя инструкций (IP), вершина стека проверяется, чтобы определить, куда идти дальше. Отрицательным является поворот влево, нулевым - движение вперед, а положительным - поворот направо. Хотя это должно было сделать код похожим на извилистые, извилистые переходы, ничто не мешает вам создавать «комнаты», в которых эти условия проверяются в каждой ячейке. Они могут привести к совершенно непредсказуемому поведению, но отлично подходят для игры в гольф.
- Исходный код (и, следовательно, макет лабиринта) может быть изменен во время выполнения, используя
<>^v
который циклически сдвигает строку или столбец или сетку.
"
нет опс.
Вот так.
Код начинается <
с трюка, который я использовал несколько раз, когда начинал с длинного куска линейного кода. Он смещает первый ряд циклически влево с IP-адресом , поэтому источник выглядит следующим образом:
<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
Но теперь IP не может никуда двигаться, поэтому он выполняет <
снова. Это продолжается, пока мы не достигнем этого состояния:
<
,,}:?
.
;(" {(={}{".
,",;=};} }) "{@
В этот момент IP может покинуть ячейку и начать выполнение второй строки, начиная с ?
. Итак, вот линейный код с разбивкой:
? # 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.
Теперь IP входит в эту комнату 3x2, которая на самом деле представляет собой две сильно сжатые (перекрывающиеся) петли 2x2 по часовой стрелке. Первый цикл читает и отбрасывает N-1
символы из 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.
Теперь мы вводим второй цикл, который читает остаток входной строки. Мы можем обнаружить EOF, потому ,
что -1
в этом случае вернемся , и IP повернет налево.
, # Read a character. Exit the loop if EOF.
( # Decrement it.
Это уменьшение на самом деле не полезно, но мы можем отменить его позже бесплатно, и здесь оно позволяет нам перекрывать два цикла.
Если мы возьмем 5 ABCDEFGHIJKLMNOP
входные данные в качестве примера, стек выглядит так:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' -1 | 5 ... ] Auxiliary
Обратите внимание, что они на самом деле соответствуют входным символам FGHIJKLMNOP
(потому что мы их уменьшили), и что мы на самом деле не хотим печатать первые из них (мы только отбросили N-1
символы, но хотим пропустить N
).
Теперь есть короткий линейный бит, который подготавливает стек к следующему циклу:
; # 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.
Стеки теперь выглядят так:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' | 5 'O' ... ] Auxiliary
Мы входим в другой цикл 2x2 по часовой стрелке. Это отбрасывает верхние N
символы из основного стека:
; # 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.
Когда мы выходим из цикла =
, 0
снова меняем местами последний и последний символ входной строки. Теперь стеки выглядят так:
Main [ ... 'E' 'F' 'G' 'H' 'I' 'O' | ... ] Auxiliary
Мы хотим напечатать содержимое основного стека (кроме нижнего элемента и всего с шагом 1) слева . Это означает, что нам нужно передать его во вспомогательный стек. Вот что делает следующий цикл 2x2 (по часовой стрелке):
{ # 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.
Стеки сейчас:
Main [ ... | 'F' 'G' 'H' 'I' 'J' 'P] ... ] Auxiliary
Мы перемещаем первый из них (тот, который мы не хотим печатать) обратно в основной стек {
. И теперь мы входим в последний цикл 2x2 ( против часовой стрелки ), который печатает остаток:
{ # 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.
Наконец мы завершаем программу с @
.
'
символом счета? Например:''123321
?