Befunge, 444 368 323 byte
&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
! "#%$
%$"#!
!!##%
|||_
_ __
Cobalah online!
Pendekatan khas untuk menggambar Kurva Hilbert adalah mengikuti jalur sebagai serangkaian goresan dan belokan, merender hasilnya menjadi bitmap atau area memori tertentu, dan kemudian menuliskan rendering itu ketika path selesai. Ini tidak layak di Befunge ketika kita hanya memiliki 2000 byte memori untuk bekerja, dan itu termasuk sumber program itu sendiri.
Jadi pendekatan yang kami ambil di sini adalah menghasilkan formula yang memberi tahu kami karakter mana yang akan dihasilkan untuk koordinat x, y. Untuk memahami cara kerja ini, itu paling mudah untuk mengabaikan render ASCII untuk memulai dengan, dan hanya berpikir kurva sebagai terdiri dari karakter kotak: ┌
, ┐
, └
, ┘
, │
, dan ─
.
Ketika kita melihat kurva seperti itu, kita dapat segera melihat bahwa tangan kanan adalah cermin yang tepat dari tangan kiri. Karakter di sebelah kanan dapat dengan mudah ditentukan dengan melihat pasangan mereka di sebelah kiri, dan memantulkannya secara horizontal (yaitu kejadian ┌
dan ┐
ditukar, sebagaimana adanya └
dan ┘
).
Kemudian melihat sudut kiri bawah, lagi-lagi kita dapat melihat bahwa bagian bawah adalah refleksi dari bagian atas. Jadi karakter di bagian bawah hanya ditentukan dengan melihat pasangan mereka di atas, dan memantulkannya secara vertikal (yaitu kejadian ┌
dan └
ditukar, sebagaimana adanya ┐
dan ┘
).
Setengah dari sudut ini sedikit kurang jelas. Blok tangan kanan dapat diturunkan dari refleksi vertikal blok yang secara diagonal bersebelahan dengannya.
Dan blok tangan kiri dapat berasal dari refleksi vertikal dari blok di paling kiri atas kurva penuh.
Pada titik ini, yang tersisa adalah sudut kiri atas, yang merupakan salah satu Hilve Curve yang satu lagi lebih rendah. Secara teori, kita seharusnya sekarang hanya perlu mengulangi prosesnya lagi, tetapi ada sedikit tangkapan - pada tingkat ini, bagian kiri dan kanan dari blok itu bukan cermin yang tepat satu sama lain.
Jadi pada apa pun selain tingkat atas, karakter sudut bawah perlu ditangani sebagai kasus khusus, di mana ┌
karakter tersebut tercermin ─
, dan │
karakter tersebut tercermin sebagai └
.
Tapi selain itu, kita benar-benar bisa mengulangi proses ini secara rekursif. Pada tingkat terakhir, kami membuat hardcode karakter kiri atas ┌
, dan karakter di bawahnya sebagai │
.
Sekarang kita memiliki cara untuk menentukan bentuk kurva pada koordinat x, y, bagaimana kita menerjemahkannya ke rendering ASCII? Ini sebenarnya hanya pemetaan sederhana yang menerjemahkan setiap ubin yang mungkin menjadi dua karakter ASCII.
┌
menjadi _
(spasi plus garis bawah)
┐
menjadi
(dua spasi)
└
menjadi |_
(bilah vertikal plus garis bawah)
┘
menjadi |
(bilah vertikal plus spasi)
│
menjadi |
(lagi-lagi bilah vertikal plus ruang)
─
menjadi __
(dua garis bawah)
Pemetaan ini tidak intuitif pada awalnya, tetapi Anda dapat melihat cara kerjanya saat melihat dua rendering yang sesuai berdampingan.
Dan pada dasarnya itu semua ada untuk itu. Sebenarnya mengimplementasikan algoritme ini di Befunge adalah masalah lain, tetapi saya akan meninggalkan penjelasan itu untuk lain waktu.