Dessiner un flocon de neige

18

Joe vit aux Bahamas. C'est l'hiver. Ses enfants sont déçus qu'il n'y ait pas de neige. Joe a besoin de faire de la neige pour ses enfants. Heureusement, il a une imprimante 3D. Il prévoit d'en faire des flocons de neige. Malheureusement, il n'a aucune idée de l'apparence d'un flocon de neige. En fait, il n'a jamais vu de flocon de neige! Aidons-le en créant un programme qui génère automatiquement pour lui une image 2D d'un flocon de neige.

Contribution

Le diamètre de l'image (en pixels), le pourcentage de l'image qui est en fait un flocon de neige.

Production

Une image d'un flocon de neige avec le diamètre requis. Il peut être enregistré dans un fichier ou affiché pour l'utilisateur.

Caractéristiques

Créez un coin avec un angle de 30 degrés. Créez un arbre brownien avec la graine initiale au point du coin. Refléter le coin autour du centre de l'image 12 fois pour générer le reste de l'image. Le flocon de neige a la couleur blanc. Le fond a la couleur noir.

Notation

En raison du fait qu'il existe différentes façons de générer un arbre brownien, le score est de 10 * nombre de votes positifs - score de golf.

Le score de golf est défini comme le nombre d'octets dans le programme avec les bonus suivants:

-20% Peut spécifier arbitrairement la symétrie du flocon de neige.

-50% Peut spécifier la forme du flocon de neige. (En pouvant spécifier le rapport des longueurs des côtés du coin.)

Le score le plus élevé l'emporte.

Voici une image de la forme du coin avec un rapport d'environ 2:

Coin

Tableau d'affichage:

Martin Buttner: 10 * 14 - 409 = -269

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

Optimiseur: 10 * 5 - 648 = -598

Le gagnant est Martin avec un score de -269!

Le numéro un
la source
Related
Martin Ender
9
Je ne comprends pas pourquoi, si nous prétendons aider quelqu'un qui n'a jamais vu un flocon de neige à savoir à quoi il ressemble, nous sommes censés lui faire avoir une symétrie de rotation d'ordre 4. Sommes-nous censés traîner le pauvre gars?
Peter Taylor
1
@Conor "Le score est de 10 * nombre de votes positifs - score de golf." Ce programme aurait un score de -300000000. C'est très bas.
TheNumberOne
1
Cales 6x60deg! une amélioration par rapport à ce qu'elle disait au moment du commentaire de @PeterTaylor, mais en fait, vous avez besoin de 12x30deg coins .. 6 pour le côté droit de chacun des 6 points, et 6 réfléchis pour le côté gauche de chaque point. BTW, je ne comprends pas le deuxième bonus
Level River St
2
@Optimizer Done, devrait être plus clair maintenant.
TheNumberOne

Réponses:

16

Mathematica, 409 octets

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

Non golfé:

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

Cela attend la saisie du formulaire {n,p}nest la taille de l'image en pixels et ple pourcentage de l'image à couvrir par le flocon de neige.

Il faut environ une demi-minute pour générer un flocon de neige avec les paramètres donnés. Vous pouvez l'accélérer en modifiant la valeur de mde 999à 99, mais le résultat semble un peu clairsemé. De même, vous pouvez augmenter la qualité en utilisant de plus grands nombres, mais cela prendra très longtemps.

Je forme l'arbre brownien sur un réseau entier, en plaçant de nouvelles particules sur {999, 0}, et en les déplaçant au hasard vers la gauche et vers le haut ou vers le bas (pas vers la droite), jusqu'à ce qu'elles frappent les particules existantes. Je contrains également le mouvement au coin entre 0 et 30 degrés. Enfin, je réfléchis ce coin sur l'axe des x et je l'affiche avec ses 5 rotations.

Voici quelques résultats (cliquez pour agrandir):

entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici

Et voici deux animations de la croissance de l'arbre brownien (10 particules par coin par image):

entrez la description de l'image icientrez la description de l'image ici

Martin Ender
la source
2
Wow j'aime ... tous, en fait. Les résultats sont sympas!
Sp3000
6

JavaScript, ES6, 799 740 695 658 648

Je compte uniquement les deux balises canvas et la fonction fde l'extrait ci-dessous dans le cadre du décompte d'octets. Le reste est pour la démo en direct

