Tkanie uszczelek - narysuj węzeł Sierpińskiego


33

Biorąc pod uwagę liczbę całkowitą N> = 2, wykonaj zdjęcie pokazujące węzeł Sierpińskiego stopnia N.

Na przykład tutaj są węzły stopnia 2, 3, 4 i 5:

Stopień 2 Stopień 3 Stopień 4 Stopień 5

Kliknij obrazy, aby wyświetlić pełny rozmiar (im wyższy stopień, tym większy obraz).

Specyfikacja

  1. Węzeł Sierpińskiego stopnia N jest rysowany z wykorzystaniem wierzchołków trójkąta Sierpińskiego stopnia N jako punktów prowadzących. Trójkąt Sierpińskiego stopnia N to trzy trójkąty Sierpińskiego stopnia N-1 ułożone w większy trójkąt. Trójkąt Sierpińskiego stopnia 0 jest trójkątem równobocznym.
  2. Najmniejsze trójkąty składowe mają długość boku 64, co daje trójkątowi Sierpińskiego, na którym opiera się węzeł, całkowitą długość boku 64 * 2 ^ N
  3. Środek zewnętrznego trójkąta znajduje się na środku obrazu. Ten sposób nie dać równe białe na górze i na dole.
  4. Dane wyjściowe to kwadratowy obraz o długości boku, sufit (64 * 2 ^ N * 2 / ROOT3)gdzie sufit (x)jest ceiling(x)najmniejszą liczbą całkowitą większą lub równą x. Jest to wystarczająco duża wielkość, aby górny wierzchołek leżącego poniżej trójkąta Sierpińskiego mógł być zawarty w obrazie, gdy środek trójkąta znajduje się w środku obrazu.
  5. Pojedyncza krzywa musi przechodzić nad i pod sobą, ściśle naprzemiennie. Rozwiązania mogą wybierać pomiędzy poniżej, a potem lub poniżej.
  6. Przykładowe obrazy pokazują czarny pierwszy plan i białe tło. Możesz wybrać dowolne dwa łatwe do odróżnienia kolory. Wygładzanie jest dozwolone, ale nie konieczne.
  7. Nie mogą istnieć przerwy w miejscu, w którym spotykają się dwa łuki lub w którym krzywa przechodzi nad lub pod sobą.
  8. Dane wyjściowe mogą pochodzić z dowolnego pliku obrazu w formacie rastrowym lub dowolnego pliku obrazu w formacie wektorowym, który zawiera prawidłowy domyślny rozmiar wyświetlania. Jeśli wyświetlasz bezpośrednio na ekranie, musi być w formie umożliwiającej przewijanie, aby zobaczyć pełny obraz, gdy jest większy niż ekran.

Określanie środka łuku, promienia i grubości

  1. Węzeł jest zbudowany jako seria okrągłych łuków, które spotykają się w punktach, w których ich styczne są równoległe, aby zapewnić płynne połączenie. Łuki te są wyświetlane jako sektory pierścieniowe (łuki o grubości).
  2. Środkami tych łuków są wierzchołki najmniejszych trójkątów odwróconych do góry nogami. Każdy taki wierzchołek jest środkiem dokładnie jednego łuku.
  3. Każdy łuk ma promień 64 * ROOT3 / 2
  4. Wyjątkiem jest to, że łuki w trzech najbardziej zewnętrznych trójkątach (w rogach dużego trójkąta) mają środek, który jest punktem środkowym dwóch sąsiadujących wewnętrznych wierzchołków, a zatem mają promień 64 * (ROOT3 / 2-1 / 2)
  5. Każdy łuk jest reprezentowany przez całkowitą grubość (różnicę między promieniem wewnętrznym i promieniem zewnętrznym), 64 * (ROOT3 / 2) / 4a czarne granice każdego z nich mają grubość 64 * (ROOT3 / 2) / 16Krzywa musi mieć te granice, a nie być tylko jednolitym paskiem.

Jednostki miary

  1. Wszystkie odległości podano w pikselach (1 to pozioma lub pionowa odległość między 2 sąsiadującymi pikselami).
  2. Pierwiastek kwadratowy z 3 musi być dokładny do 7 znaczących cyfr. Oznacza to, że twoje obliczenia muszą być równoważne z użyciem ROOT3 takiego, że1.7320505 <= ROOT3 < 1.7320515

Punktacja

Najkrótszy kod w bajtach wygrywa.


Dla tych, którzy zastanawiają się, N = 0 i N = 1 nie są uwzględnione, ponieważ odpowiadają okręgowi i koniczynie, które nie do końca pasują do wzoru, który dotyczy N> = 2. Spodziewałbym się, że większość podejść do tego wyzwania będzie musiała dodać specjalny kod sprawy dla 0 i 1, więc postanowiłem je pominąć.


