Eine Schneeflocke zeichnen


18

Joe lebt auf den Bahamas. Es ist Winter. Seine Kinder sind enttäuscht, dass es keinen Schnee gibt. Joe muss Schnee für seine Kinder machen. Zum Glück hat er einen 3D-Drucker. Er hat vor, damit Schneeflocken zu machen. Leider hat er keine Ahnung, wie eine Schneeflocke aussehen würde. Tatsächlich hat er noch nie eine Schneeflocke gesehen! Lassen Sie uns ihm helfen, indem wir ein Programm erstellen, das automatisch ein 2D-Bild einer Schneeflocke für ihn erstellt.

Eingang

Der Durchmesser des Bildes (in Pixel), der Prozentsatz des Bildes, bei dem es sich tatsächlich um eine Schneeflocke handelt.

Ausgabe

Ein Bild einer Schneeflocke mit dem erforderlichen Durchmesser. Es kann in einer Datei gespeichert oder dem Benutzer angezeigt werden.

Spezifikationen

Erstellen Sie einen Keil mit einem Winkel von 30 Grad. Erstellen Sie einen Brownschen Baum mit dem ersten Samen an der Stelle des Keils. Reflektieren Sie den Keil 12 Mal um die Bildmitte, um den Rest des Bildes zu erzeugen. Die Schneeflocke hat die Farbe Weiß. Der Hintergrund hat die Farbe Schwarz.

Wertung

Aufgrund der Tatsache, dass es verschiedene Möglichkeiten gibt, einen Brownian Tree zu generieren, beträgt die Punktzahl 10 * Anzahl der Upvotes - Golf-Punkte.

Golf Score ist definiert als die Anzahl der Bytes im Programm mit den folgenden Boni:

-20% Kann die Symmetrie der Schneeflocke beliebig festlegen.

-50% Kann die Form der Schneeflocke angeben. (Indem Sie das Verhältnis der Längen der Seiten des Keils angeben können.)

Höchste Punktzahl gewinnt.

Hier ist ein Bild, wie die Form des Keils bei einem Verhältnis von ungefähr 2 aussehen würde:

Keil

Anzeigetafel:

Martin Buttner: 10 * 14 - 409 = -269

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

Optimierer: 10 * 5 - 648 = -598

Der Gewinner ist Martin mit der Punktzahl -269!



9
Ich kann nicht verstehen, warum wir, wenn wir angeblich jemandem helfen, der noch nie eine Schneeflocke gesehen hat, zu wissen, wie sie aussieht, eine Rotationssymmetrie der Ordnung 4 erzeugen sollen. Sollen wir den armen Kerl trollen?
Peter Taylor

1
@Conor "Die Punktzahl ist 10 * Anzahl der Upvotes - Golfscore." Dieses Programm hätte eine Punktzahl von -300000000. Das ist sehr gering.
TheNumberOne

1
6x60deg Wedges! Dies ist eine Verbesserung gegenüber dem, was zum Zeitpunkt von @PeterTaylors Kommentar gesagt wurde. Tatsächlich benötigen Sie jedoch 12 x 30 Grad Keile. 6 für die rechte Seite jedes der 6 Punkte und 6 reflektierte für die linke Seite jedes Punktes. Übrigens verstehe ich den zweiten Bonus nicht
Level River St

2
@Optimizer Fertig, sollte jetzt klarer sein.
TheNumberOne

Antworten:


16

Mathematica, 409 Bytes

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

Dies setzt voraus, dass Sie das Formular eingeben, {n,p}bei dem nes sich um die Bildgröße in Pixel und pden Prozentsatz des Bildes handelt, der von der Schneeflocke bedeckt werden soll.

Es dauert ungefähr eine halbe Minute, um eine Schneeflocke mit den angegebenen Parametern zu erzeugen. Sie können es beschleunigen, indem Sie den Wert von mvon 999bis ändern 99, aber dann sieht das Ergebnis etwas spärlich aus. Ebenso können Sie die Qualität erhöhen, indem Sie größere Zahlen verwenden, aber dann dauert es sehr lange.

Ich bilde den Brownschen Baum auf einem ganzzahligen Gitter, platziere neue Partikel an {999, 0}und bewege die zufällig nach links und oben oder unten (nicht nach rechts), bis sie auf die vorhandenen Partikel treffen. Ich beschränke auch die Bewegung auf den Keil zwischen 0 und 30 Grad. Schließlich reflektiere ich diesen Keil auf der x-Achse und zeige ihn mit seinen 5 Umdrehungen an.

Hier sind einige Ergebnisse (zum Vergrößern anklicken):

Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben

Und hier sind zwei Animationen des wachsenden Brownschen Baumes (10 Partikel pro Keil pro Frame):

Bildbeschreibung hier eingebenBildbeschreibung hier eingeben


2
Wow, ich mag ... eigentlich alle. Die Ergebnisse sind schön!
Sp3000

6