Pour le regarder en action, il suffit d'exécuter l'extrait ci-dessous dans un dernier Firefox donnant la taille et le ratio via les zones de saisie

Notez que vous devrez masquer le résultat puis afficher à nouveau avant un flocon de neige consécutif

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>

Voici quelques exemples de rendus avec différentes tailles et pourcentages. Le meilleur s'appelle SkullFlake (premier dans la liste). Cliquez sur les images pour les voir en pleine résolution.

entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici

Beaucoup d'aide et de contribution de Martin et des githubphagocytes.

Optimiseur
la source
Cela ne prend pas le pourcentage de l'image remplie en entrée.
TheNumberOne
@TheBestOne, il prend en compte le pourcentage maintenant. Notez que puisqu'il s'agit d'un flocon de neige à base d'arbres browniens, ni le pourcentage ni le rapport des longueurs de coin ne peuvent être précis car un rôle d'aléatoire est en jeu.
Optimizer
Cela se qualifie maintenant.
TheNumberOne
1

Haskell, 781 733 octets

Le programme comporte l'option «spécifier le rapport des longueurs des côtés du coin», vous devez donc l'appeler avec trois arguments de ligne de commande:

./sf 150 50 40

L'argument # 1 est la taille de l'image, # 2 le% de pixels dans le coin et # 3 la longueur (en%) du côté le plus court du coin. L'image est enregistrée dans un fichier appelé "o.png".

150-50-40: 150-50-40

Mon programme produit des flocons de neige avec des pointes de coupure, car de nouveaux pixels commencent sur l'axe médian du coin (point vert, voir ci-dessous) et ont tendance à y rester, car ils se déplacent également de manière aléatoire vers la gauche, vers le haut ou vers le bas. Lorsque les pixels en dehors du coin sont supprimés, des lignes droites apparaissent sur la limite du coin (flèche verte). J'étais trop paresseux pour essayer d'autres chemins pour les pixels.

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

Lorsque le coin est suffisamment grand (3e argument 100), les pointes sur l'axe central peuvent grossir et il y en a 12.

150-40-100: 150-40-100

Peu de pixels font des formes rondes (gauche: 150-5-20; droite 150-20-90).

150-5-20 150-20-90

Le programme:

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
la source
@Optimizer: la pointe est sur l'axe médian du coin. Le coin monte et descend de 15 degrés par rapport à l'axe des x. Dans une *-*-100image, ses deux côtés atteignent le bord gauche de l'image (voir la deuxième image pour la position du coin). Il y a des pixels sur environ la moitié des côtés - les autres moitiés sont vides.
nimi
1
En utilisant ce compteur, votre programme a une longueur de 841 octets.
TheNumberOne
@TheBestOne: onglets vs espaces lors de la mise en retrait. Je les ai mélangés lors de l'ajout de 4 espaces supplémentaires pour code style. J'ai modifié mon article et défini des onglets, mais ils apparaissent toujours sous forme d'espaces. Quelqu'un sait-il comment y remédier?
nimi
@nimi Sur le site TheBestOne lié, il y a un petit #lien de hachage sur lequel vous pouvez cliquer. Vous pouvez y coller votre code à onglets et le lier.
Sp3000
Vous pourriez probablement faire un lien vers le code quelque part. Vous pouvez utiliser des espaces au lieu des tabulations pour mettre en retrait. Vous pouvez obtenir manuellement code styleen mettant en retrait toutes les lignes de 4 espaces.
TheNumberOne
0

Traitement de 2 à 575 caractères

Prend un fichier f dont la première ligne est la taille de l'image et la seconde le rayon des flocons. Chaque fois qu'un nouveau point est placé, il tourne autour du centre 12 fois. Cela crée un effet très similaire à un coin tourné, mais pas exactement le même.

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

entrez la description de l'image ici entrez la description de l'image ici

vous pouvez obtenir le traitement ici

bubalou
la source
3
Cela ne correspond pas tout à fait aux spécifications. Cela se qualifierait si vous réfléchissiez le point autour du centre au lieu de le faire pivoter.
TheNumberOne
color(255)peut devenir color(-1)pour économiser un octet
Kritixi Lithos