Narysuj krzywą Hilberta

12

Krzywa Hilberta jest rodzajem krzywej wypełniającej przestrzeń i zasadniczo odwzorowuje linię na płaszczyznę. Każdy punkt na linii odpowiada tylko jednemu punktowi na płaszczyźnie, a każdy punkt na płaszczyźnie odpowiada tylko jednemu punktowi na linii. Pokazano iteracje od 0 do 4 krzywej Hilberta:

Iteracje 0 do 4:

Cel tego zadania: Napisz kod, który rysuje czwartą iterację krzywej Hilberta, jak zdefiniowano powyżej. Twój kod powinien być kompletny - innymi słowy, jeśli utworzysz funkcję do rysowania krzywej Hilberta, twój kod musi wywołać tę funkcję. Dane wyjściowe można wyświetlić bezpośrednio na ekranie lub zapisać je w pliku obrazu. Krzywa może być obracana lub odwracana, ale linie muszą przecinać się pod kątem prostym, a wynik nie może być rozciągnięty. Sztuka ASCII jest doceniana, ale nie będzie akceptowana. Najkrótszy kod w bajtach wygrywa!

J. Antonio Perez
źródło
Czy liczba razy to wejście? Czy możemy wybrać dowolną wartość co najmniej 4?
Luis Mendo,
Czy sztukę ASCII uważa się za graficzną?
Gabriel Benamy,
Nie; przepraszam - to byłby duplikat innego pytania
J. Antonio Perez,
@JorgePerez Czy krzywa może mieć inną orientację? Jak twoja wersja przykładów z odwróconą pionowo lub o 90 stopni rotacją
Luis Mendo
Tak! Chociaż ogólny kształt musi być nadal kwadratowy
J. Antonio Perez,

Odpowiedzi:

7

R, 90 bajtów

n=scan();a=1+1i;b=1-1i;z=0;for(k in 1:n)z=c((w<-1i*Conj(z))-a,z-b,z+a,b-w)/2;plot(z,t="s")

Bezwstydny port R algorytmu zastosowanego w łączu opublikowanym przez @Luis Mendo.

Dla n=5otrzymujemy:

wprowadź opis zdjęcia tutaj

Billywob
źródło
7

MATL , 39 38 bajtów

O5:"tZjJ*JQ-wJq+t2+&y2j+_v2/]XG25Y01ZG

Pobiera to liczbę iteracji jako dane wejściowe. Jeśli chcesz go na stałe zakodować, zastąp igo numerem.

Program jest portem kodu Matlaba autorstwa Jonasa Lundgrena pokazanego tutaj .

Wynik pokazano poniżej. Możesz także spróbować w MATL Online! Wytworzenie wyjścia zajmuje kilka sekund. Ten kompilator jest eksperymentalny; może być konieczne odświeżenie strony i ponowne naciśnięcie przycisku „Uruchom”, jeśli początkowo nie działa.

wprowadź opis zdjęcia tutaj

Wyjaśnienie

O          % Push 0. This is the initial value of "z" in the original code
5:"        % Do 5 times
  t        %   Duplicate
  Zj       %   Complex conjugate
  J*       %   Multiply by 1j (imaginary unit). This is "w" in the original code
  JQ-      %   Subtract 1+1j
  w        %   Swap: brings copy of "z" to top
  Jq+      %   Add 1-1j
  t        %   Duplicate
  2+       %   Add 2
  &y       %   Duplicate the third element from top
  2j+_     %   Add 2j and negate
  v        %   Concatenate the three matrices vertically
  2/       %   Divide by 2
]          % End
XG         % Plot (in complex plane). The numbers are joined by straight lines
25Y0       % Push string 'square'
1ZG        % Make axis square
Luis Mendo
źródło
Czy możesz wyjaśnić, jak działa Twój kod?
J. Antonio Perez,
Algorytm jest dokładnie taki, jak w łączu. Ale dodam wyjaśnienie
Luis Mendo
@Jorge Explanation dodaje
Luis Mendo
omg, ten, na którym
opierasz swój,
@flawr Wszystkie podziękowania dla Jonasa Lundgrena :-)
Luis Mendo
6

