Это было удивительно сложно, и я не уверен, что это оптимально ...
<.@!$?
После дополнения и развертывания кода это представляет следующую шестнадцатеричную сетку:
При этом используется тот же поток управления, что и в моей недавней безошибочной программе для кошек , движущейся по антидиагоналам. Чтобы добиться этого, мы начинаем с отклонения указателя инструкций (IP) влево, где фиолетовый путь оборачивается в нижний левый угол.
?
читает входные данные как целое число. !
печатает его обратно. .
это просто неоперация. Теперь угол сетки действует как ветвь:
Если вход был 0
, IP будет продолжаться по красной дорожке, которая просто завершает программу с @
.
Если вход был 1
, IP будет продолжаться по зеленому пути. Опять же, .
это просто запрет, но $
это эквивалент батута Бефунге: он пропускает следующую инструкцию. После переноса следующей инструкцией будет ?
, но из-за $
выполнения фактически продолжается синий путь, начиная с !
печати другой копии 1
. Этот цикл, который только содержит !..$
, теперь повторяется бесконечно.
Исследование потока управления в шестиугольнике ...
Я считаю, что вышеуказанное решение является оптимальным. Я написал брутфорсер, который проверяет все 6-байтовые программы Hexagony, которые содержат по крайней мере одну из них ?!@
(которые необходимы; я также проверил :
и %
вместо того, @
чтобы завершить с ошибкой деления на ноль, но это тоже не помогло). Проверка печатает все программы, которые a) выдают 0
на входе 0
и завершают, и b) выдают по крайней мере два 1
с (и ничего больше) и не завершаются в течение первых 60 тактов программы (200 тактов для 5-байтовых решений) , Я сомневаюсь, что любое правильное решение потребовало бы более 200 тиков, чтобы правильно напечатать первое 0
или второе 1
на такой маленькой сетке, поэтому я не думаю, что упустил какие-либо потенциальные решения.
Поиск не дал никаких результатов для 5 байтов, но 57 результатов для 6 байтов (используя @
; нет необходимости завершать с ошибкой, если мы можем решить это чисто в том же количестве байтов). Из этих 57 только 6 были ложными срабатываниями, которые фактически напечатали только два 1
с, а затем вошли в бесконечный цикл, не печатая больше. Одно решение было указано дважды, поскольку оно содержало две !
команды. Это оставляет ровно 50 действительных решений.
Существует определенная степень вырождения между решениями, в которых один или два символа несущественны, например потому, что они в любом случае фактически не работают. Решения могут быть сгруппированы в 23 набора действительно различных программ (в некоторых случаях разница между двумя наборами составляет всего один символ, но это существенно меняет поток управления, поэтому я их подсчитал отдельно). Две группы даже используют несколько указателей инструкций очень неожиданным образом. Поскольку я никогда не смог бы придумать большинство из этих способов использования ветвей и зеркал, они очень интересно изучают, какие виды управления потоками возможны в гексагонии, и я определенно изучил некоторые новые приемы для будущих гольфов.
Общий поток управления почти всегда одинаково: читать номер, распечатать его. Если это 0
найти путь к @
, если нет, продолжайте циклически проходить !
при сохранении значения ребра 1
. Есть четыре заметных исключения:
- Одно решение (одно с двумя
!
) печатает два 1
s за итерацию по сетке, поэтому печатает примерно в два раза быстрее, чем большинство программ. Я отметил это x2
ниже.
- Несколько решений (те , которые содержат
o
) заменить 1
с 111
(символьным кодом o
), поэтому они печатают три 1
с на итерацию, что делают их напечатать примерно в три раза быстрее, чем в большинстве программ. Я пометил их x3
ниже.
- Два решения добавляют a
1
к значению ребра в каждой итерации (так 1
-> 11
-> 111
-> ...). Они печатаются очень быстро, но со временем у них заканчивается память. Я пометил их OoM
ниже.
- Два решения входят в очень узкую петлю, которая просто подпрыгивает вперед и назад
!
, печатая на каждом другом тике (вместо каждого 5-го или около того), что делает их немного быстрее (и аккуратнее). Я пометил их ><
ниже.
Так вот и весь зоопарк:
#1 #5 #12 #19
?!/$.@ ?$!>$@ .?!/$@ |!|?$@ # ><
?!/$1@ # OoM ?$!|$@ =?!/$@
?!/$=@ #20
?!/$\@ #6 #13 $@.?<!
?!/$o@ # x3 ?/!<|@ .?/!$@ $@1?<! # OoM
?!/$!@ # x2 =?/!$@ $@=?<!
#7 $@o?<! # x3
#2 ?\!<|@ #14
?!>$)@ \!?__@ #21
?!>$1@ #8 _>_!?@
?!>$o@ # x3 ?<!>$@ # >< #15
?!|$)@ \_?!$@ #22
?!|$1@ #9 <!@.$?
?!|$o@ # x3 ?\$!@$ #16 <!@/$?
\_?!_@ <!@=$?
#3 #10 <$@!$?
?!|)$@ ?~#!@) #17 <.@!$?
?!|1$@ ?~#!@1 $$?\@! </@!$?
?!|o$@ # x3 <=@!$?
#11 #18
#4 ?$)\@! \$?\@! #23
?_!<@> ?$1\@! <<@]!?
?$o\@! # x3
Ниже приведен краткий обзор нескольких наиболее представительных групп. Особенно группы 10 и 23 стоит проверить. В других группах есть много других интересных и порой запутанных путей, но я думаю, что в конце этого вам достаточно скучно. Для тех, кто действительно хочет изучать гексагонию, их, безусловно, стоит исследовать, поскольку они демонстрируют еще более возможное использование зеркал и $
.
Группа 1
Это не намного сложнее, чем мое первоначальное решение, но пути идут в разных направлениях. Это также учитывает наибольшее количество вариантов в одной ячейке, так как самый правый неоперативный объект может быть заменен 5 различными командами, которые все еще делают это действительным без изменения структуры:
Группа 2
Этот довольно интересный, потому что он движется только горизонтально. После перехода к >
IP-адрес сразу же меняется на противоположный, принимая ветку в углу. Это не совсем хорошо видно на диаграмме, но в случае 1
мы снова пересекаем первый ряд, но на этот раз в обратном направлении. Это также означает, что мы сталкиваемся ?
снова, который теперь возвращает 0
(EOF). Это исправлено с )
(приращением), чтобы сохранить печать 1
s. Это также имеет 5 вариантов, которые )
также могут быть 1
или o
, и >
также могут быть |
:
Группа 3
Это выглядит почти идентично предыдущему, но чертовски грязно. До удара, |
а затем прохождения нижнего или верхнего ряда это то же самое. Но в случае цикла, $
теперь пропускается )
на зеркало. Таким образом, мы идем по бирюзовой дорожке направо, теперь нажимаем на приращение, пропускаем все @
до того, как |
снова обернемся, а затем возвращаемся к зеленой дорожке наверху.
Группа 4
Я думал, что это было особенно изящно:
_
Зеркало в верхнем правом углу не является изначально не-оп, поэтому мы печатаем с !
и ударил <
. Теперь 0
путь попадает в горизонтальное зеркало и заканчивается. 1
Путь занимает очень интересную траекторию , хотя: она отклоняется вниз, заворачивает к !
, перенаправляется в сторону по горизонтали , а затем заворачивает назад к !
снова . Затем он продолжает двигаться в форме ромба, печатая дважды за итерацию (каждый третий тик).
Группа 8
Это одно из двух решений с очень плотным циклом печати:
В <
выступает в качестве филиала. После оборачивания дважды, 0
удары @
. 1
с другой стороны, сначала пропускает ?
, затем снова >
отправляет его на $
, то есть пропускает @
. Затем IP оборачивается в бирюзовый путь, где он подпрыгивает назад и вперед между >
и <
(обтекание края между ними).
Группа 10
Одна из двух групп, которые используют другие указатели инструкций, и это абсолютно красиво. Гексагония имеет 6 - каждый начинается с другого угла по краю по часовой стрелке, но одновременно активен только один из них.
Как обычно, мы читаем с ?
. Теперь ~
унарное отрицание: оно превращается 1
в -1
. Далее мы попали #
. Это один из способов переключения между IP-адресами: он принимает текущее граничное значение по модулю 6 и переключается на соответствующий IP-адрес (IP-адреса нумеруются 0
по часовой стрелке). Так что, если вход был 0
, то IP просто остается прежним, и скучно идет прямо вперед !@
. Но если вход был 1
, то текущее значение, -1
которое есть 5 (mod 6)
. Поэтому мы переключаемся на IP, который начинается в той же ячейке (зеленый путь). Сейчас #
не работает и ?
устанавливает край памяти на 0
. )
увеличивает, так что !
печатает 1
. Теперь мы ~
снова ударили, чтобы убедиться, что#
до сих пор не работает (в отличие от переключения на IP 1, который завершит программу). Удивительно, насколько хорошо все сочетается в этой маленькой программе.
Группа 22
Просто отметим, что это группа, в которой находится мое первоначальное решение. Это также самая большая группа, потому что no-op может находиться в двух разных местах, и есть несколько вариантов для действительной (действующей no-op) команды.
Группа 23
Это другая группа, использующая несколько IP-адресов. На самом деле этот использует 3 разных IP. В верхнем правом углу немного беспорядка, но я постараюсь провести вас через это:
Итак, начало, которое вы видели раньше: <
отклоняет северо-восток, ?
читает ввод. Теперь ]
есть еще один способ переключения между IP-адресами: он передает управление следующему IP-адресу по часовой стрелке. Таким образом, мы переключаем управление на бирюзовый путь, который (я знаю, что это трудно увидеть) начинается в северо-восточном углу юго-востока. Это сразу же отражается <
тем, что оно охватывает юго-восточный угол, идущий на северо-запад. Это также ударил, ]
поэтому мы переключаемся на следующий IP. Это серая тропа, начинающаяся в восточном углу и идущая на юго-запад. Он печатает ввод, затем переносится в северо-восточный угол. <
отклоняет путь в горизонтальное положение, где он отражается другим <
. Теперь правая рука<
действует как ветвь: если вход был 0
, IP перемещается на северо-восток и переносится на @
. Если вход был 1
, IP перемещается в !
, оборачивается в левую и <
там, где он отражается ... теперь в углу, он оборачивается обратно в !
, отклоняется вправо <
, отражается слева <
и начинается путь над...
Довольно беспорядок, но красивый беспорядок. :)
Диаграммы, созданные с помощью удивительного HexagonyColorer Тимви .