2.}<@>%?<{>$"/\M!8;
Удобочитаемый:
2 . }
< @ > %
? < { > $
" / \ M
! 8 ;
Попробуйте онлайн!
Вероятно, это может быть игра в гольф одним или двумя байтами, но это может потребовать некоторой действительно изобретательной компоновки, которую можно было бы легче найти с помощью грубой силы (даже если это может занять довольно много времени).
Объяснение высокого уровня
Программа в основном следует этому псевдокоду:
while (read number is not zero)
{
if (number is even)
print number;
}
Который злоупотребляет тем, как Hexagony пытается прочитать число, когда STDIN пуст (возвращает ноль). Большое спасибо Мартину за помощь в разработке этого подхода.
Полное объяснение
Я до сих пор не возился с Моно, чтобы запустить фантастическую эзотерическую IDE Тимви , поэтому я опирался на Мартина, чтобы предоставить мне несколько полезных симпатичных картинок!
Сначала немного о базовом контроле потока в гексагоне. Первый указатель инструкций (IP), который является единственным используемым в этой программе, начинается в верхнем левом углу гексагонального исходного кода и начинает двигаться вправо. Всякий раз, когда ИП покидает край шестиугольника, он перемещается side_length - 1
рядами к середине шестиугольника. Поскольку эта программа использует шестиугольник с длиной стороны три, IP всегда будет перемещаться на две строки, когда это происходит. Единственное исключение - если он перемещается за пределы среднего ряда, где он условно перемещается к вершине или низу шестиугольника, в зависимости от значения текущего края памяти.
Теперь немного об условностях. Только в условном Hexagony для потока управления является >
, <
а средний край шестиугольника. Все они следуют постоянному правилу: если значение на текущем фронте памяти равно нулю или отрицательный поток управления перемещается влево, а если положителен, управление течет вправо. Квадратные скобки больше и меньше перенаправляют IP под углом шестьдесят градусов, в то время как край шестиугольника определяет, к какой строке переходит IP.
Гексагония также имеет специальную модель памяти, где все данные хранятся по краям бесконечной гексагональной сетки. Эта программа использует только три ребра: одно для хранения двух, одно для текущего читаемого числа и одно для числа по модулю два. Это выглядит примерно так:
Mod \ / Input
|
2
Я не собираюсь подробно объяснять, где мы находимся в памяти в каждой точке во время объяснения программы, поэтому возвращайтесь сюда, если вас смущает то, где мы находимся в памяти.
После всего этого фактическое объяснение может начаться. Сначала мы заполняем ребро «2» в памяти цифрой 2, затем выполняем no-op и перемещаем указатель памяти вправо ( 2.}
).
Далее мы начинаем основной цикл программы. Мы читаем первое число из STDIN, а затем нажимаем на условное выражение ( ?<
). Если в STDIN не осталось чисел, это читает ноль в текущем крае памяти, поэтому мы поворачиваем налево на то @
, что завершает программу. В противном случае мы отскакиваем от зеркала, перемещаем указатель памяти назад и влево, оборачиваем вокруг шестиугольника, чтобы вычислить остаток от деления ввода на 2, а затем нажимаем на другое условие ( /"%>
).
Если остаток равен единице (т. Е. Число было нечетным), мы поворачиваем направо, следуя синему пути выше, начиная с повторного выполнения no-op, затем переходим к нижней части шестиугольника, умножаем текущее ребро на 10 и затем добавляем восьмой, отскочив от пары зеркал, сделайте то же самое умножение и сложение снова, получив 188 на текущем ребре, вернувшись к вершине шестиугольника, снова выполнив no-op и, наконец, завершив программу ( .8/\8.@
). Этот запутанный результат был счастливой случайностью, я изначально написал гораздо более простую логику, но заметил, что могу убрать ее в пользу запрета, который, как мне показалось, больше соответствует духу гексагонии.
Если остаток был равен нулю, мы вместо этого поворачиваем налево, следуя красному пути выше. Это заставляет нас переместить указатель памяти влево, а затем распечатать значение (входное значение) в виде числа. Зеркало, с которым мы сталкиваемся, действует как no-op из-за направления, в котором мы движемся ( {/!
). Затем мы достигаем края шестиугольника, который действует условно только с одним результатом, так как входное значение, которое было до этого, уже было проверено на положительное значение, поэтому мы всегда движемся вправо (если вы представляете себя лицом в направлении IP) , Затем мы умножаем ввод на 10 и добавляем два, только чтобы изменить направление, обернуть вокруг и перезаписать новое значение на значение ascii заглавной буквы M, 77. Затем мы нажимаем на некоторые зеркала и выходим через край середины шестигранник с батутом (2<M\>$
). Так как 77 положительно, мы двигаемся вправо к нижней части шестиугольника и из-за батута пропускаем первую инструкцию ( !
). Затем мы умножаем текущий край памяти на 10 и добавляем 8, получая 778. Затем мы выводим это значение mod 256 (10) в виде символа ASCII, который оказывается символом новой строки. Наконец, мы выходим из шестиугольника и возвращаемся к первому, ?
который переопределяет 778 следующим входным значением.