Disegna un fiocco di neve


18

Joe vive alle Bahamas. È inverno. I suoi figli sono delusi dal fatto che non ci sia neve. Joe deve fare la neve per i suoi figli. Fortunatamente, ha una stampante 3D. Ha in programma di fare dei fiocchi di neve con esso. Sfortunatamente non ha idea di come sarebbe un fiocco di neve. In realtà, non ha mai visto un fiocco di neve! Aiutiamolo creando un programma che genera automaticamente una 2d immagine di un fiocco di neve per lui.

Ingresso

Il diametro dell'immagine (in pixel), la percentuale dell'immagine che è in realtà un fiocco di neve.

Produzione

L'immagine di un fiocco di neve con il diametro richiesto. Può essere salvato in un file o visualizzato all'utente.

specificazioni

Crea un cuneo con un angolo di 30 gradi. Crea un albero browniano con seme iniziale nel punto del cuneo. Rifletti il ​​cuneo intorno al centro dell'immagine 12 volte per generare il resto dell'immagine. Il fiocco di neve ha il colore Bianco. Lo sfondo ha il colore Nero.

punteggio

A causa del fatto che ci sono diversi modi per generare un albero browniano, il punteggio è 10 * numero di voti - punteggio golf.

Il punteggio di golf è definito come il numero di byte nel programma con i seguenti bonus:

-20% Può specificare arbitrariamente la simmetria del fiocco di neve.

-50% Può specificare la forma del fiocco di neve. (Potendo specificare il rapporto tra le lunghezze dei lati del cuneo.)

Il punteggio più alto vince.

Ecco un'immagine quale sarebbe la forma del cuneo con il rapporto di circa 2:

Cuneo

Pagelle:

Martin Buttner: 10 * 14 - 409 = -269

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

Ottimizzatore: 10 * 5 - 648 = -598

Il vincitore è Martin con il punteggio -269!



9
Non riesco a capire perché, se presumibilmente stiamo aiutando qualcuno che non ha mai visto un fiocco di neve a sapere che aspetto hanno, dovremmo farli avere una simmetria rotazionale dell'ordine 4. Dovremmo trollare il povero ragazzo?
Peter Taylor,

1
@Conor "Il punteggio è 10 * numero di voti - punteggio di golf." Quel programma avrebbe un punteggio di -300000000. Questo è molto basso.
TheNumberOne,

1
Zeppe 6x60deg! un miglioramento su ciò che ha detto al momento del commento di @PeterTaylor, ma in realtà hai bisogno di zeppe da 12x30 gradi .. 6 per il lato destro di ciascuno dei 6 punti e 6 riflessi per il lato sinistro di ogni punto. A proposito, non capisco il secondo bonus
Level River St

2
@Optimizer Fatto, dovrebbe essere più chiaro ora.
TheNumberOne

Risposte:


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]

Ungolfed:

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

Ciò prevede di immettere il modulo in {n,p}cui si ntrova la dimensione dell'immagine in pixel ed pè la percentuale dell'immagine che deve essere coperta dal fiocco di neve.

Ci vuole qualcosa come mezzo minuto per generare un fiocco di neve con i parametri indicati. Puoi accelerarlo modificando il valore di mda 999a 99, ma il risultato appare un po 'scarso. Allo stesso modo, puoi aumentare la qualità usando numeri più grandi, ma poi ci vorrà molto tempo.

Sto formando l'albero browniano su un reticolo intero, posizionando nuove particelle {999, 0}e spostando casualmente verso sinistra e verso l'alto o verso il basso (non verso destra), fino a quando non colpiscono le particelle esistenti. Sto anche vincolando il movimento al cuneo tra 0 e 30 gradi. Infine, rifletto quel cuneo sull'asse x e lo visualizzo con le sue 5 rotazioni.

Ecco alcuni risultati (clicca per una versione più grande):

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

Ed ecco due animazioni della crescita dell'albero browniano (10 particelle per cuneo per fotogramma):

inserisci qui la descrizione dell'immagineinserisci qui la descrizione dell'immagine


2
Wow mi piace ... tutti loro, in realtà. I risultati sono buoni!
Sp3000,

6

JavaScript, ES6, 799 740 695 658 648