JavaScript, ES6, 799 740 695 658 648

Ich zähle nur die beiden Canvas-Tags und die Funktion faus dem folgenden Snippet als Teil der Byteanzahl. Der Rest des Materials ist für Live-Demo

Um es in Aktion zu sehen, führen Sie einfach das folgende Snippet in einem aktuellen Firefox aus und geben Sie die Größe und das Verhältnis über die Eingabefelder an

Beachten Sie, dass Sie das Ergebnis ausblenden müssen, bevor Sie eine Schneeflocke sehen

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>

Hier einige Beispiele für Renderings mit unterschiedlichen Größen und Prozentsätzen. Der beste heißt SkullFlake (erster in der Liste). Klicken Sie auf die Bilder, um sie in voller Auflösung anzuzeigen.

Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben

Viel Hilfe und Input von Martin und Githubphagozyten.


Hierbei wird nicht der Prozentsatz des Bildes als Eingabe verwendet.
TheNumberOne

@TheBestOne wird jetzt prozentual berücksichtigt. Da es sich um eine Schneeflocke auf Brown'scher Baumbasis handelt, können weder der Prozentsatz noch das Verhältnis der Keillängen genau sein, da die Zufälligkeit eine Rolle spielt.
Optimierer

Dies ist jetzt qualifiziert.
TheNumberOne

1

Haskell, 781 733 Bytes

Das Programm bietet die Option „Geben Sie das Verhältnis der Seitenlängen des Keils an“, sodass Sie es mit drei Befehlszeilenargumenten aufrufen müssen:

./sf 150 50 40

Argument Nr. 1 ist die Größe des Bildes, Nr. 2 der Prozentsatz der Pixel im Keil und Nr. 3 die Länge (in%) der kürzeren Seite des Keils. Das Bild wird in einer Datei mit dem Namen „o.png“ gespeichert.

150-50-40: 150-50-40

Mein Programm erzeugt Schneeflocken mit abgeschnittenen Spitzen, weil neue Pixel auf der Mittelachse des Keils beginnen (grüner Punkt, siehe unten) und dort bleiben, weil sie sich nach links, oben oder unten gleichermaßen zufällig bewegen. Wenn Pixel außerhalb des Keils verworfen werden, erscheinen gerade Linien an der Grenze des Keils (grüner Pfeil). Ich war zu faul, um andere Pfade für die Pixel auszuprobieren.

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

Wenn der Keil groß genug ist (3. Argument 100), können die Stacheln auf der Mittelachse wachsen und dann gibt es 12 von ihnen.

150-40-100: 150-40-100

Nur wenige Pixel ergeben runde Formen (links: 150-5-20; rechts: 150-20-90).

150-5-20 150-20-90

Das Programm:

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: Der Dorn befindet sich auf der Mittelachse des Keils. Der Keil bewegt sich um 15 Grad zur x-Achse auf und ab. In einem *-*-100Bild reichen beide Seiten bis zum linken Rand des Bildes (siehe das zweite Bild für die Position des Keils). Ungefähr auf der Hälfte der Seiten befinden sich Pixel - die anderen Hälften sind leer.
Nimi

1
Mit diesem Zähler hat Ihr Programm eine Länge von 841 Bytes.
TheNumberOne

@TheBestOne: Tabulatoren und Leerzeichen beim Einrücken. Ich habe sie vertauscht, wenn ich 4 zusätzliche Leerzeichen für hinzufüge code style. Ich habe meinen Beitrag bearbeitet und Tabs festgelegt, sie werden jedoch weiterhin als Leerzeichen angezeigt. Weiß jemand, wie man es repariert?
nimi

@nimi Auf der Seite, die mit TheBestOne verlinkt ist, gibt es einen kleinen Hash- #Link, auf den Sie klicken können. Sie können Ihren Code mit Registerkarten dort einfügen und verknüpfen.
Sp3000,

Sie könnten wahrscheinlich irgendwo einen Link zum Code erstellen. Sie können Leerzeichen anstelle von Tabulatoren zum Einrücken verwenden. Sie könnten manuell code styledurch Einziehen jeder Zeile 4 Leerzeichen erhalten.
TheNumberOne

0

Verarbeitung 2 - 575 Zeichen

Nimmt eine Datei auf, deren erste Zeile die Bildgröße und die zweite den Flockenradius angibt. Jedes Mal, wenn ein neuer Punkt platziert wird, wird er 12 Mal um die Mitte gedreht. Dies erzeugt einen sehr ähnlichen Effekt wie ein gedrehter Keil, aber nicht genau den gleichen.

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

Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben

Sie können erhalten die Verarbeitung hier


3
Dies entspricht nicht ganz den Spezifikationen. Dies würde qualifizieren, wenn Sie den Punkt um die Mitte spiegeln, anstatt ihn zu drehen.
TheNumberOne

color(255)kann werden color(-1), um ein Byte zu speichern
Kritixi Lithos
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.