スノーフレークを描く


18

ジョーはバハマに住んでいます。冬です。彼の子供たちは雪がないことに失望しています。ジョーは子供のために雪を作る必要があります。幸いなことに、彼は3Dプリンターを持っています。彼はそれで雪片を作る予定です。残念ながら、彼は雪の結晶がどのように見えるかわかりません。実際、彼はスノーフレークを見たことがない!彼のために雪片の2Dイメージを自動的に生成するプログラムを作成して、彼を助けましょう。

入力

画像の直径(ピクセル単位)、実際には雪片である画像の割合。

出力

必要な直径のスノーフレークの画像。ファイルに保存するか、ユーザーに表示できます。

仕様書

30度の角度を持つくさびを作成します。ウェッジのポイントに初期シードを持つブラウン木を作成します。画像の残りの部分を生成するために、画像の中心の周りにウェッジを12回反射します。スノーフレークの色は白です。背景の色は黒です。

得点

ブラウンの木を生成する方法はさまざまであるため、スコアは10 *投票数-ゴルフスコアです。

ゴルフスコアは、プログラム内のバイト数として定義され、次のボーナスがあります。

-20%スノーフレークの対称性を任意に指定できます。

-50%スノーフレークの形状を指定できます。(ウェッジの辺の長さの比率を指定できることにより。)

最高スコアが勝ちます。

以下の図は、比率が約2の場合のウェッジの形状を示しています。

くさび

スコアボード:

マーティン・バトナー:10 * 14-409 = -269

ニミ:10 * 1-733 * .5 = -356.5

オプティマイザー:10 * 5-648 = -598

勝者は-269のスコアを持つマーティンです!



9
雪の結晶を見たことがない人が自分の外見を知るのを助けていると言われているのなら、その理由を理解できません。順序4の回転対称性を持たせる必要があります。
ピーターテイラー14

1
@Conor「スコアは10 *投票数-golfscoreです。」そのプログラムのスコアは-300000000です。それは非常に低いです。
TheNumberOne

1
6x60degウェッジ!@PeterTaylorのコメント時に言ったことの改善ですが、実際には12x30degのくさびが必要です。6つのポイントのそれぞれの右側に6つ、各ポイントの左側に6つ反映されます。ところで、私は2番目のボーナスを理解していない
レベル川セント

2
@Optimizer Doneは、より明確になりました。
TheNumberOne

回答:


16

Mathematica、409バイト

