Мне нравятся пифагорейские деревья


17

... так что это задача сделать меня деревом.

Создайте программу или функцию с именем tree, которая принимает один целочисленный аргумент N и рисует пифагорейское дерево N уровня глубоко, где уровень 0 - это просто ствол.

Каждое соединение дерева должно располагать вершину треугольника в случайной точке по периметру (эта точка должна быть равномерно распределена по крайней мере по 5 одинаково разнесенным точкам или равномерно по всему полукругу).

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

РЕДАКТИРОВАТЬ: я закрою конкурс и приму самый маленький ответ, когда ему неделя



Ложь. Я по другому алгоритму :)
— Александр-Бретт

Ok. Справедливо. Вы можете рассмотреть вопрос о повторном представлении «Пифагорейского дерева».
— DavidC

Мне нравятся поезда? :)
— Томсминг

Ответы:


15

Mathematica, 246 234 221 символов

g[n_,s_:1]:={p=RandomReal[q=Pi/2],r=##~Rotate~(o={0,0})&,t=Translate}~With~If[n<0,{},Join[#~t~{0,s}&/@(#~r~p&)/@g[n-1,s*Cos@p],t[#,s{Cos@p^2,1+Sin[2p]/2}]&/@(r[#,p-q]&)/@g[n-1,s*Sin@p],{Rectangle[o,o+s]}]]
f=Graphics@g@#&

Это, конечно, не самый элегантный / самый короткий способ сделать это.

Использование: f[8]

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

А вот пример выходов для f[6]и f[10]соответственно.

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

Немного негольфя

g[n_, s_:1] := With[{p},
  r = Rotate;
  t = Translate;
  p = RandomReal[q = Pi/2];
  If[n < 0, {},
   Join[
    (t[#, {0, s}] &) /@ (r[#, p, {0, 0}] &) /@ g[n - 1, s*Cos[p]],
    (t[#, s {Cos[p]^2, 1 + Sin[2 p]/2}] &) /@ (r[#, p - q, {0, 0}] &) /@
       g[n - 1, s*Sin[p]],
    {Rectangle[{0, 0}, {s, s}]}
    ]
   ]
  ]
f = Graphics@g[#] &

Это впечатляет. Жаль, у меня нет mathematica для его проверки - не могли бы вы добавить еще пару примеров выходных данных?
— Александр-Бретт

@ ali0sha смотри правку
— Мартин Эндер

Вам не нужно Showтам, и Moduleэто также не нужно.
— swish

@swish Спасибо за Showподсказку, но как мне избавиться Module? Если я не объявлю pлокальный, он будет перезаписан в рекурсивных вызовах, поэтому я не смог сделать оба вызова с одним и тем же p, верно?
— Мартин Эндер

@ m.buettner Может быть, вы можете использовать Block, который короче, чем Module.
— алефалия

20

CFDG, 134 знака

Это не совсем верно, потому что вы не можете ограничить глубину рекурсии. Но проблема просто требует решения в этом . :)

startshape t
c(q)=cos(q/2)^2
d(q)=1+sin(q)/2
p=acos(-1)
shape t{w=rand(p)
SQUARE[x .5 .5]t[trans 0 1 c(w) d(w)]t[trans c(w) d(w) 1 1]}

Результаты выглядят примерно так

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

Еще для 46 символов (всего 180 символов ) вы можете даже раскрасить его:

startshape t
c(q)=cos(q/2)^2
d(q)=1+sin(q)/2
p=acos(-1)
shape t{w=rand(p)
SQUARE[x .5 .5 h 25 sat 1 b .2]t[trans 0 1 c(w) d(w) b .08 .8 h 2.2]t[trans c(w) d(w) 1 1 b .08 .8 h 2.2]}

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


Я знаю, что это не совсем онтоп, но как будет выглядеть версия, если вместо «белого шума» вы используете «коричневый шум» в качестве углов?
— 14ıʇǝɥʇuʎs

@ Synthetica Вы имеете в виду, что угол наклона больше 90 ° и меньше на 0 и 180?
— Мартин Эндер

@ Synthetica похоже на это . Я не смог реализовать реальный шум случайного блуждания, потому что для этого нужно взять входной параметр (последнее случайное значение), настроить его и передать. Это делает грамматику контекстно-зависимой и, следовательно, не поддерживается CFDG. Я слегка притворялся, просто толкая случайные значения немного больше к π / 2, используя простую кубическую функцию на случайной выборке.
— Мартин Эндер

Я думаю, что ваша imgur-связь нарушена, а также, несмотря на то, что мне нравятся цвет и форма, я думаю, что должен дисквалифицировать эту по той причине, о которой вы упомянули
— alexander-brett

@ ali0sha ты прав, вот фиксированная ссылка . Дисквалификация этого абсолютно справедлива, я просто хотел поделиться с людьми контекстным искусством, и это выглядело как аккуратный подход к проблеме. ;) ... Ну, я до сих пор получил ответ Mathematica ^^
— Мартин Эндер

4

Постскриптум, 322 270

Редактировать: кажется, что realtimeне может быть использован в качестве правильного случайного генератора семян. Поэтому мы будем использовать переменную окружения для этой цели и запустим программу следующим образом:

gs -c 20 $RANDOM -f tree.ps

или

gswin32c -c 20 %RANDOM% -f tree.ps

Теперь наши деревья менее предсказуемы. 14 байтов добавляются к общему количеству. Другие изменения: 1) Программный аргумент теперь передается в командной строке. 2) Нет явного счетчика итераций - размер стека служит для этой цели (угол поворота левой ветви сохраняется в стеке, для рисования правой ветви позже). 3) Для требуемой глубины нет именованной переменной - размер стека - это его смещение в стеке. Он остается там на выходе, то есть не потребляется.

srand
250 99 translate
50 50 scale
/f{
    count
    dup index div dup 1 le{
        0 exch 0 setrgbcolor
        0 0 1 1 rectfill
        0 1 translate
        rand 5 mod 1 add 15 mul
        gsave
        dup rotate
        dup cos dup scale
        f
        grestore
        dup cos dup dup mul
        exch 2 index sin mul translate
        dup 90 sub rotate
        sin dup scale 1
        f
        pop
    }{pop}ifelse
}def
f

Я думаю, что это довольно очевидно - состояние графики подготовлено и fпроцедура вызывается рекурсивно для каждого последовательного уровня глубины, дважды - для «левой» и «правой» ветвей. Работа с прямоугольником1x1 размера (см. Исходный масштаб) избавляет от необходимости умножения на длину стороны. Угол поворота левой ветви рандомизирован - используется одно из 5 случайных равноотстоящих делений - я думаю, что это предотвращает возможные уродливые случаи для равномерной случайности.

Это может быть медленно для необходимой глубины более 20 или около того.

Далее следует версия для игры в гольф, использующая двоичные токены в кодировке ASCII (см. Ответ luser droog из связанной темы). Обратите внимание, cos, sin, randне могут использовать эти обозначения.

/${{<920>dup 1 4 3 roll put cvx exec}forall}def srand 250 99<AD>$ 50 50<8B>$/f{count(8X68)$ 1 le{0(>)$ 0<9D>$ 0 0 1 1<80>$ 0 1<AD>$ rand 5 mod 1 add 15<~CecsG2u~>$ cos<388B>$ f(M8)$ cos(88l>)$ 2(X)$ sin<6CAD38>$ 90<A988>$ sin<388B>$ 1 f pop}{pop}(U)$}def f

,

/${{<920>dup 1 4 3 roll put cvx exec}forall}def
srand
250 99<AD>$
50 50<8B>$
/f{
count(8X68)$
1 le{
0(>)$ 0<9D>$
0 0 1 1<80>$
0 1<AD>$
rand 5 mod 1 add 15 
<~CecsG2u~>$
cos<388B>$ 
f
(M8)$
cos(88l>)$
2(X)$ sin<6CAD38>$
90<A988>$ sin<388B>$
1
f
pop
}{pop}(U)$
}def
f

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


Я думаю, что стиль здесь заключается в том, что необходимо добавить аргументы командной строки, чтобы получить 344 балла ... Я должен сказать, что даже по стандартам codegolf это выглядит довольно внушительно. Как далеко вы можете получить это с двоичными токенами? Вы не далеко от Mathematica, конечно,
— Александр-Бретт

@ ali0sha -dGraphicsAlphaBits- это флаг для вывода сглаживания, чтобы предотвратить появление неровных краев больших квадратов, его можно опустить (или «скрыть», например, в переменной среды). Некоторым людям это может нравиться больше без этого флага (листья деревьев получают больше «объема»). Ну, эти 20 байтов не так уж и важны. Я бы сказал, что скидка 20-25% - использование двоичных токенов в кодировке ascii (судя по ответу по теме) Может быть, скидка 50% без ascii-кодирования, 2 двоичных байта на маркер имени системы. Будут похожи на некоторые обычно выигрышные языки;)
— user2846289