1
Czy pomogłoby mieć diagram pokazujący, do czego odnoszą się wszystkie liczby?
trichoplax

Czy zanim przejdę do golfa w odpowiedzi / dodam rogi, czy naprawdę konieczne jest podanie 7 znaczących liczb w przypadku drobnych szczegółów, takich jak grubość linii itp.? Dokładność taka jak „7 znaczących cyfr lub 1 piksel, w zależności od tego, która wartość jest większa” wydaje się bardziej odpowiednia.
Level River St

@LevelRiverSt, ponieważ rozmiar obrazu skaluje się wraz z wejściem, nawet 7 znaczących cyfr jest niewystarczające dla dokładności 1 piksela dla większej N. Ustawiłem 7 znaczących cyfr po krótkiej dyskusji na czacie, więc wszystkie odpowiedzi są takie same standard.
trichoplax

Tak, jest to konieczne do skalowania obrazu dla większych N. 7 znaczących liczb na obrazie 1000000 x 1000000 odpowiada 0,1 pikselowi, ale przy obliczeniach pośrednich mogłoby być gorzej. Po prostu uważam, że stroke-width:3.464102podobnie jest nieco przesadnie, jeśli chodziło o uzyskanie dokładności 1 piksela. Jeśli tak, to postanowię.
Level River St

Odpowiedzi:


27

Ruby, 1168 932

Poprawiono błąd z zeszłej nocy, więcej golfa do zrobienia po wyjaśnieniu.

Jest to (obecnie) pełny program, który przyjmuje liczbę ze standardowego wejścia i wysyła svgplik na standardowe wyjście. Wybrałem svg, ponieważ wiedziałem, że można spełnić wszystkie wymagania pytania, ale miało pewne problemy. w szczególności SVG obsługuje tylko łuki kół jako część pathobiektu i nie definiuje ich pod względem ich środka, ale raczej dwa punkty końcowe.

Kod