{n,p}=Input[];m=999;Clear@f;_~f~_=0;0~f~0=1;r=RandomInteger;For[i=0,i<m,++i,For[x=m;y=0,f[x+1,y]+f[x-1,y]+f[x,y+1]+f[x,y-1]<1,a=b=-m;While[x+a<0||y+b<0||(y+b)/(x+a)>Tan[Pi/6],a=-r@1;b=r@2-1];x+=a;y+=b];x~f~y=1];Graphics[{White,g=Point/@Join@@{c=Cases[Join@@Table[{i,j}-1,{i,m},{j,m}],{i_,j_}/;i~f~j>0],c.{{1,0},{0,-1}}},Array[Rotate[g,Pi#/3,{0,0}]&,6]},Background->Black,ImageSize->n*p,ImageMargins->n(1-p)/2]

ゴルフをしていない:

{n,p}=Input[];
m = 999;
ClearAll@f;
_~f~_ = 0;
0~f~0 = 1;
r = RandomInteger;
For[i = 0, i < m, ++i,
  For[x = m; y = 0, 
   f[x + 1, y] + f[x - 1, y] + f[x, y + 1] + f[x, y - 1] < 1,
   a = b = -m;
   While[x + a < 0 || y + b < 0 || (y + b)/(x + a) > Tan[Pi/6],
    a = -r@1;
    b = r@2 - 1
    ];
   x += a;
   y += b
   ];
  x~f~y = 1
  ];
Graphics[
 {White, g = 
   Point /@ 
    Join @@ {c = 
       Cases[Join @@ Table[{i, j} - 1, {i, m}, {j, m}], {i_, j_} /;
          i~f~j > 0], c.{{1, 0}, {0, -1}}}, 
  Array[Rotate[g, Pi #/3, {0, 0}] &, 6]},
 Background -> Black,
 ImageSize -> n*p,
 ImageMargins -> n (1 - p)/2
 ]

これは、フォームの入力を想定した画素の画像サイズであり、雪片によってカバーされる画像の割合です。{n,p}np

指定されたパラメーターでスノーフレークを生成するのに30分程度かかります。あなたは、の値を変更することによって、それをスピードアップすることができますmから99999、しかし、結果はビットスパースを探します。同様に、大きな数字を使用することで品質を上げることができますが、非常に時間がかかります。

私は整数格子上にブラウン木を形成し、新しい粒子をに配置し{999, 0}、それらが既存の粒子に当たるまで、ランダムに左または上(右ではなく)に移動します。また、モーションを0〜30度のウェッジに制限しています。最後に、そのくさびをx軸に反映し、5回転で表示します。

以下に結果を示します(クリックすると拡大します)。

ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください

そして、ブラウンの木が成長する2つのアニメーションがあります(フレームごとにウェッジあたり10個のパーティクル)。

ここに画像の説明を入力してくださいここに画像の説明を入力してください


2
うわー、私はそれらがすべて、実際に好きです。結果は素晴らしいです!
Sp3000 14

6

JavaScript、ES6、799740695 658 648

fバイトカウントの一部として、以下のスニペットから2つのキャンバスタグと関数のみをカウントしています。残りはライブデモ用です

実際の動作を見るには、最新のFirefoxで以下のスニペットを実行して、入力ボックスからサイズと比率を指定します

結果を非表示にし、連続する雪片の前に再び表示する必要があることに注意してください

f=(N,P)=>{E.width=E.height=D.width=D.height=N
E.style.background="#000"
C=D.getContext("2d"),F=E.getContext("2d")
C.strokeStyle='#fff'
M=Math,r=M.random,I=0,n=N/2
C.beginPath()
C.rect(n,n,2,2)
C.fill()
B=_=>{x=n*P/100,y=0,w=[]
do{w.push([x,y])
do{X=2*((r()*2)|0)
Y=2*(((r()*3)|0)-1)
}while(x-X<0||y-Y<0||(y-Y)/(x-X)>.577)
x-=X,y-=Y}while(!C.isPointInPath(n+x,n+y))
I++
w=w.slice(-4)
x=w[0]
C.moveTo(x[0]+n,x[1]+n)
w.map(x=>C.lineTo(n+x[0],n+x[1]))
C.stroke()
E.width=E.height=N
for(i=0;i<12;i++){F.translate(n,n)
i||F.rotate(M.PI/6)
i-6?F.rotate(M.PI/3):F.scale(1,-1)
F.translate(-n,-n)
F.drawImage(D,0,0)}
I<(n*n*P*.22/100)&&setTimeout(B,15)}
B()}
<input placeholder="Input N" id=X /><input placeholder="Input percentage" id=Y /><button onclick="f(~~X.value,~~Y.value)">Create snowflake</button><br>
<canvas id=E><canvas id=D>

さまざまなサイズと割合でレンダリングする例をいくつか示します。最良のものはSkullFlakeと呼ばれます(リストの最初)。画像をクリックして、最大解像度で表示します。

ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください

Martinとgithubphagocyteからの多くのヘルプと入力。


これは、入力として塗りつぶされる画像の割合を取りません。
TheNumberOne

@TheBestOneは、今ではパーセンテージを考慮しています。これはブラウンツリーベースのスノーフレークであるため、ランダム性の役割が作用しているため、ウェッジの長さの割合も比率も正確ではないことに注意してください。
オプティマイザー

これは今資格があります。
TheNumberOne

1

Haskell、781 733バイト

このプログラムは、「くさびの辺の長さの比率を指定する」オプションを備えているため、3つのコマンドライン引数で呼び出す必要があります。

./sf 150 50 40

引数#1は画像のサイズ、#2はウェッジ内のピクセルの%、#3はウェッジの短辺の長さ(%)です。画像は「o.png」というファイルに保存されます。

150-50-40: 150-50-40

私のプログラムは、新しいピクセルがウェッジの中央軸(緑色のドット、下を参照)から始まり、左、上、または下に等しくランダムに移動するため、そこにとどまるため、カットオフスパイクのある雪片を生成します。ウェッジの外側のピクセルが破棄されると、ウェッジの境界に直線が表示されます(緑の矢印)。私はピクセルに対して他のパスを試すのが面倒でした。

150-50-40: 150-40-40e

ウェッジが十分に大きい場合(3番目の引数100)、中央軸のスパイクが大きくなり、12個あります。

150-40-100: 150-40-100

丸い形を作るピクセルはほとんどありません(左:150-5-20、右150-20-90)。

150-5-20 150-20-90

プログラム:

import System.Environment;import System.Random;import Graphics.GD
d=round;e=fromIntegral;h=concatMap;q=0.2588
j a(x,y)=[(x,y),(d$c*e x-s*e y,d$s*e x+c*e y)] where c=cos$pi/a;s=sin$pi/a
go s f w p@(x,y)((m,n):o)|x<1=go s f w(s,0)o|abs(e$y+n)>q*e x=go s f w p o|elem(x-m,y+n)f&&(v*z-z)*(b-q*z)-(-v*q*z-q*z)*(a-z)<0=p:go s(p:f)w(s,0)o|1<2=go s f w(x-m,y+n)o where z=e s;a=e x;b=e y;v=e w/100
main = do 
 k<-getArgs;g<-getStdGen;let(s:p:w:_)=map read k
 i<-newImage(2*s,2*s);let t=h(j 3)$h(\(x,y)->[(x,y),(d$0.866*e x+0.5*e y,d$0.5*e x-0.866*e y)])$take(s*d(q*e s)*p`div`100)$go s[(0,0)]w(s,0)$map(\r->((1+r)`mod`2,r))(randomRs(-1,1)g)
 mapM(\(x,y)->setPixel(x+s,y+s)(rgb 255 255 255)i)((h(j(-3/2))t)++(h(j(3/2))t));savePngFile "o.png" i

@Optimizer:スパイクはウェッジの中央軸上にあります。ウェッジはx軸に対して15度上下します。で*-*-100それの両側は、画像の左側境界に達する像(楔の位置に対する第2の画像を参照)。側面の約半分にピクセルがあります-他の半分は空です。
nimi

1
このカウンタを使用すると、プログラムの長さは841バイトになります。
TheNumberOne

@TheBestOne:インデント時のタブとスペース。追加の4つのスペースを追加するときにそれらを混同しましたcode style。投稿を編集してタブを設定しましたが、まだスペースとして表示されます。誰でもそれを修正する方法を知っていますか?
nimi

@nimi TheBestOneリンクのサイトに#は、クリックできる小さなハッシュリンクがあります。タブ付きコードをそこに貼り付けてリンクすることができます。
Sp3000

おそらくどこかにコードへのリンクを作成できます。インデントするには、タブの代わりにスペースを使用できます。code style4行ごとにインデントすることで手動で取得できます。
TheNumberOne

0

処理2-575文字

最初の行が画像サイズで、2行目がフレーク半径であるファイルfを取り込みます。新しいポイントが配置されるたびに、中心の周りを12回回転します。これにより、回転ウェッジと非常に似た効果が作成されますが、まったく同じではありません。

  int d,w,h,k,l,o,p,x,y;
  String n[] = loadStrings("f.txt");
  d=Integer.parseInt(n[0]);
  h=Integer.parseInt(n[1]);
  size(d,d);
  w=d/2;
  k=l=(int)random(d); 
  background(0);
  loadPixels();
  o=p=0;
  pixels[w*w*2+w]=color(255);
  while(true)
  {
    o=k+(int)random(-2,2);
    p=l+(int)random(-2,2);
    if(p*d+o>d*d-1 || p*d+o<0 || o<0 || o>d){
      k=l=(int)random(d);
    }
    else
    {
      if(pixels[p*d+o]==color(255))
      {
        p=l-w;
        o=k-w;
        if(o*o+p*p>h*h){break;}
        float s,c;
        for(int j=0;j<12;j++)
        {
          s=sin(PI*j/6);
          c=cos(PI*j/6);         
          x=(int)((o*c)-(p*s));
          y=(int)(((p*c)+(o*s)));
          pixels[(int)(d*y+x+w+(w*d))]=color(255);
        }
        k=l=(int)random(d);  
      }
      else
      {
        k=o;
        l=p;
      }
    }
  }
  updatePixels(); 

ここに画像の説明を入力してください ここに画像の説明を入力してください

ここで処理を取得できます


3
これは仕様に完全には適合しません。これは、中心点を回転させるのではなく、中心の周りに点を反映した場合に適格となります。
TheNumberOne

color(255)color(-1)1バイトを保存するようになることができます
Kritixi Lithos
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.