Biorąc pod uwagę liczbę całkowitą n
wyświetlamy na n
th iteracji Hilberta Curve w ASCII za pomocą znaków _
i |
.
Oto pierwsze 4 iteracje:
n=1
_
| |
n=2
_ _
| |_| |
|_ _|
_| |_
n=3
_ _ _ _
| |_| | | |_| |
|_ _| |_ _|
_| |_____| |_
| ___ ___ |
|_| _| |_ |_|
_ |_ _| _
| |___| |___| |
n=4
_ _ _ _ _ _ _ _
| |_| | | |_| | | |_| | | |_| |
|_ _| |_ _| |_ _| |_ _|
_| |_____| |_ _| |_____| |_
| ___ ___ | | ___ ___ |
|_| _| |_ |_| |_| _| |_ |_|
_ |_ _| _ _ |_ _| _
| |___| |___| |_| |___| |___| |
|_ ___ ___ ___ ___ _|
_| |_ |_| _| |_ |_| _| |_
| _ | _ |_ _| _ | _ |
|_| |_| | |___| |___| | |_| |_|
_ _ | ___ ___ | _ _
| |_| | |_| _| |_ |_| | |_| |
|_ _| _ |_ _| _ |_ _|
_| |___| |___| |___| |___| |_
Wyjaśnienia
- Moje pytanie jest podobne do Narysuj krzywą Hilberta i Narysuj krzywą Hilberta za pomocą ukośników .
- Konwersja między znakami podkreślenia (
_
) i pionowymi słupkami (|
) jestu=2*v-1
gdzieu
jest liczbą_
s iv
jest liczbą|
s. - Aby zachować spójność z moim pierwotnym postem, krzywa musi zaczynać się i kończyć na dole.
- Możesz mieć pełny program lub funkcję.
- Wyjście na standardowe wyjście (lub coś podobnego).
- Możesz mieć wiodące lub końcowe białe spacje, dane wyjściowe muszą po prostu zostać wyrównane, aby wyglądały jak przykłady.
- To jest golf golfowy, więc wygrywa najkrótsza odpowiedź w bajtach.
Odpowiedzi:
Befunge,
444368323 bajtówWypróbuj online!
Typowe podejście do rysowania Krzywej Hilberta polega na podążaniu ścieżką jako serii pociągnięć i zwojów, renderowaniu wyniku w mapę bitową lub w pewnym obszarze pamięci, a następnie zapisywaniu tego renderowania po ukończeniu ścieżki. Jest to po prostu niewykonalne w Befunge, gdy mamy tylko 2000 bajtów pamięci do pracy, i obejmuje to źródło samego programu.
Podjęliśmy więc formułę, która mówi nam dokładnie, który znak wyprowadzić dla danej współrzędnej x, y. Aby zrozumieć, jak to działa, to najłatwiej zignorować rendering ASCII na początek, i tylko myśleć o krzywej jako składający się ze znaków skrzynkowych:
┌
,┐
,└
,┘
,│
, i─
.Kiedy spojrzymy na taką krzywą, natychmiast zobaczymy, że prawa strona jest dokładnym lustrem lewej strony. Znaki po prawej stronie można po prostu określić, patrząc na partnera po lewej stronie i odzwierciedlając go w poziomie (tj. Wystąpienia
┌
i┐
zamiana, podobnie jak└
i┘
).Następnie patrząc na lewy dolny róg, ponownie widzimy, że dolna połowa jest odbiciem górnej połowy. Tak więc postacie na dole są po prostu określane, patrząc na swojego partnera powyżej i odzwierciedlając go w pionie (tj. Wystąpienia
┌
i└
są zamieniane, tak jak┐
i┘
).Pozostała połowa tego rogu jest nieco mniej oczywista. Blok po prawej stronie można uzyskać z pionowego odbicia bloku przyległego do niego po przekątnej.
Blok lewej ręki można wyprowadzić z pionowego odbicia bloku w lewym górnym rogu pełnej krzywej.
W tym momencie pozostaje nam tylko lewy górny róg, który jest tylko kolejną krzywą Hilberta o jedną iterację niżej. Teoretycznie powinniśmy teraz po prostu powtórzyć proces, ale jest trochę haczyka - na tym poziomie lewa i prawa połowa bloku nie są dokładnymi zwierciadłami.
Tak więc na czymkolwiek innym niż najwyższy poziom, znaki dolnego rogu należy traktować jako specjalny przypadek, w którym
┌
postać jest odzwierciedlana jako─
, a│
postać jest odzwierciedlana jako└
.Ale poza tym naprawdę możemy po prostu powtórzyć ten proces rekurencyjnie. Na ostatnim poziomie kodujemy lewy górny znak jako
┌
, a znak pod nim jako│
.Teraz, gdy mamy sposób na określenie kształtu krzywej przy określonej współrzędnej x, y, jak przełożyć to na renderowanie ASCII? Jest to po prostu proste mapowanie, które tłumaczy każdy możliwy kafelek na dwa znaki ASCII.
┌
staje się_
(spacja plus podkreślenie)┐
staje się└
staje się|_
(pionowy pasek plus podkreślenie)┘
staje się|
(pionowy pasek plus spacja)│
staje się|
(ponownie pionowy pasek plus spacja)─
staje się__
(dwa podkreślenia)To odwzorowanie początkowo nie jest intuicyjne, ale możesz zobaczyć, jak to działa, patrząc na dwa odpowiadające sobie renderingi obok siebie.
I to w zasadzie wszystko. W rzeczywistości implementacja tego algorytmu w Befunge to zupełnie inny problem, ale wyjaśnię to na inny czas.
źródło
C, 267 bajtów
Wypróbuj online!
h()
używa rekurencji do generowania pociągnięć krzywej Hliberta.t()
drukuje znak obrysu tylko wtedy, gdy położenie pisakap
jest równe bieżącej pozycji wyjściowejq
.Jest to nieefektywne, ale proste.
Jeśli krzywa zaczyna się w lewym górnym rogu, kod można zmniejszyć do 256 bajtów.
źródło
puts("")
zamiastputchar(10)
i"..."+l*8+d*2
zamiast&"..."[l*8+d*2]
in--?h(d+r...-r,n):0
zamiastn--&&(h(d+r...-r,n))