Befunge, 444 368 323 octets
&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
! "#%$
%$"#!
!!##%
|||_
_ __
Essayez-le en ligne!
L'approche typique pour dessiner la courbe de Hilbert consiste à suivre le chemin sous la forme d'une série de traits et de virages, en rendant le résultat sous forme de bitmap ou d'une zone de mémoire, puis en écrivant ce rendu lorsque le chemin est terminé. Ce n'est tout simplement pas possible dans Befunge lorsque nous n'avons que 2000 octets de mémoire pour travailler, et cela inclut la source du programme lui-même.
Donc, l'approche que nous avons adoptée ici est de trouver une formule qui nous indique exactement quel caractère afficher pour une coordonnée x, y donnée. Pour comprendre comment cela fonctionne, il est plus facile d'ignorer le rendu ASCII pour commencer, et il suffit de penser de la courbe comme composée de caractères de la boîte: ┌
, ┐
, └
, ┘
, │
et ─
.
Lorsque nous regardons la courbe comme ça, nous pouvons immédiatement voir que le côté droit est un miroir exact du côté gauche. Les personnages à droite peuvent simplement être déterminés en regardant leur partenaire sur la gauche et en le réfléchissant horizontalement (c'est-à-dire les occurrences de ┌
et ┐
sont permutées, comme le sont └
et ┘
).
Ensuite, en regardant dans le coin inférieur gauche, encore une fois, nous pouvons voir que la moitié inférieure est un reflet de la moitié supérieure. Ainsi, les caractères en bas sont simplement déterminés en recherchant leur partenaire au-dessus et en le réfléchissant verticalement (c'est-à-dire les occurrences de ┌
et └
sont permutées, comme le sont ┐
et ┘
).
La moitié restante de ce coin est un peu moins évidente. Le bloc de droite peut être dérivé d'une réflexion verticale du bloc diagonalement adjacent à lui.
Et le bloc de gauche peut être dérivé d'une réflexion verticale du bloc tout en haut à gauche de la courbe complète.
À ce stade, tout ce qui nous reste est le coin supérieur gauche, qui est juste une autre itération de Hilbert Curve inférieure. En théorie, nous devrions maintenant simplement devoir répéter le processus à nouveau, mais il y a un petit problème - à ce niveau, les moitiés gauche et droite du bloc ne sont pas des miroirs exacts l'une de l'autre.
Donc, à tout autre chose qu'au niveau supérieur, les caractères du coin inférieur doivent être traités comme un cas spécial, où le ┌
caractère est reflété comme ─
, et le │
caractère est reflété comme └
.
Mais à part cela, nous pouvons vraiment répéter ce processus récursivement. Au dernier niveau, nous codons en dur le caractère en haut à gauche comme ┌
, et le caractère en dessous comme │
.
Maintenant que nous avons un moyen de déterminer la forme de la courbe à une coordonnée x, y particulière, comment traduire cela en rendu ASCII? Il s'agit en fait d'un simple mappage qui traduit chaque tuile possible en deux caractères ASCII.
┌
devient _
(espace plus souligné)
┐
devient
(deux espaces)
└
devient |_
(barre verticale plus souligné)
┘
devient |
(barre verticale plus espace)
│
devient |
(encore une barre verticale plus un espace)
─
devient __
(deux traits de soulignement)
Ce mappage n'est pas intuitif au début, mais vous pouvez voir comment cela fonctionne en regardant deux rendus correspondants côte à côte.
Et c'est essentiellement tout ce qu'il y a à faire. En fait, l'implémentation de cet algorithme dans Befunge est un autre problème, mais je vais laisser cette explication pour une autre fois.