ASCII Hilbert Curve

23

Étant donné une nsortie entière, la nième itération de la courbe de Hilbert en ASCII en utilisant les caractères _et |.

Voici les 4 premières itérations:

n=1
 _ 
| |

n=2
 _   _ 
| |_| |
|_   _|
 _| |_

n=3
 _   _   _   _ 
| |_| | | |_| |
|_   _| |_   _|
 _| |_____| |_ 
|  ___   ___  |
|_|  _| |_  |_|
 _  |_   _|  _ 
| |___| |___| |

n=4
 _   _   _   _   _   _   _   _ 
| |_| | | |_| | | |_| | | |_| |
|_   _| |_   _| |_   _| |_   _|
 _| |_____| |_   _| |_____| |_ 
|  ___   ___  | |  ___   ___  |
|_|  _| |_  |_| |_|  _| |_  |_|
 _  |_   _|  _   _  |_   _|  _ 
| |___| |___| |_| |___| |___| |
|_   ___   ___   ___   ___   _|
 _| |_  |_|  _| |_  |_|  _| |_ 
|  _  |  _  |_   _|  _  |  _  |
|_| |_| | |___| |___| | |_| |_|
 _   _  |  ___   ___  |  _   _ 
| |_| | |_|  _| |_  |_| | |_| |
|_   _|  _  |_   _|  _  |_   _|
 _| |___| |___| |___| |___| |_ 

Clarifications

  • Ma question est similaire à Dessiner la courbe de Hilbert et Dessiner la courbe de Hilbert à l'aide de barres obliques .
  • La conversion entre les traits de soulignement ( _) et les barres verticales ( |) est u=2*v-1uest le nombre de _s et vle nombre de |s.
  • Pour maintenir la cohérence avec mon message d'origine, la courbe doit commencer et se terminer en bas.
  • Vous pouvez avoir un programme complet ou une fonction.
  • Sortie vers stdout (ou quelque chose de similaire).
  • Vous pouvez avoir des espaces blancs de début ou de fin, la sortie n'a qu'à s'aligner pour ressembler aux exemples.
  • C'est le code-golf, donc la réponse la plus courte en octets gagne.
Bobas_Pett
la source
3
Pourriez-vous s'il vous plaît inclure une définition de la courbe de Hilbert dans votre message, et les spécifications exactes de la façon dont la version ASCII est construite?
Loovjo
@Bobas_Pett: Pas kolmogorov-complexité
shooqie
@shooqie il y a un débat à ce sujet sur meta
trichoplax
@Loovjo J'ai ajouté un point sur les longueurs des traits de soulignement (_) et des barres verticales (|) sous "Clarifications", si plus d'informations ou une définition rigoureuse sont encore nécessaires, dites-le moi.
Bobas_Pett
@shooqie j'ai supprimé la balise
Bobas_Pett

Réponses:

5

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 ).

Courbe de Hilbert de niveau 3 montrant la réflexion sur l'axe vertical

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 ).

Courbe de Hilbert de niveau 3 montrant la réflexion sur l'axe horizontal dans le coin inférieur gauche

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.

Courbe de Hilbert de niveau 3 montrant comment le bloc supérieur droit du coin inférieur gauche peut être dérivé

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.

Courbe de Hilbert de niveau 3 montrant comment le bloc supérieur gauche du coin inférieur gauche peut être dérivé

À 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 .

Courbe de Hilbert de niveau 3 montrant comment le bloc supérieur gauche du coin inférieur gauche peut être dérivé

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 .

Séquence d'images montrant comment les parties restantes de la courbe sont dérivées

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.

Courbe de Hilbert de niveau 2 rendue en art ASCII et avec des caractères de boî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.

James Holderness
la source
2

C, 267 octets

const n=4,s=1<<n,a[]={1,-s,-1,s};l,p,q;
t(d){d&=3;p-q||printf("%.2s",&"__|      _|       |___ _|_| | | "[l*8+d*2]);p+=a[l=d];}
h(d,r,n){n--&&(h(d+r,-r,n),t(d+r),h(d,r,n),t(d),h(d,r,n),t(d-r),h(d-r,-r,n));}
main(){for(;p=s*s-s,l=1,q<s*s;++q%s||putchar(10))h(0,1,n),t(3);}

Essayez-le en ligne!

h()utilise la récursivité pour générer les traits de la courbe hlibert. t()imprime uniquement le caractère de trait si la position du crayon pest égale à la position de sortie actuelle q.

C'est inefficace mais simple.

Si la courbe commence en haut à gauche, le code peut être réduit à 256 octets.

Milo Yip
la source
Suggérer puts("")au lieu de putchar(10)et "..."+l*8+d*2au lieu de &"..."[l*8+d*2]et n--?h(d+r...-r,n):0au lieu den--&&(h(d+r...-r,n))
plafondcat