Вы говорите, шесть разных видов фруктовых петель? Вот для чего была создана Гексагония.
){r''o{{y\p''b{{g''<.{</"&~"&~"&<_.>/{.\.....~..&.>}<.._...=.>\<=..}.|>'%<}|\.._\..>....\.}.><.|\{{*<.>,<.>/.\}/.>...\'/../==.|....|./".<_>){{<\....._>\'=.|.....>{>)<._\....<..\..=.._/}\~><.|.....>e''\.<.}\{{\|./<../e;*\.@=_.~><.>{}<><;.(~.__..>\._..>'"n{{<>{<...="<.>../
Ладно не было О боже, что я сделал для себя ...
Этот код теперь является шестиугольником с длиной стороны 10 (он начался в 19). Вероятно, это может быть еще немного, возможно, даже до размера 9, но я думаю, что моя работа здесь выполнена ... Для справки, в источнике 175 действующих команд, многие из которых являются потенциально ненужными зеркалами (или были добавлены для отмены). команда с пути пересечения).
Несмотря на кажущуюся линейность, код на самом деле двумерный: Hexagony преобразует его в правильный шестиугольник (который также является допустимым кодом, но все пробелы в Hexagony являются необязательными). Вот развернутый код во всем его ... ну, я не хочу сказать "красота":
) { r ' ' o { { y \
p ' ' b { { g ' ' < .
{ < / " & ~ " & ~ " & <
_ . > / { . \ . . . . . ~
. . & . > } < . . _ . . . =
. > \ < = . . } . | > ' % < }
| \ . . _ \ . . > . . . . \ . }
. > < . | \ { { * < . > , < . > /
. \ } / . > . . . \ ' / . . / = = .
| . . . . | . / " . < _ > ) { { < \ .
. . . . _ > \ ' = . | . . . . . > {
> ) < . _ \ . . . . < . . \ . . =
. . _ / } \ ~ > < . | . . . . .
> e ' ' \ . < . } \ { { \ | .
/ < . . / e ; * \ . @ = _ .
~ > < . > { } < > < ; . (
~ . _ _ . . > \ . _ . .
> ' " n { { < > { < .
. . = " < . > . . /
объяснение
Я даже не буду пытаться объяснить все запутанные пути выполнения в этой версии игры в гольф, но алгоритм и общий поток управления идентичны этой версии без правил, которую, возможно, будет легче изучить для действительно любопытных после того, как я объясню алгоритм:
) { r ' ' o { { \ / ' ' p { . . .
. . . . . . . . y . b . . . . . . .
. . . . . . . . ' . . { . . . . . . .
. . . . . . . . \ ' g { / . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . > . . . . < . . . . . . . . .
. . . . . . . . . . . . . . > . . ) < . . . . .
. . . . . . . . . . / = { { < . . . . ( . . . . .
. . . . . . . . . . . ; . . . > . . . . . . . . . <
. . . . . . . . . . . . > < . / e ; * \ . . . . . . .
. . . . . . . . . . . . @ . } . > { } < . . | . . . . .
. . . . . / } \ . . . . . . . > < . . . > { < . . . . . .
. . . . . . > < . . . . . . . . . . . . . . . | . . . . . .
. . . . . . . . _ . . > . . \ \ " ' / . . . . . . . . . . . .
. . . . . . \ { { \ . . . > < . . > . . . . \ . . . . . . . . .
. < . . . . . . . * . . . { . > { } n = { { < . . . / { . \ . . |
. > { { ) < . . ' . . . { . \ ' < . . . . . _ . . . > } < . . .
| . . . . > , < . . . e . . . . . . . . . . . . . = . . } . .
. . . . . . . > ' % < . . . . . . . . . . . . . & . . . | .
. . . . _ . . } . . > } } = ~ & " ~ & " ~ & " < . . . . .
. . . \ . . < . . . . . . . . . . . . . . . . } . . . .
. \ . . . . . . . . . . . . . . . . . . . . . . . < .
. . . . | . . . . . . . . . . . . . . . . . . = . .
. . . . . . \ . . . . . . . . . . . . . . . . / .
. . . . . . > . . . . . . . . . . . . . . . . <
. . . . . . . . . . . . . . . . . . . . . . .
_ . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
Честно говоря, в первом абзаце я шутил только наполовину. Тот факт, что мы имеем дело с циклом из шести элементов, на самом деле очень помог. Модель памяти Hexagony представляет собой бесконечную гексагональную сетку, где каждое ребро сетки содержит целое число произвольной точности со знаком, инициализированное в ноль.
Вот схема расположения памяти, которую я использовал в этой программе:
Длинный прямой бит слева используется как строка a
с нулем в конце произвольного размера, связанная с буквой r . Пунктирные линии на других буквах представляют собой структуру такого же типа, каждая из которых повернута на 60 градусов. Первоначально указатель памяти указывает на край, обозначенный 1 , обращенный на север.
Первый линейный бит кода устанавливает внутреннюю «звезду» ребер в буквы, roygbp
а также устанавливает начальное ребро так 1
, чтобы мы знали, где цикл заканчивается / начинается (между p
и r
):
){r''o{{y''g{{b''p{
После этого мы снова на краю с надписью 1 .
Теперь общая идея алгоритма такова:
- Для каждой буквы в цикле продолжайте читать буквы из STDIN и, если они отличаются от текущей буквы, добавьте их в строку, связанную с этой буквой.
- Когда мы читаем письмо, которое в настоящее время ищем, мы сохраняем
e
на краю надпись с надписью ? , потому что пока цикл не завершен, мы должны предположить, что нам придется съесть и этого персонажа. После этого мы переместимся по кольцу к следующему персонажу в цикле.
- Есть два способа, которыми этот процесс может быть прерван:
- Либо мы завершили цикл. В этом случае мы делаем еще один быстрый цикл по циклу, заменяя все те, что
e
в ? граничит с n
s, потому что теперь мы хотим, чтобы этот цикл оставался на цепочке. Затем мы переходим к печати кода.
- Или мы нажимаем EOF (который мы распознаем как отрицательный символьный код). В этом случае мы записываем отрицательное значение в ? край текущего символа (чтобы мы могли легко отличить его от обоих
e
и n
). Затем мы ищем 1 ребро (чтобы пропустить остаток потенциально неполного цикла), а затем перейдем к печати кода.
- Код печати снова проходит цикл: для каждого символа в цикле он очищает сохраненную строку при печати
e
для каждого символа. Тогда он движется к ? край, связанный с персонажем. Если оно отрицательное, мы просто завершаем программу. Если оно положительное, мы просто печатаем его и переходим к следующему символу. Как только мы завершим цикл, мы вернемся к шагу 2.
Еще одна вещь, которая может быть интересной, - это то, как я реализовал строки произвольного размера (потому что я впервые использую неограниченную память в Hexagony).
Представьте себе , что мы в каком - то момент , когда мы по- прежнему читаем символы для г (так что мы можем использовать схему как есть) и а [0] и 1 уже заполнены с персонажами (все северо-запад от них по - прежнему равен нулю ). Например, возможно, мы только что прочитали первые два символа ввода в эти края и теперь читаем a .og
y
Новый персонаж читается в краю. Мы используем ? край, чтобы проверить, равен ли этот символ r
. (Здесь есть хитрый трюк: гексагония может легко различать только положительное и не положительное, поэтому проверка на равенство с помощью вычитания раздражает и требует как минимум двух ветвей. Но все буквы меньше, чем в 2 раза, поэтому мы можем сравнить значения, взяв по модулю, который даст только ноль, если они равны.)
Поскольку y
отличается от r
, мы перемещаем (немаркированный) край слева в и копируем y
туда. Теперь мы перемещаемся дальше по шестиугольнику, каждый раз копируя символ на одно ребро дальше, пока у нас не появится y
край напротив in . Но теперь в [0] уже есть символ, который мы не хотим перезаписывать. Вместо этого мы «таскать» y
вокруг следующего шестиугольника и проверить с 1 . Но там тоже есть персонаж, поэтому мы идем дальше с шестигранником. Теперь [2] по-прежнему равен нулю, поэтому мы копируемy
внутрь. Указатель памяти теперь перемещается назад вдоль строки к внутреннему кольцу. Мы знаем, когда достигли начала строки, потому что (немаркированные) ребра между a [i] равны нулю, тогда как ? положительно.
Это, вероятно, будет полезной техникой для написания нетривиального кода в Hexagony в целом.