Лабиринт , 28 25 24 23 22 байта
" >
?!?:|}\{@
@\?"":)!
Это было безумно весело! :) Это самая плотно сжатая программа Лабиринт, которую я когда-либо писал. У меня было так много версий на 20 и 21 байт, которые почти сработали, и я все еще сомневаюсь, что это оптимально ...
Он принимает входные данные в виде списка натуральных чисел (с произвольным разделителем) и выводит результат в STDOUT как целые числа, разделенные переводом строки.
Охота на 20/21 байт: я проверил все программы вида
" XX
?!?X}\{@
@\?XX)!
где X
любой разумный характер грубой силой, но не нашел каких-либо действительных решений. Конечно, это не означает, что более короткого решения не существует, но невозможно заставить 20-байтовые программы без приличного количества предположений о его структуре.
объяснение
(Объяснение немного устарело, но я все еще не уверен, что решение является оптимальным, поэтому я подожду с его обновлением.)
Итак, обычно лабиринтные программы должны выглядеть как лабиринты. Пока указатель инструкций находится в коридоре, он будет следовать за этим коридором. Когда IP-адрес достигает любого вида соединения, направление определяется на основе верхнего значения основного стека Лабиринта (Лабиринт имеет два стека с бесконечным количеством нулей внизу). Как правило, это означает, что любой нетривиальный цикл будет довольно дорогим, потому что если у вас повсюду непустые ячейки, все является соединением, и в большинстве случаев вершина стека не будет иметь правильное значение для IP. идти по пути, который вы хотели бы выбрать. Итак, что вы делаете, вы увеличиваете петли так, чтобы они имели единое целое в центре только с одной четко определенной точкой входа и выхода каждая.
Но в этот раз мне действительно повезло, и все так хорошо сочеталось друг с другом, что я мог сложить все в один большой комок. :)
Поток управления начинается на _
юге. _
Толкает ноль на основной стек. Это может показаться неактивным, но это увеличивает (неявную) глубину стека, до 1
которой мы будем нуждаться позже.
?
читает целое число из STDIN. Если больше нет целых чисел для чтения, это толкает ноль. В этом случае IP-адрес продолжает двигаться на юг и сразу же @
завершает работу программы (поскольку список ввода пуст). В противном случае IP поворачивает на восток.
Сейчас мы входим в очень узкий цикл с двумя точками выхода:
!?;
\?
;
!
возвращает целое число обратно в STDOUT, оставляя только ноль в стеке. IP продолжает двигаться на восток и ?
читает следующее целое число. Если это не ноль, мы берем право и движемся на юг. ?
читает другой (следующий четный индекс). Опять же, если это не ноль, мы берем право и движемся на запад.
Затем \
печатает перевод строки без изменения стека, поэтому мы делаем еще один поворот вправо, двигаясь на север. !
выводит следующее целое число четного индекса Поскольку теперь в стеке есть хотя бы одно (положительное) нечетное целое число, мы продолжаем поворачивать направо и цикл повторяется.
Как только один из них ?
попадает в конец списка, они нажимают ноль и двигаются прямо на соответствующий ;
, который отбрасывает этот ноль.
В случае, если в списке был только один элемент, мы закончили (потому что мы распечатали это сразу), поэтому IP продолжит двигаться на восток до самого @
конца, снова завершив программу (печатая завершающий перевод строки в пути).
В противном случае нам также необходимо вывести нечетные целые числа. В этом случае два пути (из двух точек выхода первого цикла) сливаются в середине "
, поворачивая на восток в любом случае.
_
толкает ноль, чтобы избежать перехода влево @
, и ;
сбрасывает этот ноль. Теперь мы входим в новый цикл:
"}
""
IP вводит это в левую нижнюю ячейку, двигаясь на север, обходя петлю по часовой стрелке. }
Сдвигает верхнюю часть основного стека к вспомогательной стеке. Пока в стеке все еще есть элемент, IP продолжает делать свое дело. Как только все было перемещено во вспомогательный стек (и полностью изменено в процессе), IP продолжает двигаться на восток, входя в последний цикл:
\{@
#!
\
снова печатает перевод строки, {
перемещает элемент из вспомогательного стека обратно в основной. Если это все еще был элемент списка, он будет положительным, и IP поворачивается на юг, где элемент печатается !
. Затем #
толкает глубину стека (и именно здесь _
важна начальная буква, потому что это #
обеспечивает положительную глубину стека), так что IP все еще поворачивается направо, через \
и {
снова.
После того, как мы распечатали все, {
вытянули ноль из нижней части вспомогательного стека, IP-адрес продолжился на восток и @
завершил программу.