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