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


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.