Conto solo i due tag canvas e la funzione fdello snippet di seguito come parte del conteggio byte. Il resto è per la demo live

Per vederlo in azione, basta eseguire lo snippet di seguito in un ultimo Firefox che fornisce le dimensioni e il rapporto tramite le caselle di input

Nota che dovrai nascondere il risultato e mostrarlo di nuovo prima di un fiocco di neve consecutivo

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>

Ecco alcuni rendering di esempio con dimensioni e percentuali diverse. Il migliore si chiama SkullFlake (primo nella lista). Fai clic sulle immagini per vederle a piena risoluzione.

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

Un sacco di aiuto e input da Martin e githubphagocyte.


Questo non prende la percentuale dell'immagine che viene riempita come input.
TheNumberOne

@TheBestOne ora tiene conto della percentuale. Si noti che poiché si tratta di un fiocco di neve a base di albero browniano, né la percentuale né il rapporto per le lunghezze del cuneo possono essere accurati poiché è in gioco un ruolo di casualità.
Ottimizzatore

Questo si qualifica ora.
TheNumberOne

1

Haskell, 781 733 byte

Il programma presenta l'opzione "specifica il rapporto tra le lunghezze dei lati del cuneo", quindi devi chiamarlo con tre argomenti della riga di comando:

./sf 150 50 40

L'argomento n. 1 è la dimensione dell'immagine, n. 2 la percentuale di pixel nel cuneo e n. 3 la lunghezza (in%) del lato più corto del cuneo. L'immagine viene salvata in un file chiamato "o.png".

150-50-40: 150-50-40

Il mio programma produce fiocchi di neve con punte tagliate, perché i nuovi pixel iniziano sull'asse centrale del cuneo (punto verde, vedi sotto) e tendono a rimanere lì, perché si muovono ugualmente casuali a sinistra, su o giù. Man mano che i pixel esterni al cuneo vengono scartati, le linee rette appaiono sul bordo del cuneo (freccia verde). Ero troppo pigro per provare altri percorsi per i pixel.

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

Quando il cuneo è abbastanza grande (3 ° argomento 100) i picchi sull'asse centrale possono crescere e poi ce ne sono 12.

150-40-100: 150-40-100

Pochi pixel formano forme rotonde (a sinistra: 150-5-20; a destra 150-20-90).

150-5-20 150-20-90

Il programma:

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: il picco si trova sull'asse centrale del cuneo. Il cuneo sale e scende di 15 gradi rispetto all'asse x. In *-*-100un'immagine entrambi i lati raggiungono il bordo sinistro dell'immagine (vedere la seconda immagine per la posizione del cuneo). Ci sono pixel su circa la metà dei lati - le altre metà sono vuote.
nimi

1
Usando questo contatore il tuo programma ha una lunghezza di 841 byte.
TheNumberOne

@TheBestOne: Tab contro Spazi durante il rientro. Li ho mescolati quando ho aggiunto altri 4 spazi per code style. Ho modificato il mio post e impostato Tab, ma appaiono comunque come spazi. Qualcuno sa come aggiustarlo?
nimi

@nimi Sul sito TheBestOne collegato c'è un piccolo #link hash su cui puoi fare clic. Puoi incollare qui il tuo codice a schede e collegarlo.
Sp3000,

Probabilmente potresti creare un link al codice da qualche parte. È possibile utilizzare gli spazi anziché le schede per rientrare. È possibile ottenere manualmente code stylerientrando in ogni riga 4 spazi.
TheNumberOne

0

Elaborazione 2 - 575 caratteri

Comprende un file f la cui prima riga è la dimensione dell'immagine e la seconda è il raggio dei fiocchi. Ogni volta che viene posizionato un nuovo punto, questo viene ruotato attorno al centro 12 volte. Questo crea un effetto molto simile a un cuneo ruotato, ma non esattamente lo stesso.

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

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

puoi ottenere l'elaborazione qui


3
Questo non si adatta perfettamente alle specifiche. Ciò si qualificherebbe se si riflettesse il punto attorno al centro invece di ruotarlo.
TheNumberOne il

color(255)può diventare color(-1)per salvare un byte
Kritixi Lithos il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.