Befunge, 444 368 323 байт
&1>\1-:v
0v^*2\<_$00p>
_>:10p\:20pv^_@#-*2g00:+1,+55$
^!-<v*2g000<>$#<0>>-\:v
g2*^>>10g20g+v \ ^*84g_$:88+g,89+g,\1+:00
v#*!-1g02!g01_4^2_
>::00g2*-!\1-:10g-\20g-++>v
87+#^\#p01#<<v!`g01/2\+76:_
vv1-^#1-g01:\_$:2/20g`!
_ 2/^>:10g#vv#`g02/4*3:\+77
v>0p^^/2:/2_
<^2-1-g02</2`#*3:
0g+10p2*:^*3_1
! "#%$
%$"#!
!!##%
|||_
_ __
Спробуйте в Інтернеті!
Типовий підхід до малювання кривої Гільберта полягає в тому, щоб слідувати по шляху, як серія штрихів і поворотів, перетворюючи результат у растрову карту чи якусь область пам’яті, а потім виписувати цю візуалізацію, коли шлях закінчений. Це просто неможливо в Befunge, коли у нас є лише 2000 байт пам'яті для роботи, і це включає джерело самої програми.
Отже, підхід, який ми тут застосували, - це придумати формулу, яка точно підказує, який символ виводити для заданої координати x, y. Щоб зрозуміти , як це працює, це найпростіше ігнорувати ASCII рендеринга , щоб почати с, і просто думати про криву , як з коробки символів: ┌
, ┐
, └
, ┘
, │
, і ─
.
Коли ми дивимось на криву таким чином, ми можемо відразу побачити, що права рука - це точне дзеркало лівої сторони. Символів праворуч можна просто визначити, дивлячись на свого партнера зліва та відображаючи його по горизонталі (тобто події ┌
та ┐
міняються місцями, як є └
і ┘
).
Потім, дивлячись на нижній лівий кут, ми знову бачимо, що нижня половина - це відображення верхньої половини. Таким чином, символи на дні просто визначається шляхом пошуку свого партнера вище, і відображає його вертикально (тобто входжень ┌
і └
міняються місцями, так само як ┐
і ┘
).
Решта половини цього кута трохи менш очевидна. Правий блок може бути отриманий від вертикального відображення блоку, діагонально прилеглого до нього.
А лівий блок можна отримати від вертикального відображення блоку в самому верхньому лівому куті від повної кривої.
У цій точці все, що нам залишилося, - це верхній лівий кут, який є лише іншою ітерацією Гільберта на одну ітерацію нижче. Теоретично нам слід просто повторити процес ще раз, але тут є трохи прикуту - на цьому рівні ліва і права половини блоку не є точними дзеркалами один одного.
Тож на будь-якому, окрім верхнього рівня, символи нижнього кута потрібно обробляти як особливий випадок, де ┌
персонаж відображається як ─
, а │
персонаж відображається як └
.
Але крім цього, ми дійсно можемо просто повторювати цей процес рекурсивно. На останньому рівні ми жорстко кодуємо верхній лівий символ як ┌
, а символ під ним як │
.
Тепер, коли у нас є спосіб визначити форму кривої на певній координаті x, y, як ми переведемо це на візуалізацію ASCII? Насправді це просто просте відображення, що переводить кожну можливу плитку на два символи ASCII.
┌
стає _
(пробіл плюс підкреслення)
┐
стає
(два пробіли)
└
стає |_
(вертикальна смуга плюс підкреслення)
┘
стає |
(вертикальна смуга плюс пробіл)
│
стає |
(знову вертикальна смуга плюс пробіл)
─
стає __
(дві підкреслення)
Це відображення спочатку не інтуїтивно зрозуміло, але ви можете побачити, як воно працює, переглядаючи два відповідні візуалізації поряд.
І це в основному все, що там є. Насправді реалізація цього алгоритму в Befunge - це зовсім інша проблема, але я поясню це пояснення для іншого часу.