Draw A Snowflake

18

Joe tinggal di Bahama. Ini musim dingin. Anak-anaknya kecewa karena tidak ada salju. Joe perlu membuat salju untuk anak-anaknya. Untungnya, ia memiliki printer 3-d. Dia berencana membuat kepingan salju dengan itu. Sayangnya dia tidak tahu bagaimana bentuk kepingan salju. Bahkan, dia belum pernah melihat serpihan salju! Mari kita bantu dia dengan membuat program yang secara otomatis menghasilkan gambar salju 2d untuknya.

Memasukkan

Diameter gambar (dalam piksel), persentase gambar yang sebenarnya adalah kepingan salju.

Keluaran

Gambar kepingan salju dengan diameter yang diperlukan. Itu dapat disimpan ke file atau ditampilkan kepada pengguna.

Spesifikasi

Buat irisan yang memiliki sudut 30 derajat. Buat Pohon Brown dengan benih awal pada titik irisan. Refleksikan irisan di sekitar tengah gambar 12 kali untuk menghasilkan sisa gambar. Kepingan salju memiliki warna Putih. Latar belakang memiliki warna Hitam.

Mencetak gol

Karena kenyataannya ada berbagai cara untuk menghasilkan Pohon Brown, skornya adalah 10 * jumlah upvote - skor golf.

Skor golf didefinisikan sebagai jumlah byte dalam program dengan bonus berikut:

-20% Dapat secara sewenang-wenang menentukan simetri kepingan salju.

-50% Dapat menentukan bentuk kepingan salju. (Dengan bisa menentukan rasio panjang sisi wedge.)

Kemenangan skor tertinggi.

Berikut ini gambar bentuk wedge dengan perbandingan kira-kira 2:

Baji

Papan angka:

Martin Buttner: 10 * 14 - 409 = -269

Nimi: 10 * 1 - 733 * .5 = -356.5

Pengoptimal: 10 * 5 - 648 = -598

Pemenangnya adalah Martin dengan skor -269!

TheNumberOne
sumber
Terkait
Martin Ender
9
Saya tidak dapat mengerti mengapa, jika kita diduga membantu seseorang yang belum pernah melihat kepingan salju tahu seperti apa bentuknya, kita seharusnya membuat mereka memiliki simetri rotasi urutan 4. Apakah kita seharusnya mengendalikan orang miskin?
Peter Taylor
1
@Conor "Nilainya 10 * jumlah upvotes - golfscore." Program itu akan memiliki skor -300000000. Itu sangat rendah.
TheNumberOne
1
6x60deg irisan! sebuah perbaikan pada apa yang dikatakannya pada saat komentar @PeterTaylor, tetapi sebenarnya Anda membutuhkan wedges 12x30deg .. 6 untuk sisi kanan dari masing-masing 6 poin, dan 6 yang dipantulkan untuk sisi kiri setiap poin. BTW, saya tidak mengerti bonus kedua
Level River St
2
@Optimizer Selesai, harus lebih jelas sekarang.
TheNumberOne

Jawaban:

16

Mathematica, 409 byte

{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]

Tidak Disatukan:

{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
 ]

Ini mengharapkan input bentuk di {n,p}mana nukuran gambar dalam piksel, dan pmerupakan persentase dari gambar yang akan ditutupi oleh kepingan salju.

Dibutuhkan sekitar setengah menit untuk menghasilkan kepingan salju dengan parameter yang diberikan. Anda dapat mempercepatnya dengan mengubah nilai mdari 999menjadi 99, tetapi hasilnya terlihat agak jarang. Demikian juga, Anda dapat meningkatkan kualitas dengan menggunakan angka yang lebih besar, tetapi kemudian akan memakan waktu sangat lama.

Saya membentuk pohon Brown pada kisi integer, menempatkan partikel baru di {999, 0}, dan memindahkan secara acak ke kiri dan ke atas atau ke bawah (bukan ke kanan), sampai mereka mengenai partikel yang ada. Saya juga membatasi gerakan ke irisan antara 0 dan 30 derajat. Akhirnya, saya merefleksikan irisan itu pada sumbu x, dan menampilkannya dengan 5 putarannya.

Berikut beberapa hasil (klik untuk versi yang lebih besar):

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

Dan inilah dua animasi dari pertumbuhan pohon Brown (10 partikel per irisan per bingkai):

masukkan deskripsi gambar di sinimasukkan deskripsi gambar di sini

Martin Ender
sumber
2
Wow saya suka ... semuanya, sebenarnya. Hasilnya bagus!
Sp3000
6

