Lubię pitagorejskie drzewa

17

... więc jest to wyzwanie, aby uczynić mnie drzewem.

Utwórz program lub funkcję o nazwie drzewo, która pobiera pojedynczy argument liczby całkowitej, N i rysuje Drzewo Pitagorejskie na poziomach N, gdzie poziom 0 to tylko pień.

Każde skrzyżowanie drzewa powinno umieszczać wierzchołek trójkąta w losowym punkcie na obwodzie (ten punkt powinien być równomiernie rozmieszczony w co najmniej 5 równo rozmieszczonych punktach lub równomiernie na całym półkolu).

Opcjonalnie twoje drzewo może być 3d, być kolorowe lub być oświetlone zgodnie z porą dnia. Jest to jednak gra w golfa, więc wygrywa najmniejszy plik.

EDYCJA: Zamknę konkurs i przyjmuję najmniejszą odpowiedź, gdy będzie miała tydzień

Alexander-Brett
źródło
Wygląda
DavidC
Fałszywy. Poszukuję innego algorytmu :)
Alexander-Brett
Dobrze. Słusznie. Możesz rozważyć ponowne przesłanie swojego zgłoszenia do „Drzewa pitagorejskiego”.
DavidC
Lubię pociągi? :)
tomsmeding

Odpowiedzi:

15

Mathematica, 246 234 221 znaków

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@#&

Z pewnością nie jest to najbardziej elegancki / najkrótszy sposób na zrobienie tego.

Stosowanie: f[8]

wprowadź opis zdjęcia tutaj

A oto przykładowe wyniki dla f[6]i f[10]odpowiednio.

wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj

Nieco golfisty:

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[#] &
Martin Ender
źródło
To całkiem imponujące. Szkoda, że ​​nie mam matematyki do przetestowania - czy mógłbyś dodać jeszcze kilka przykładowych wyników?
Alexander-brett
@ ali0sha patrz edycja
Martin Ender
Nie potrzebujesz Showtam i Modulejest to również niepotrzebne.
świst
@swish Dzięki za Showpodpowiedź, ale jak mogę się tego pozbyć Module? Jeśli nie podam adresu plokalnego, zostanie on nadpisany w połączeniach rekurencyjnych, więc nie mogę wykonać obu połączeń z tym samym p, prawda?
Martin Ender
@ m.buettner Może możesz użyć Block, który jest krótszy niż Module.
alephalpha
20

CFDG, 134 znaki

Ten nie jest dokładnie poprawny, ponieważ nie można ograniczyć głębokości rekurencji. Ale problem wymaga tylko rozwiązania tego problemu . :)

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

Wyniki wyglądają mniej więcej tak

wprowadź opis zdjęcia tutaj

W przypadku kolejnych 46 znaków ( łącznie 180 znaków ) możesz nawet pokolorować:

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

wprowadź opis zdjęcia tutaj

Martin Ender
źródło
Wiem, że nie jest to w pełni tematyczne, ale jak wyglądałaby wersja, gdyby zamiast „białego szumu” użyć „brązowego szumu” jako kątów?
30ıʇǝɥʇuʎs
@Synthetica masz na myśli więcej kątów około 90 ° i mniej przy 0 i 180?
Martin Ender
@Synthetica Podobne do tego . Nie mogłem zaimplementować rzeczywistego szumu, ponieważ wymaga to przyjęcia parametru wejściowego (ostatniej wartości losowej), dostosowania go i przekazania. Sprawiłoby to, że gramatyka byłaby zależna od kontekstu i dlatego nie jest obsługiwana przez CFDG. Lekko to sfałszowałem, po prostu przesuwając wartości losowe nieco bardziej w stronę π / 2, używając prostej funkcji sześciennej na losowej próbce.
Martin Ender
Myślę, że twoje łącze imgur jest zerwane, a także bardzo podoba mi się kolor i kształt, myślę, że muszę zdyskwalifikować ten z powodu, o którym wspomniałeś
Alexander-Brett
@ ali0sha masz rację, oto stały link . Dyskwalifikacja tego jest absolutnie sprawiedliwa, chciałem po prostu podzielić się Wolną Kontekstem z niektórymi ludźmi i wydawało się to dobrym podejściem do problemu. ;) ... Cóż, wciąż mam odpowiedź Mathematica ^^
Martin Ender
4

Postscriptum, 322 270

Edycja: Wygląda na to, że realtimenie można go użyć jako właściwego losowego generatora. Dlatego użyjemy do tego celu zmiennej środowiskowej i uruchomimy program w następujący sposób:

gs -c 20 $RANDOM -f tree.ps

lub

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

Teraz nasze drzewa są mniej przewidywalne. 14 bajtów dodaje się do łącznej liczby. Inne zmiany: 1) Argument programu jest teraz przekazywany w wierszu poleceń. 2) Do tego celu nie służy jawny rozmiar stosu licznika iteracji (kąt obrotu lewej gałęzi jest zapisywany na stosie, aby później narysować prawą gałąź). 3) Nie ma nazwanej zmiennej dla wymaganej głębokości - rozmiar stosu to jego przesunięcie na stosie. Zostaje tam przy wyjściu, tzn. Nie jest zużywany.

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

Myślę, że to dość oczywiste - stan grafiki jest przygotowany, a fprocedura jest wywoływana rekurencyjnie dla każdego kolejnego poziomu głębokości, dwa razy - dla gałęzi „lewej” i „prawej”. Praca z prostokątem o 1x1rozmiarze (patrz oryginalna skala) pozwala uniknąć mnożenia przez długość boku. Kąt obrotu lewej gałęzi jest losowy - stosuje się jeden z 5 losowych równomiernie rozmieszczonych podziałów - myślę, że zapobiega możliwym brzydkim przypadkom równomiernej losowości.

Wymagana głębokość może wynosić ponad 20 lub więcej.

Następna jest wersja golfowa, wykorzystująca tokeny binarne zakodowane w ASCII (patrz odpowiedź luser droog z połączonego tematu). Uwaga, cos, sin, randnie mogą korzystać z tego zapisu.

/${{<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

wprowadź opis zdjęcia tutaj

użytkownik 2846289
źródło
Myślę, że styl polega na tym, że argumenty wiersza poleceń muszą być dodane, więc te wyniki 344 ... Muszę powiedzieć, że nawet według standardów codegolf jest to dość imponująco zagraniczne. Jak daleko można to zrobić za pomocą binarnych tokenów? Na pewno nie jesteś daleko od Mathematica
Alexander-Brett
@ ali0sha, -dGraphicsAlphaBitsjest flagą na wyjściu anty-aliasu, aby zapobiec postrzępionym krawędziom większych kwadratów, można go pominąć (lub „ukryć” np. w zmiennej środowiskowej). Niektórym może się to bardziej podobać bez tej flagi (liście drzew mają większą objętość). Cóż, te 20 bajtów nie jest aż tak ważne. Powiedziałbym, że 20-25% zniżki na używanie tokenów binarnych zakodowanych w formacie ascii (sądząc po odpowiedzi na powiązany temat). Może 50% zniżki bez kodowania ascii, 2 bajty binarne na token nazwy systemu. Będzie wyglądał jak niektóre zwykle wygrywające języki;)
user2846289
Myślę, że powinieneś to zrobić - uczynić to nieco bardziej konkurencyjnym tutaj :)
Alexander-Brett
3

Coffeescript 377B 352B

Czuję się brudny pisząc coffeescript, ale nie mogę znaleźć porządnego pakietu rysunkowego dla 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

Nieco ładniejszy w javascript i jestem znacznie bardziej zadowolony z pętli for, ale bez [x, y, z] = Składni Po prostu nie potrafię zrobić tego na tyle krótko, aby pokonać 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])}}

Muszę powiedzieć, że jestem trochę zirytowany, to prawie dwa razy dłużej niż rozwiązanie matematyczne: - / zobacz to w akcji: http://jsfiddle.net/FK2NX/3/

Alexander-Brett
źródło
Kilka sugestii: Możesz zapisać co najmniej 16 znaków, używając średników zamiast podziałów linii w CoffeeScript. W obu przypadkach, jeśli którakolwiek z metod Xzwrotu X, możesz połączyć je w łańcuch. I można zapisać kolejny dobry kilka znaków, zapisując M.sini M.coszmiennych pojedynczych znaków.
Martin Ender
Niestety operacje kontekstowe nie zwracają kontekstu, przez co byłem bardzo zdenerwowany. Możesz także zmienić nazwę M.sin na Ms, ale linia Ms = M.sin zajmuje więcej znaków, niż oszczędza ... Spoglądam na usuwanie spacji.
Alexander-Brett
Nie, możesz po prostu zrobić s=M.sin.
Martin Ender
Dlaczego mogę zrobić S = M.sin, ale nie R = X.rotate?
Alexander-Brett
Przypuszczam , że rotateużywa this, a sinnie używa . Musiałbyś zrobić coś takiego R=X.rotate.bind(X), ale prawdopodobnie nie jest to już więcej warte.
Martin Ender