Це було напрочуд хитро, і я не переконаний, що це оптимально ...
<.@!$?
Після прокладки та розгортання коду це являє собою наступну шістнадцяткову сітку:
Для цього використовується аналогічний потік керування, як у моєї недавньої програми без кішок , що рухається по діагоналях. Для цього ми починаємо, відхиливши вказівник інструкції (IP) зліва, де фіолетова доріжка обертається до лівого нижнього кута.
?
читає вхід як ціле число. !
друкує його назад. .
це просто неоперація. Тепер кут сітки виступає як гілка:
Якщо вхід був 0
, IP буде продовжуватися по червоному шляху, який просто припиняє програму @
.
Якщо вхід був 1
, IP буде продовжуватися зеленим шляхом. Знову ж таки, .
це просто $
бездіяльність , але це еквівалент батуту Бефунге: він пропускає наступну інструкцію. Після завершення обговорення наступною інструкцією буде те ?
, але завдяки $
виконанню насправді продовжується синім шляхом, починаючи з !
друку іншої копії 1
. Цей цикл, який містить лише !..$
зараз, повторюється нескінченно.
Дослідження контрольного потоку в Гексагоні ...
Я вважаю, що вищезазначене рішення є оптимальним. Я написав грубої форсер, який перевіряє всі 6-байтні програми шестикутників, які містять принаймні по одній з них ?!@
(які необхідні; я також перевірив :
і %
замість цього @
завершити з помилкою поділу на нуль, але це теж не допомогло). Чек роздруковує всі програми, які: а) виробляють 0
вхід 0
і завершують; б) виробляють принаймні дві 1
секунди (і нічого іншого) і не припиняються протягом перших 60 тиків програми (200 тиків для 5-байтних рішень) . Я сумніваюся, що будь-яке дійсне рішення потребує більше 200 тиків, щоб правильно надрукувати перше 0
чи друге 1
на такій невеликій сітці, тому я не думаю, що я пропустив жодне потенційне рішення.
Пошук не дав жодних результатів для 5 байт, але 57 результатів для 6 байт (використовуючи @
; немає необхідності припиняти помилку, якщо ми можемо вирішити це чисто в тій же кількості байтів). З цих 57 лише 6 були помилковими, які насправді надрукували лише два 1
s, а потім увійшли до нескінченного циклу, не друкуючи більше. Одне рішення було перераховано двічі, оскільки воно містило дві !
команди. Це залишає рівно 50 дійсних рішень.
Існує певна кількість виродженості між рішеннями, коли один або два символи не є істотними, наприклад, тому що вони фактично не спрацьовують. Рішення можна згрупувати в 23 набори справді відмінних програм (в деяких випадках існує лише одна різниця символів між двома наборами, але це суттєво змінює потік управління, тому я їх порахував окремо). Дві групи навіть користуються декількома вказівниками вкрай несподівано. Оскільки я б ніколи не придумав більшість цих способів використання гілок і дзеркал, вони роблять дуже цікаве вивчення можливих видів контрольного потоку в Гексагоні, і я, безумовно, навчився деяких нових хитрощів для майбутніх гольфів.
Загальний потік управління майже завжди однаково: читати номер, роздрукувати його. Якщо він 0
знайде спосіб до @
, якщо не продовжувати циклічно !
, зберігаючи значення краю 1
. Є чотири помітні винятки:
- Одне рішення (одне з двома
!
) друкує два 1
с за ітерацію через сітку, тому друкується приблизно вдвічі швидше, ніж більшість програм. Я це позначив 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
на a -1
. Далі ми натискаємо на #
. Це один із способів перемикання між IP-адресами: він приймає поточне значення по модулю 6 і переходить на відповідний IP (IP-адреси нумеруються 0
за годинниковою стрілкою). Отже, якщо вхід був 0
, то IP просто залишається тим самим і їде нудно прямо вперед !@
. Але якщо вхід був 1
, то поточне значення таке, -1
яке є 5 (mod 6)
. Таким чином, ми переходимо до IP, який починається з тієї самої комірки (зелений шлях). Тепер #
не працює і ?
встановлює межу пам'яті 0
. )
з кроком, так що !
друкується a 1
. Тепер ми ~
знову вдаримося, щоб забезпечити це#
все ще не працює (на відміну від переходу на IP 1, що припинить програму). Це розумне те, наскільки добре все вписується в цю маленьку програму.
22 група
Зауважимо лише, що це група, в якій знаходиться моє оригінальне рішення. Також трапляється найбільша група, тому що неоперативний режим може знаходитися в двох різних місцях, і є кілька варіантів для фактичної (ефективної безвідмовної) команди.
23 група
Це інша група, що використовує кілька IP-адрес. Насправді для цього використовується 3 різних IP-адреси. Правий верхній кут трохи безлад, але я спробую провести вас через це:
Отже, початок, який ви бачили раніше: <
відхиляє Північний-Схід, ?
читає введення. Тепер ]
є ще один спосіб змінити між IP-адресами: він передає контроль на наступний IP в порядку годинникової стрілки. Тож ми переключаємо управління на бірюзовий шлях, який (я знаю, що це важко побачити) починається в північно-східному куті, що йде на південний схід. Це відразу відбивається <
так, що він завертається до південно-східного кута, йдучи на північний захід. Він також потрапляє, ]
тому ми переходимо до наступного IP. Це сіра стежка, що починається в східному куті, йде південніше. Він друкує вхід, а потім переносить на північно-східний кут. <
відхиляє шлях у горизонталь, де він відбивається іншим <
. Тепер права<
виконує функцію гілки: якщо вхід був 0
, IP переміщується на північний схід і переходить на @
. Якщо вхід був 1
, IP переміщується до !
, перегортається на ліворуч, <
де воно відображається ... тепер у кутку він повертається назад до !
, відхиляється праворуч <
, відбивається ліворуч, <
і шлях починається понад ...
Досить безлад, але гарний безлад. :)
Діаграми, створені за допомогою дивовижного HexagonyColorer Тімві .