Нарисуй снежинку


18

Джо живет на Багамах. Это зима. Его дети разочарованы тем, что снега нет. Джо должен сделать снег для своих детей. К счастью, у него есть 3-й принтер. Он планирует сделать снежинки из этого. К сожалению, он понятия не имеет, как будет выглядеть снежинка. На самом деле, он никогда не видел снежинки! Давайте поможем ему, создав программу, которая автоматически генерирует для него 2-мерное изображение снежинки.

вход

Диаметр изображения (в пикселях), процент изображения, которое на самом деле является снежинкой.

Выход

Изображение снежинки с необходимым диаметром. Он может быть сохранен в файл или отображен для пользователя.

Характеристики

Создайте клин с углом 30 градусов. Создайте броуновское дерево с начальным семенем в точке клина. Отразите клин вокруг центра изображения 12 раз, чтобы создать остальную часть изображения. Снежинка имеет цвет Белый. Фон имеет цвет Черный.

счет

В связи с тем, что существуют разные способы генерирования броуновского дерева, количество баллов составляет 10 * - количество очков в гольфе.

Оценка гольфа определяется как количество байтов в программе со следующими бонусами:

-20% Можно произвольно указать симметрию снежинки.

-50% Можно указать форму снежинки. (Имея возможность указать соотношение длин сторон клина.)

Самый высокий балл выигрывает.

Вот изображение, которое будет иметь форму клина с соотношением примерно 2:

Клин

Табло:

Мартин Буттнер: 10 * 14 - 409 = -269

Ними: 10 * 1 - 733 * .5 = -356,5

Оптимизатор: 10 * 5 - 648 = -598

Победителем стал Мартин с результатом -269!



9
Я не могу понять, почему, если якобы мы помогаем кому-то, кто никогда не видел снежинки, знать, как они выглядят, мы должны сделать так, чтобы они имели вращательную симметрию порядка 4. Должны ли мы троллить бедного парня?
Питер Тейлор

1
@Conor "Счет 10 * количество голосов - оценка по гольфу." Эта программа будет иметь оценку -300000000. Это очень низко.
TheNumberOne

1
6x60 градусов клинья! улучшение того, что было сказано во время комментария @PeterTaylor, но на самом деле вам нужны клинья 12x30 градусов. 6 для правой стороны каждой из 6 точек и 6 отраженных для левой стороны каждой точки. Кстати, я не понимаю второй бонус
Level River St

2
@Optimizer Готово, теперь должно быть понятнее.
TheNumberOne

Ответы:


16

Mathematica, 409 байтов

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

Это предполагает ввод формы, {n,p}где nнаходится размер изображения в пикселях и pпроцентное отношение изображения, которое будет покрыто снежинкой.

Генерация снежинки с заданными параметрами занимает примерно полминуты. Вы можете ускорить его, изменив значение mс 999на 99, но тогда результат выглядит немного разреженным. Аналогично, вы можете повысить качество, используя большие числа, но тогда это займет очень много времени.

Я формирую броуновское дерево на целочисленной решетке, размещаю новые частицы {999, 0}и перемещаю их случайным образом влево и вверх или вниз (не вправо), пока они не коснутся существующих частиц. Я также ограничиваю движение клином между 0 и 30 градусами. Наконец, я отражаю этот клин на оси X и показываю его с 5 поворотами.

Вот некоторые результаты (нажмите для увеличения):

введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь

А вот две анимации роста броуновского дерева (10 частиц на клин на кадр):

введите описание изображения здесьвведите описание изображения здесь


2
Ух ты, мне нравятся ... все они, на самом деле. Результаты хороши!
Sp3000

6

JavaScript, ES6, 799 740 695 658 648

Я только считаю два тега холста и функцию fиз фрагмента ниже как часть количества байтов. Остальная часть материала для живого демо

Чтобы увидеть его в действии, просто запустите приведенный ниже фрагмент в последнем Firefox, указав размер и соотношение через поля ввода

Обратите внимание, что вам придется скрыть результат, а затем показать снова перед последовательной снежинкой

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>

Вот несколько примеров рендеров с разными размерами и процентами. Лучший из них называется SkullFlake (первый в списке). Нажмите на изображения, чтобы увидеть их в полном разрешении.

введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь

Большая помощь и вклад от Мартина и githubphagocyte.


Это не берет процент от изображения, которое заполнено как ввод.
TheNumberOne

@TheBestOne теперь учитывает процент. Обратите внимание, что, поскольку это снежинка на основе броуновского дерева, ни процент, ни соотношение длин клина не могут быть точными, поскольку в игру играет роль случайности.
Оптимизатор

Это квалифицируется сейчас.
TheNumberOne

1

Haskell, 781 733 байта

В программе предусмотрена опция «указать соотношение длин сторон клина», поэтому вы должны вызывать ее с тремя аргументами командной строки:

./sf 150 50 40

Аргумент # 1 - это размер изображения, # 2 -% пикселей в клине и # 3 - длина (в%) более короткой стороны клина. Изображение сохраняется в файле с именем «o.png».

150-50-40: 150-50-40

Моя программа производит снежинки с обрезанными шипами, потому что новые пиксели начинаются на средней оси клина (зеленая точка, см. Ниже) и имеют тенденцию оставаться там, потому что они движутся одинаково случайно влево, вверх или вниз. Поскольку пиксели за пределами клина отбрасываются, на границе клина (зеленая стрелка) появляются прямые линии. Я был слишком ленив, чтобы попробовать другие пути для пикселей.

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

Когда клин достаточно большой (3-й аргумент 100), шипы на средней оси могут расти, и тогда их будет 12.

150-40-100: 150-40-100

Несколько пикселей имеют круглую форму (слева: 150-5-20; справа 150-20-90).

150-5-20 150-20-90

Программа:

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: шип находится на средней оси клина. Клин идет вверх и вниз на 15 градусов к оси х. На *-*-100изображении обе его стороны достигают левой границы изображения (положение клина см. На втором изображении). Примерно на половине сторон расположены пиксели, остальные половины пусты.
Ними

1
Используя этот счетчик, ваша программа имеет длину 841 байт.
TheNumberOne

@TheBestOne: табуляция и пробел при отступе. Я перепутал их при добавлении дополнительных 4 пробелов для code style. Я отредактировал свой пост и установил вкладки, но они все еще отображаются в виде пробелов. Кто-нибудь знает как это исправить?
Ними

@nimi На сайте TheBestOne есть небольшая хеш- #ссылка, по которой можно щелкнуть. Вы можете вставить свой код с вкладками туда и связать его.
Sp3000

Возможно, вы могли бы сделать ссылку на код где-нибудь. Вы можете использовать пробелы вместо вкладок для отступа. Вы можете вручную получить code styleпутем отступа в каждой строке 4 пробела.
TheNumberOne

0

Обработка 2 - 575 символов

Принимает файл f, первая строка которого представляет собой размер изображения, а вторая - радиус чешуек. Каждый раз, когда ставится новая точка, она вращается вокруг центра 12 раз. Это создает эффект, очень похожий на вращающийся клин, но не совсем такой же.

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

введите описание изображения здесь введите описание изображения здесь

Вы можете получить обработку здесь


3
Это не совсем соответствует спецификациям. Это было бы правильно, если бы вы отражали точку вокруг центра, а не вращали ее.
TheNumberOne

color(255)может стать color(-1)для сохранения одного байта
Kritixi Lithos
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.