JavaScript, ES6, 799 740 695 658 648

Saya hanya menghitung dua tag kanvas dan fungsi fdari cuplikan di bawah ini sebagai bagian dari jumlah byte. Sisa barang adalah untuk demo langsung

Untuk menyaksikannya beraksi, jalankan cuplikan di bawah ini di Firefox terbaru yang memberikan ukuran dan rasio melalui kotak input

Perhatikan bahwa Anda harus menyembunyikan hasilnya lalu tampil lagi sebelum kepingan salju berturut-turut

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>

Berikut adalah beberapa contoh render dengan ukuran dan persentase yang berbeda. Yang terbaik disebut SkullFlake (pertama dalam daftar). Klik gambar untuk melihatnya dalam resolusi penuh.

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

Banyak bantuan dan masukan dari Martin dan githubphagocyte.

Pengoptimal
sumber
Ini tidak mengambil persentase dari gambar yang diisi sebagai input.
TheNumberOne
@TheBestOne mengambil persentase ke akun sekarang. Perhatikan bahwa karena ini adalah kepingan salju berbasis pohon Brown, baik persentase maupun rasio untuk panjang irisan tidak dapat akurat karena peran keacakan sedang dimainkan.
Pengoptimal
Ini memenuhi syarat sekarang.
TheNumberOne
1

Haskell, 781 733 Bytes

Program ini menampilkan opsi "tentukan rasio panjang sisi wedge", jadi Anda harus menyebutnya dengan tiga argumen baris perintah:

./sf 150 50 40

Argumen # 1 adalah ukuran gambar, # 2% dari piksel dalam irisan dan # 3 panjang (dalam%) dari sisi yang lebih pendek dari irisan. Gambar disimpan dalam file yang disebut "o.png".

150-50-40: 150-50-40

Program saya menghasilkan kepingan salju dengan paku cut-off, karena piksel baru mulai pada sumbu tengah wedge (titik hijau, lihat di bawah) dan cenderung tetap di sana, karena mereka bergerak secara acak ke kiri, ke atas atau ke bawah. Karena piksel di luar baji dibuang, garis lurus muncul di batas baji (panah hijau). Saya terlalu malas untuk mencoba jalur lain untuk piksel.

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

Ketika baji cukup besar (argumen ke-3 100) lonjakan pada sumbu tengah dapat tumbuh dan kemudian ada 12 dari mereka.

150-40-100: 150-40-100

Beberapa piksel membuat bentuk bundar (kiri: 150-5-20; kanan 150-20-90).

150-5-20 150-20-90

Program:

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
nimi
sumber
@Optimizer: spike ada di sumbu tengah wedge. Irisan naik dan turun 15 derajat ke sumbu x. Dalam *-*-100gambar kedua sisi mencapai ke batas kiri gambar (lihat gambar kedua untuk posisi irisan). Ada piksel di sekitar setengah dari sisi - bagian lainnya kosong.
nimi
1
Menggunakan penghitung ini, program Anda memiliki panjang 841 byte.
TheNumberOne
@TheBestOne: Tab vs Spasi saat indentasi. Saya telah mencampurnya ketika menambahkan 4 ruang tambahan untuk code style. Saya telah mengedit posting saya dan mengatur Tab, tetapi masih muncul sebagai spasi. Adakah yang tahu cara memperbaikinya?
nimi
@nimi Di situs yang terhubung TheBestOne ada sedikit #tautan hash yang bisa Anda klik. Anda dapat menempelkan kode tab di sana dan menautkannya.
Sp3000
Anda mungkin dapat membuat tautan ke kode di suatu tempat. Anda bisa menggunakan spasi alih-alih tab untuk membuat indentasi. Anda bisa mendapatkan secara manual code styledengan membuat indentasi setiap spasi 4 baris.
TheNumberOne
0

Memproses 2 - 575 karakter

Mengambil file f yang baris pertama adalah ukuran gambar dan yang kedua adalah radius serpihan. Setiap kali titik baru ditempatkan, ia diputar di sekitar pusat 12 kali. Ini menciptakan efek yang sangat mirip dengan irisan yang diputar, tetapi tidak persis sama.

  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(); 

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

Anda dapat memproses di sini

bubalou
sumber
3
Ini tidak sesuai dengan spesifikasinya. Ini akan memenuhi syarat jika Anda mencerminkan titik di sekitar tengah alih-alih memutarnya.
TheNumberOne
color(255)dapat menjadi color(-1)menghemat satu byte
Kritixi Lithos