MATLAB, 264 262 161 bajtów

Działa to nadal bardzo podobnie, z tym wyjątkiem, że w zasadzie obliczamy „pochodną” krzywej Hilberta, którą następnie „integrujemy” poprzez „sumę”. Zmniejsza to rozmiar kodu o całkiem sporo bajtów.

function c;plot(cumsum([0,h(1,1+i,4)]));axis equal;end function v=h(f,d,l);v=d*[i*f,1,-i*f];if l;l=l-1;D=i*d*f;w=h(f,d,l);x=h(-f,D,l);v=[x,D,w,d,w,-D,-x];end;end

Stara wersja

To tylko proste podejście rekurencyjne. Dla uproszczenia użyłem liczb zespolonych do przechowywania informacji wektorowych. Możesz zmienić krzywą na części h(0,1,1+i,4). Pierwszy argument p=0to pozycja początkowa, drugi argument fto flaga orientacji ( +1lub -1), trzeci argument dto kierunek / obrót, w którym należy narysować krzywą, a czwarty lto głębokość rekurencji.

function c;hold on;h(0,1,1+i,4);axis equal;end function p=h(p,f,d,l);q=@plot;if l;l=l-1;d=i*d*f;p=h(p,-f,d,l);q(p+[0,d]);p=p+d;d=-i*d*f;p=h(p,f,d,l);q(p+[0,d]);p=p+d;p=h(p,f,d,l);d=-i*d*f;q(p+[0,d]);p=p+d;p=h(p,-f,d,l);else;q(p + d*[0,i*f,1+i*f,1]);p=p+d;end;end

Tak to wygląda w starszych wersjach:

Tak to wygląda w 2015b:

->
wada
źródło
1
W Matlabie R2015b drukuje się w kolorach <3
Luis Mendo
Haha, tak fajnie :)
flawr
@LuisMendo Miałem teraz możliwość gry w golfa dzięki cumsumpomysłowi, który jest po prostu genialny!
flawr
3

MATLAB / Octave, 202 bajty

Zauważyłem, że wersja @LuisMendo, która jest połączona, była znacznie krótsza niż poprzednie „ręcznie robione” rozwiązanie, ale używa zupełnie innego podejścia. Zamieszczam tutaj wersję golfa jako CW:

Ta wersja jest oparta na podejściu systemowym Lindenmayer:

A=zeros(0,2);B=A;C=A;D=A;n=[0,1];e=[1,0];for k=1:4;a=[B;n;A;e;A;-n;C];b=[A;e;B;n;B;-e;D];c=[D;-e;C;-n;C;e;A];D=[C;-n;D;-e;D;n;B];A=a;B=b;C=c;end;A=[0,0;cumsum(A)];plot(A(:,1),A(:,2));axis off;axis equal

wprowadź opis zdjęcia tutaj

wad
źródło
3

JavaScript (ES6), 266 ... 233 232 bajty

Renderowanie SVG krzywej Hilberta.

document.write('<svg><path fill=none stroke=red d="M8 8'+(f=(i,s='2',d=x=y=8)=>i?f(i-1,s.replace(/./g,c=>[32410401423,,10432423401][+c]||c)):s.replace(/./g,c=>c-4?(d+=c&1&&c-2,''):`L${x+=4-'4840'[d&=3]} ${y+=4-'0484'[d]}`))(5)+'">')

Zaoszczędził 1 bajt dzięki Neilowi

Arnauld
źródło
1
Spróbujfill=none
Neil,
2

Python 3, 177 175 171 bajtów

Prosta implementacja systemu Lindenmayera dla krzywej Hilberta. Zapraszamy do gry w golfa!

Edycja: -2 bajty dzięki Kade. -3 bajty od zmiany struktury budowy krzywej Hilberta. -1 bajt dzięki produktom ETH.

from turtle import*;s="a";exec('t=""\nfor c in s:t+=c>"F"and"+-abFF-+baFFba-+FFab+-"[c<"b"::2]or c\ns=t;'*5)
for c in s:
 if"-">c:rt(90)
 elif"F">c:lt(90)
 elif"a">c:fd(9)

