Conta Dokuma - Bir Sierpiński düğümü çizin


33

N> = 2 olan bir tamsayı verildiğinde, N derece Sierpiński düğümü gösteren bir görüntü oluşturun.

Mesela, işte 2, 3, 4 ve 5 derecelik knotlar:

Derece 2 Derece 3 Derece 4 Derece 5

Tam boy görmek için resimlerin üzerine tıklayınız (ne kadar yüksek olursa resim o kadar büyük olur).

Şartname

  1. N derece Sierpiński düğümü, N derece Sierpiński üçgeni köşeleri kılavuz noktaları olarak kullanılarak çizilir. N derece bir Sierpiński üçgeni, daha büyük bir üçgen şeklinde düzenlenmiş N-1 derece üç Sierpiński üçgenidir. 0 derecelik bir Sierpiński üçgeni eşkenar bir üçgendir.
  2. En küçük bileşen üçgenleri yan uzunluğa (64) sahiptir ve düğümün üzerinde durduğu Sierpiński üçgenini verir. 64 * 2 ^ N
  3. Dış üçgenin merkezi görüntünün merkezinde bulunur. Bu mu değil altta ve üstte eşit boşluk verir.
  4. Çıkış tarafındaki uzunluğunun bir kare görüntü Tavan (64 * 2 ^ N * 2 / ROOT3)burada Tavan (x)olduğu ceiling(x), daha küçük tam sayı x ya da eşittir. Bu, üçgenin merkezi görüntünün merkezinde olduğunda, alttaki Sierpiński üçgeninin üst tepe noktası görüntünün içinde yer alacak kadar büyüktür.
  5. Tek eğri kesinlikle değişmeli olarak kendi altından ve üstünden geçmelidir. Çözümler altında veya altında ya da altında arasında seçim yapabilir.
  6. Örnek görüntüler siyah ön plan ve beyaz arka planı göstermektedir. Kolayca ayırt edilebilen iki rengi seçebilirsiniz. Kenar yumuşatma izin verilir, ancak gerekli değildir.
  7. İki arkın buluştuğu veya eğrinin kendisinin üzerinden veya altından geçtiği boşluklar olmamalıdır.
  8. Çıktı, herhangi bir raster biçimindeki görüntü dosyasına veya doğru varsayılan görüntü boyutu içeren herhangi bir vektör biçimi görüntü dosyasına olabilir. Doğrudan ekrana getirirseniz, ekrandan daha büyük olduğunda tam görüntüyü kaydırmak için kaydırmaya izin veren bir formda olmalıdır.

Yay merkezi, yarıçap ve kalınlığın belirlenmesi

  1. Düğüm, teğetlerinin paralel olduğu noktalarda bir araya gelerek kesintisiz bir birleşme sağlamak için bir dizi dairesel yay şeklinde yapılmıştır. Bu yaylar halka kesitli sektörler (kalınlıktaki yaylar) olarak gösterilir.
  2. Bu yayların merkezleri, en küçük baş aşağı üçgenlerin köşeleridir. Bu gibi her tepe tam bir arkın merkezidir.
  3. Her yayın yarıçapı vardır. 64 * ROOT3 / 2
  4. Bunun istisnası, en dıştaki üçgenin (büyük üçgenin köşelerinde) bulunan arkların, iki bitişik iç köşenin orta noktası olan bir merkeze sahip olmaları ve dolayısıyla yarıçapının yarıçapına sahip olmasıdır. 64 * (ROOT3 / 2-1 / 2)
  5. Her yay toplam kalınlıkla (iç yarıçap ve dış yarıçap arasındaki fark) temsil edilir 64 * (ROOT3 / 2) / 4ve bunun siyah kenarlıklarının her birinin kalınlığı vardır 64 * (ROOT3 / 2) / 16. Eğri bu kenarlıklara sahip olmalı ve sadece katı bir şerit olmamalıdır.

Ölçü birimleri

  1. Tüm mesafeler piksel cinsindendir (1, bitişik 2 piksel arasındaki yatay veya dikey mesafedir).
  2. 3'ün karekökü 7 önemli rakam için doğru olmalıdır. Diğer bir deyişle, hesaplamalarınız öyle bir ROOT3 kullanmaya eşdeğer olmalıdır.1.7320505 <= ROOT3 < 1.7320515

puanlama

Bayt cinsinden en kısa kod kazanır.


Merak edenler için, N = 0 ve N = 1 dahil edilmedi çünkü N> = 2 için geçerli olan paternle tam olarak uyuşmayan bir daireye ve trefoile uyuyorlar. Bu zorluğa yaklaşan yaklaşımların çoğunun 0 ve 1 için özel durum kodu eklemesi gerekeceğini umuyorum, bu yüzden bunları atlamaya karar verdim.


1
Tüm sayıların neyle ilgili olduğunu gösteren bir şema olması yardımcı olur mu?
trichoplax

