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 - это еще одна проблема, но я оставлю это объяснение в другой раз.