wprowadź opis zdjęcia tutaj

Ungolfing

import turtle

hilbert_seq = "a"

for _ in range(5):
    new_seq = ""
    for char in hilbert_seq:
        if char == "a":
            new_seq += "-bF+aFa+Fb-"
        elif char == "b":
            new_seq += "+aF-bFb-Fa+"
        else:
            new_seq += char
    hilbert_seq = new_seq

for char in hilbert_seq:
    if char == "F":
        turtle.forward(9)
    elif char == "+":
        turtle.right(90)
    elif char == "-":
        turtle.left(90)
Sherlock9
źródło
Zmiana sposobu tworzyć tmożna zapisać dwa bajty: t+=[[c,"+AF-BFB-FA+"][c=="B"],"-BF+AFA+FB-"][c=="A"]. Ponieważ wzór jest prawie taki sam dla nich dwóch, zastanawiam się, czy jest jakiś sposób, aby tego użyć ...
Kade
Być może zmienić, if c>"E":aby if"E"<c:zapisać bajt?
ETHproductions
1

MSWLogo (wersja 6.5b), 136 bajtów

Na podstawie końcowego programu krzywej Hilberta tutaj .

to h :n :a :l
if :n=0[stop]
rt :a
h :n-1(-:a):l
fd :l
lt :a
h :n-1 :a :l
fd :l
h :n-1 :a :l
lt :a
fd :l
h :n-1(-:a):l
rt :a
end
h 5 90 9

hZdefiniowana jest funkcja , która przyjmuje liczbę iteracji :n(na podstawie 1), kąt :a, długość :l. Jest rekurencyjny, nazywając siebie niższą iteracją z :azanegowanym kątem w dwóch przypadkach, aby uzyskać prawidłową orientację.

  • rt :a, lt :aobróć żółwia (trójkąt, którego ścieżka jest wytyczona) w prawo, w lewo o :astopnie.
  • fd :lprzesuwa żółwia krok po :lkroku.

Wreszcie, funkcja nazywa się: h 5 90 9. Żółw może być ukryte za dodatkowe 2 bajtach ht.

(5-1) -ta iteracja

dla Moniki
źródło
Co się dzieje w lewym górnym rogu?
flawr
@flawr To żółw. Można to ukryć, dołączając ht.
dla Moniki
1

Mathematica 128 bajtów

Graphics[Line@AnglePath[Total/@Split[Cases[Nest[#/.{-2->(s=##&@@#&)[l={-1,2,0,1,-2,0,-2,1,0,2,-1}],2->s@-l}&,{-2},4],-1|1|0],#!=0&][[;;-2,;;-2]]*Pi/2]]

Jeśli chcesz, zamień 4 powyżej na inną liczbę iteracji.

Wykonano jako system Lindenmayera z sekwencjami liczb całkowitych zamiast ciągów znaków, więc druga reguła produkcyjna jest tylko przeczeniem pierwszej reguły. Ta wersja ma 151 bajtów.

Port kodu MATLAB Jonasa Lundgrena ma tylko 128 bajtów.

z=0;Graphics[Line[{Re[#],Im[#]}&/@Flatten[Table[w=I*Conjugate[z];z={w-(a=1+I),z-(b=1-I),z+a,b-w}/2,{k,5}][[5]]]],AspectRatio->1]

Widzę, że w przyszłej wersji Mathematica może to być naprawdę krótkie, coś w rodzaju:

Graphics@HilbertCurve[n]

http://mathworld.wolfram.com/HilbertCurve.html

Kelly Lowder
źródło
1

LindenMASM , 63 bajtów

Kolejne pytanie z odpowiedzią LindenMASM? Niesamowite!

STT
AXI A
INC 5
SET F 0
RPL A -BF+AFA+FB-
RPL B +AF-BFB-FA+
END

Ponownie, z powodu niektórych błędów rysowania w Pythonie turtle, czasami po uruchomieniu tego całego rysunku nie ma. Jak jednak widać, faktycznie działa:

4. iteracja

Kade
źródło