n=gets.to_i
r=64*w=0.75**0.5
m=1<<n-2
z=128*m/w
a=(s="<path style='fill:none;stroke:black;stroke-width:3.464102' transform='translate(%f %f)'
")%[0,r-r*m*8/3]+"d='M18.11943,-2A#{b=r-6*w-32} #{b} 0 0,0 #{-b} 0#{k='A%f %f 0 0 '%([58*w]*2)}0 0,38.71692
M28.58980,1.968882#{l='A%f %f 0 0 '%([70*w]*2)}0 #{c=r+6*w-32} 0A#{c} #{c} 0 0,0 #{-c} 0#{l}0 -9 44.65423'/>"
p=2
m.times{|i|(i*2+1).times{|j|(p>>j)%8%3==2&&a<<s%[128*(j-i),r*3+r*i*4-r*m*8/3]+
"d='M-55,44.65423#{k}0 11.5,25.11473#{l}1 35.41020,1.968882
M-64,51.48786#{l}0 20.5,30.31089#{k}1 36.82830,13.17993
M-82.17170,-2.408529#{l}1 -11.5,25.11473#{k}0 0,38.71692
M-81.52984 8.35435#{k}1 -20.5,30.31089#{l}0 -9,44.65423
M9,44.65423#{k}0 81.52984,8.35435
M0,51.48786#{l}0 91.17169,13.17993'/>"}
p^=p*4}
puts "<svg xmlns='http://www.w3.org/2000/svg' viewBox='#{-z} #{-z} #{e=2*z+1} #{e}' width='#{e}px' height='#{e}px'>"+
"<g transform='rotate(%d)'>#{a}</g>"*3%[0,120,240]+"</svg>"

Wyjście N = 4

przeskalowane przez wymianę stosu. Wygląda znacznie lepiej niż oryginał.

wprowadź opis zdjęcia tutaj Wyjaśnienie

Na początku zastanawiałem się nad czymś takim jak http://euler.nmt.edu/~jstarret/sierpinski.html, gdzie trójkąt jest podzielony na trzy różnokolorowe pasma, z których każdy tworzy ścieżkę od jednego rogu do drugiego. Niekompletne koła są tam pokazane jako niekompletne sześciokąty. wpisanie okręgów w sześciokąty pokazuje, że promień okręgu powinien być sqrt(3)/2pomnożony przez długość boczną. Pasma można budować rekurencyjnie, jak pokazano, ale istnieje dodatkowa komplikacja, ponieważ rogi muszą być zaokrąglone i trudno jest określić, w którym kierunku zakrzywiać, więc nie zastosowałem tego podejścia.

To, co zrobiłem, było następujące.

Na poniższym obrazku widać poziome skręty należące do jednostek N = 2 (na zielono) ułożone w trójkąt sierpiński i dodatkowe skręty mostkowe (na niebiesko).

Powszechnie wiadomo, że liczby nieparzyste na trójkącie Pascala tworzą trójkąt sierpiński. p=1Trójbicie sierpińskiego cyfr binarnych można uzyskać w analogiczny sposób, zaczynając od liczby i iteracyjnie ją xoring p<<1.

Zmodyfikowałem to podejście, zaczynając od p=2iteracyjnie xoring p*4. Daje to trójkąt sierpiński na przemian z kolumnami zer.

Teraz możemy przesunąć w prawo p i sprawdzić ostatnie trzy bity za pomocą %8. Jeśli tak 010, musimy narysować zielony zwrot należący do jednostki N = 2. jeśli są 101, musimy narysować niebieski, pomostowy zwrot. Aby przetestować obie te liczby razem, znajdujemy moduł %3i jeśli jest to 2, musimy narysować zwrot akcji.

Wreszcie, oprócz poziomych skrętów, wykonujemy dwie kopie obrócone o 120 i 240 stopni, aby narysować skośne skręty i uzupełnić obraz. Pozostało tylko dodać rogi.

Skomentowany kod

n=gets.to_i

#r=vertical distance between rows 
r=64*w=0.75**0.5

#m=number of rows of horizontal twists
m=1<<n-2

#z=half the size of the viewport
z=128*m/w

#s=SVG common to all paths
s="<path style='fill:none;stroke:black;stroke-width:3.464102' transform='translate(%f %f)'
"

#initialize a with SVG to draw top corner loop. Set k and l to the SVG common to all arcs of 58*w and 70*w radius 
a=s%[0,r-r*m*8/3]+
"d='M18.11943,-2A#{b=r-6*w-32} #{b} 0 0,0 #{-b} 0#{k='A%f %f 0 0 '%([58*w]*2)}0 0,38.71692
M28.58980,1.968882#{l='A%f %f 0 0 '%([70*w]*2)}0 #{c=r+6*w-32} 0A#{c} #{c} 0 0,0 #{-c} 0#{l}0 -9 44.65423'/>"

#p is the pattern variable, top row of twists has one twist so set to binary 00000010
p=2

#loop vertically and horizontally
m.times{|i|
 (i*2+1).times{|j|

   #leftshift p. if 3 digits inspected are 010 or 101 
   (p>>j)%8%3==2&&

   #append to a, the common parts of a path...
   a<<s%[128*(j-i),r*3+r*i*4-r*m*8/3]+

   #...and the SVG for the front strand and left and right parts of the back strand (each strand has 2 borders)
"d='M-55,44.65423#{k}0 11.5,25.11473#{l}1 35.41020,1.968882
M-64,51.48786#{l}0 20.5,30.31089#{k}1 36.82830,13.17993
M-82.17170,-2.408529#{l}1 -11.5,25.11473#{k}0 0,38.71692
M-81.52984 8.35435#{k}1 -20.5,30.31089#{l}0 -9,44.65423
M9,44.65423#{k}0 81.52984,8.35435
M0,51.48786#{l}0 91.17169,13.17993'/>"}

#modify the pattern by xoring with 4 times itself for the next row
p^=p*4}

#output complete SVG of correct size with three copies of the finished pattern rotated through 0,120,240 degrees.
puts "<svg xmlns='http://www.w3.org/2000/svg' viewBox='#{-z} #{-z} #{e=2*z+1} #{e}' width='#{e}px' height='#{e}px'>"+
"<g transform='rotate(%d)'>#{a}</g>"*3%[0,120,240]+"</svg>"

wprowadź opis zdjęcia tutaj


Jeśli powiesz „Wygląda znacznie lepiej niż oryginał”, warto dodać coś w rodzaju „(kliknij obraz, aby zobaczyć pełny rozmiar)” dla każdego, kto nie zdaje sobie sprawy.
trichoplax

@ Trichoplax nie przyszło mi do głowy, aby kliknąć obraz. Ale w każdym razie jest to PNG, ponieważ wymiana stosu nie akceptuje obrazów svg, więc krawędzie są celowo rozmyte. Mój lokalny plik SVG ma znacznie wyraźniejsze krawędzie i wygląda znacznie lepiej.
Level River St

Wykonano szybką poprawkę @trichoplax na rozmiar obrazu. Będzie więcej golfa następnego dnia.
Level River St

1
+1 świetna robota. Szczególnie podoba mi się szczegółowe wyjaśnienie schematem oznaczonym kolorem.
trichopaks

1
Hiperłącze nie działa.
mbomb007,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.