Narysuj płatek śniegu

18

Joe mieszka na Bahamach. To jest zima. Jego dzieci są rozczarowane, że nie ma śniegu. Joe musi zrobić śnieg dla swoich dzieci. Na szczęście ma drukarkę 3D. Planuje zrobić z niego płatki śniegu. Niestety nie ma pojęcia, jak wyglądałby płatek śniegu. W rzeczywistości nigdy nie widział płatka śniegu! Pomóżmy mu, tworząc program, który automatycznie generuje dla niego obraz 2D płatka śniegu.

Wejście

Średnica obrazu (w pikselach), procent obrazu, który w rzeczywistości jest płatkiem śniegu.

Wynik

Obraz płatka śniegu o wymaganej średnicy. Można go zapisać do pliku lub wyświetlić użytkownikowi.

Dane techniczne

Utwórz klin o kącie 30 stopni. Utwórz Drzewo Browna z początkowym nasieniem w punkcie klina. 12 razy odbij klin wokół środka obrazu, aby wygenerować resztę obrazu. Płatek śniegu ma kolor Biały. Tło ma kolor Czarny.

Punktacja

Ze względu na to, że istnieją różne sposoby generowania drzewa Browna, wynik to 10 * liczba głosów pozytywnych - wynik golfowy.

Wynik golfa jest definiowany jako liczba bajtów w programie z następującymi bonusami:

-20% Można dowolnie określić symetrię płatka śniegu.

-50% Można określić kształt płatka śniegu. (Dzięki możliwości określenia stosunku długości boków klina.)

Najwyższy wynik wygrywa.

Oto zdjęcie, jaki byłby kształt klina ze współczynnikiem około 2:

Klin

Tablica wyników:

Martin Buttner: 10 * 14 - 409 = -269

Nimi: 10 * 1-733 * .5 = -356,5

Optymalizator: 10 * 5 - 648 = -598

Zwycięzcą jest Martin z wynikiem -269!

Numer jeden
źródło
Powiązane
Martin Ender,
9
Nie rozumiem, dlaczego, jeśli rzekomo pomagamy komuś, kto nigdy nie widział płatka śniegu, wiedzieć, jak wyglądają, powinniśmy sprawić, by mieli rotacyjną symetrię porządku 4. Czy powinniśmy trollować biedaka?
Peter Taylor,
1
@ Conor „Wynik to 10 * liczba głosów pozytywnych - wynik golfa.” Ten program miałby wynik -300000000. To jest bardzo niskie.
TheNumberOne
1
Kliny 6x60 stopni! poprawa w stosunku do tego, co zostało powiedziane w czasie komentarza @PeterTaylor, ale tak naprawdę potrzebujesz klinów 12x30 stopni .. 6 dla prawej strony każdego z 6 punktów i 6 odbijanych dla lewej strony każdego punktu. BTW, nie rozumiem drugiej premii
Level River St
2
@Optimizer Gotowe, powinno być teraz jaśniejsze.
TheNumberOne

Odpowiedzi:

16

Mathematica, 409 bajtów

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

Nie golfowany:

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

Ta forma przewiduje wprowadzanie {n,p}gdzie nrozdzielczość jest w pikselach, a pudział procentowy obrazu do objęte śniegu.

Wygenerowanie płatka śniegu o podanych parametrach zajmuje około pół minuty. Możesz to przyspieszyć, zmieniając wartość mz 999na 99, ale wtedy wynik wygląda na nieco rzadszy. Podobnie, możesz zwiększyć jakość, używając większych liczb, ale wtedy zajmie to bardzo długo.

Tworzę drzewo Browna na siatce liczb całkowitych, umieszczam nowe cząstki {999, 0}i przesuwam losowo w lewo i w górę lub w dół (nie w prawo), dopóki nie uderzą w istniejące cząstki. Ograniczam również ruch do klina między 0 a 30 stopni. Na koniec odbijam ten klin na osi X i wyświetlam go z 5 obrotami.

Oto kilka wyników (kliknij, aby powiększyć):

wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj

A oto dwie animacje wzrostu drzewa Browna (10 cząstek na klin na ramkę):

wprowadź opis zdjęcia tutajwprowadź opis zdjęcia tutaj

Martin Ender
źródło
2
Wow, lubię ... właściwie wszystkie. Rezultaty są miłe!
Sp3000,
6

JavaScript, ES6, 799 740 695 658 648