Я думаю, что вы должны сделать это - сделать это немного более конкурентоспособным здесь :)
— alexander-brett

3

Coffeescript 377B 352B

Я чувствую себя грязно, пишу coffeescript, но не могу найти приличный пакет для рисования для python3: - /

Q=(n)->X=(D=document).body.appendChild(C=D.createElement('Canvas')).getContext('2d');C.width=C.height=400;M=Math;T=[[175,400,50,i=0]];S=M.sin;C=M.cos;while [x,y,l,a]=T[i++]
 X.save();X.translate x,y;X.rotate -a;X.fillRect 0,-l,l,l;X.restore();T.push [e=x-l*S(a),f=y-l*C(a),g=l*C(b=M.random()*M.PI/2),d=a+b],[e+g*C(d),f-g*S(d),l*S(b),d-M.PI/2] if i<2**n

Javascript 393B 385B

Немного красивее в javascript, и я гораздо счастливее с циклом for, но без синтаксиса [x, y, z] = A, я просто не могу сделать его достаточно коротким, чтобы превзойти coffeescript

function Q(n){X=(D=document).body.appendChild(C=D.createElement('Canvas')).getContext('2d');C.width=C.height=600;M=Math;T=[[275,400,50,i=0]];while(A=T[i++]){X.save();X.translate(x=A[0],y=A[1]);X.rotate(-(a=A[3]));X.fillRect(0,-(l=A[2]),l,l);X.restore();S=M.sin;C=M.cos;i<M.pow(2,n)&&T.push([e=x-l*S(a),f=y-l*C(a),g=l*C(b=M.random()*M.PI/2),d=a+b],[e+g*C(d),f-g*S(d),l*S(b),d-M.PI/2])}}

Должен сказать, я немного раздражен, это почти вдвое дольше, чем решение Mathematica: - / увидеть его в действии: http://jsfiddle.net/FK2NX/3/


Несколько советов: Вы можете сохранить не менее 16 символов, используя точки с запятой вместо разрывов строк в CoffeeScript. В обоих случаях, если любой из методов при Xвозврате X, вы можете связать их. И вы можете сохранить еще одну хорошую группу символов, сохраняя M.sinи M.cosв односимвольных переменных.
— Мартин Эндер

К сожалению, контекстные операции не возвращают контекст, который меня очень расстроил. Также вы можете переименовать M.sin в Ms, но строка Ms = M.sin занимает больше символов, чем сохраняет ... Я посмотрю, как убирать пробелы.
— Александр-Бретт

Нет, ты можешь просто сделать s=M.sin.
— Мартин Эндер

Почему я могу сделать S = M.sin, но не R = X.rotate?
— Александр-Бретт

Я полагаю, rotateиспользует thisи sinне делает. Вам нужно сделать что-то подобное R=X.rotate.bind(X), но это, вероятно, не стоит больше.
— Мартин Эндер
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.