ルビー、1168 932
昨夜の間違いを修正し、明確化した後にゴルフをするようにしました。
これは(現在)stdinから数値を受け取り、svg
ファイルをstdoutに出力する完全なプログラムです。質問のすべての要件を満たすことが可能であることを知っていたため、svgを選択しましたが、いくつかの問題がありました。特に、SVGはpath
オブジェクトの一部として円弧のみをサポートし、中心ではなく2つの端点で定義します。
コード
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 = 4
スタック交換によって再スケーリングされます。オリジナルとしてはるかに良く見えます。
説明
まず、http://euler.nmt.edu/~jstarret/sierpinski.htmlのようなものを考えました。三角形は3つの異なる色のストランドに分割され、それぞれが1つのコーナーから別のコーナーへのパスを形成します。不完全な円は、そこに不完全な六角形として表示されます。六角形の内側に円を刻むと、円の半径に辺の長さをsqrt(3)/2
掛けたものになるはずです。ストランドは図のように再帰的に構築できますが、角を丸くする必要があり、どの方向に湾曲するかを知るのが難しいため、さらに複雑になります。したがって、このアプローチは使用しませんでした。
私がしたことは次のとおりでした。
下の画像では、N = 2ユニット(緑色)に属する水平方向のねじれが、シエルピンスキーの三角形に配置されており、追加の架橋ねじれ(青色)があります。
パスカルの三角形の奇数がシエルピンスキーの三角形を形成することはよく知られています。2進数のsierpinski三角形は、数値で開始し、p=1
で繰り返しxorすることにより、同様の方法で取得できますp<<1
。
私はこのアプローチを修正p=2
しましたp*4
。これにより、ゼロの列と交互にシエルピンスキーの三角形が得られます。
これでpを右シフトし、を使用して最後の3ビットを検査できます%8
。もしそうであれば010
、N = 2ユニットに属する緑のツイストを描く必要があります。もしそうなら101
、青い、橋を架けるねじれを描く必要があります。これらの数値の両方を一緒にテストするには、モジュロを見つけます。%3
これが2の場合、ツイストを描く必要があります。
最後に、水平方向のねじれに加えて、2つのコピーを120度と240度回転させて斜めのねじれを描き、画像を完成させます。残っているのは、角を追加することだけです。
コメント付きコード
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>"