Liczę tylko dwa znaczniki canvas i funkcję f z fragmentu poniżej jako część liczby bajtów. Reszta jest przeznaczona na demo na żywo

Aby obejrzeć go w akcji, po prostu uruchom poniższy fragment w najnowszym Firefoksie, podając rozmiar i stosunek za pomocą pól wprowadzania

Pamiętaj, że będziesz musiał ukryć wynik, a następnie pokazać go ponownie przed kolejnym płatkiem śniegu

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>

Oto kilka przykładowych renderów o różnych rozmiarach i wartościach procentowych. Najlepszy nazywa się SkullFlake (pierwszy na liście). Kliknij obrazy, aby zobaczyć je w pełnej rozdzielczości.

wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj

Dużo pomocy i wkładu ze strony Martina i githubphagocyte.

Optymalizator
źródło
To nie bierze procent obrazu wypełnionego jako dane wejściowe.
TheNumberOne
@TheBestOne uwzględnia teraz procent. Zwróć uwagę, że ponieważ jest to płatek śniegu oparty na drzewie Browna, ani procent, ani stosunek długości klinów nie mogą być dokładne, ponieważ w grę wchodzi rola losowości.
Optymalizator
To się teraz kwalifikuje.
TheNumberOne
1

Haskell, 781 733 bajtów

Program zawiera opcję „określ stosunek długości boków klina”, więc musisz wywołać go za pomocą trzech argumentów wiersza poleceń:

./sf 150 50 40

Argument nr 1 to rozmiar obrazu, nr 2% pikseli w klinie, a # 3 długość (w%) krótszego boku klina. Obraz jest zapisywany w pliku o nazwie „o.png”.

150–50–40: 150–50–40

Mój program produkuje płatki śniegu z odciętymi skokami, ponieważ nowe piksele zaczynają się na środkowej osi klina (zielona kropka, patrz poniżej) i mają tendencję do pozostania tam, ponieważ poruszają się one losowo w lewo, w górę lub w dół. Gdy piksele poza klinem są odrzucane, na granicy klina pojawiają się proste linie (zielona strzałka). Byłem zbyt leniwy, by wypróbować inne ścieżki dla pikseli.

150–50–40: 150–40–40e

Gdy klin jest wystarczająco duży (trzeci argument 100), kolce na środkowej osi mogą rosnąć, a następnie jest ich 12.

150–40–100: 150–40–100

Kilka pikseli tworzy okrągłe kształty (po lewej: 150-5-20; po prawej 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
źródło
@Optimizer: kolec znajduje się na środkowej osi klina. Klin przesuwa się w górę i w dół o 15 stopni w stosunku do osi x. Na *-*-100obrazie obie jego strony sięgają do lewej krawędzi obrazu (patrz położenie drugiego klina). Po około połowie boków znajdują się piksele - pozostałe połówki są puste.
nimi
1
Za pomocą tego licznika twój program ma długość 841 bajtów.
TheNumberOne
@TheBestOne: Tabs vs. Spaces podczas wcięcia. Zmieszałem je, dodając dodatkowe 4 spacje dla code style. Zredagowałem swój post i ustawiłem tabulatory, ale nadal pojawiają się jako spacje. Czy ktoś wie jak to naprawić?
nimi
@nimi Na stronie TheBestOne znajduje się #link z hashem, który można kliknąć. Możesz wkleić tam swój kod z kartami i połączyć go.
Sp3000,
Prawdopodobnie mógłbyś gdzieś utworzyć link do kodu. Do wcięcia można użyć spacji zamiast tabulatorów. Możesz ręcznie uzyskać code stylewcięcie każdego wiersza o 4 spacje.
TheNumberOne
0

Przetwarzanie 2 - 575 znaków

Pobiera plik f, którego pierwsza linia to rozmiar obrazu, a druga to promień płatków. Za każdym razem, gdy umieszczany jest nowy punkt, jest on 12 razy obracany wokół środka. Daje to bardzo podobny efekt jak obrócony klin, ale nie dokładnie taki sam.

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

wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj

możesz uzyskać przetwarzanie tutaj

bubalou
źródło
3
To nie do końca pasuje do specyfikacji. To by się kwalifikowało, gdybyś odbił punkt wokół centrum zamiast go obracać.
TheNumberOne
color(255)można color(-1)zapisać jeden bajt
Kritixi Lithos