Cevabımı yazmadan / köşeleri eklememden önce, hattın kalınlığı vb. Gibi küçük ayrıntılar için gerçekten 7 önemli rakam gerekli midir? "7 önemli rakam veya 1 piksel, hangisi daha büyükse" gibi bir doğruluk daha uygun görünmektedir.
Level River St

@LevelRiverSt, görüntünün büyüklüğü girişe göre ölçeklendiğinden, 7 büyük rakam bile daha büyük N için 1 piksel doğruluğu için yetersizdir. Bazı tartışmalardan sonra tüm cevaplar aynı tutulacak şekilde 7 önemli rakama karar verdim. standart.
trichoplax

Evet, resmin daha büyük N için ölçeklendirilmesi için gereklidir. 1000000 x 1000000 görüntüdeki 7 önemli rakam 0,1 piksele karşılık gelir, ancak ara hesaplarda bundan daha kötü olabilirdi. Sadece stroke-width:3.4641021 piksel doğruluk elde etmek için bir fikir elde edersem, bunun biraz daha fazla olduğunu düşünüyorum . İktidar varsa, devam edeceğim ve böyle de dahil edeceğim.
Seviye River St

Yanıtlar:


27

Ruby, 1168 932

Dün geceki bir hata düzeltildi, netleştikten sonra yapılacak daha çok golf oynadı.

Bu (şu anda) stdin'den bir sayı kabul eden ve svgstdout'a bir dosya çıktısı veren tam bir programdır . Svg'yi seçtim çünkü sorunun tüm gereksinimlerini yerine getirmenin mümkün olduğunu biliyordum, ancak bazı sorunları vardı. özellikle SVG sadece pathnesnenin bir parçası olarak dairelerin yaylarını destekler ve onları merkezleri açısından değil, iki bitiş noktası olarak tanımlar.

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>"

N çıkışı = 4

Stack değişimi ile yeniden ölçeklendirildi. Orijinal olarak çok daha iyi görünüyor.

görüntü tanımını buraya girin açıklama

İlk başta http://euler.nmt.edu/~jstarret/sierpinski.html gibi üçgenin kırıldığı, her biri bir köşeden diğerine giden bir yol oluşturan üç farklı renkte şeritlere bölündüm. Eksik daireler, orada eksik altıgenler olarak gösterilir. Altıgenlerin içine daireler yazılması, daire yarıçapının sqrt(3)/2yan uzunluklarının çarpı olması gerektiğini gösterir . Teller gösterildiği gibi yinelemeli olarak oluşturulabilir, ancak köşelerin yuvarlatılması gerektiğinden ve hangi yöne eğrinin eğileceğini bilmek zor olduğu için ek bir komplikasyon var, bu yüzden bu yaklaşımı kullanmadım.

Yaptığım şey şuydu:

Aşağıdaki resimde, bir sierpinski üçgeninde düzenlenmiş N = 2 birime (yeşil) ait yatay bükümler ve ek köprüleme bükümleri (mavi) vardır.

Pascal üçgeni üzerindeki tek sayıların sierpinski üçgeni oluşturduğu yaygın bir bilgidir. Bir sierpinski ikili rakam üçgeni, sayı ile başlayıp p=1yinelemeli olarak xoring yapılarak benzer şekilde elde edilebilir p<<1.

Bu yaklaşımı değiştirdim, başlangıçta p=2ve yinelemeli olarak xoring p*4. Bu, sıfır sütunlarla değişen sierpinski üçgenini verir.

Şimdi p haklarını değiştirebilir ve son üç parçayı kullanarak inceleyebiliriz %8. Eğer 010öyleyse N = 2 birime ait yeşil bir büküm çizmemiz gerekir. eğer onlar 101mavi, köprüleyici bir bükülme çizmemiz gerekiyor. Bu sayıların ikisini birlikte test etmek için moduloyu buluruz %3ve eğer bu 2 ise büküm çizmeliyiz.

Son olarak, yatay bükülmelere ek olarak, çapraz bükülmeleri çizmek ve resmi tamamlamak için 120 ve 240 derece döndürülmüş iki kopya çıkartıyoruz. Geriye kalan tek şey köşeleri eklemektir.

Yorumlanan 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>"

görüntü tanımını buraya girin


"Özgün olarak daha iyi görünüyor" dediğiniz yerde, farkında olmayan herkes için "(tam boyutta görmek için resme tıklayın)" gibi bir şey eklemek faydalı olabilir.
trichoplax

@trichoplax resmin üzerine tıklamak bana olmamıştı. Ama yine de, bu bir PNG'dir, çünkü yığın değişimi svg görüntülerini kabul etmez, bu nedenle kenarlar kasıtlı olarak bulanıklaşır. Yerel SVG dosyamın daha keskin kenarları var ve çok daha iyi görünüyor.
Level River St

@trichoplax görüntü boyutunda hızlı düzeltme yapıldı. Başka bir gün daha golf oynayacak.
Level River St

1
+1 harika iş. Özellikle renk kodlu diyagramla ilgili ayrıntılı açıklamaları beğeniyorum.
trichoplax

1
Köprü öldü.
mbomb007
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.