J'aime les pythagoriciens

17

... c'est donc un défi de faire de moi un arbre.

Produisez un programme ou une fonction appelée arbre qui prend un seul argument entier, N et dessine un arbre de Pythagore N niveaux en profondeur, où le niveau 0 est juste le tronc.

Chaque jonction de l'arbre doit placer le sommet du triangle à un point aléatoire sur le périmètre (ce point doit être uniformément réparti sur au moins 5 points également espacés, ou uniformément sur tout le demi-cercle).

En option, votre arbre peut être en 3D, coloré ou éclairé en fonction de l'heure de la journée. Cependant, c'est du code-golf, donc le plus petit fichier gagne.

EDIT: Je vais fermer le concours et accepter la plus petite réponse quand elle aura une semaine

alexander-brett
la source
Semble
DavidC
Faux. Je suis après un algorithme différent :)
alexander-brett
D'accord. C'est suffisant. Vous voudrez peut-être envisager de renommer votre soumission à "Arbre de Pythagore".
DavidC
J'aime les trains? :)
tomsmeding

Réponses:

15

Mathematica, 246 234 221 caractères

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

Ce n'est certainement pas la manière la plus élégante / la plus courte de le faire.

Usage: f[8]

entrez la description de l'image ici

Et voici des exemples de sorties pour f[6]et f[10]respectivement.

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

Assez peu golfé:

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
la source
C'est assez impressionnant. Dommage que je ne dispose pas de Mathématiques pour le tester - pourriez-vous ajouter quelques autres exemples de sorties?
alexander-brett
@ ali0sha voir edit
Martin Ender
Vous n'avez pas besoin Showlà-dedans, et Modulec'est également inutile.
Swish
@swish Merci pour l' Showastuce, mais comment m'en débarrasser Module? Si je ne déclare pas plocal, il sera écrasé dans les appels récursifs, donc je ne pourrais pas faire les deux appels avec le même p, non?
Martin Ender
@ m.buettner Vous pouvez peut-être utiliser Blockce qui est plus court que Module.
alephalpha
20

CFDG, 134 caractères

Celui-ci n'est pas exactement valide, car vous ne pouvez pas limiter la profondeur de récursivité. Mais le problème appelle simplement une solution dans celui-ci . :)

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

Les résultats ressemblent à ceci

entrez la description de l'image ici

Pour 46 autres caractères ( 180 caractères au total), vous pouvez même le colorier en:

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

entrez la description de l'image ici

Martin Ender
la source
Je sais que ce n'est pas entièrement ontopique, mais à quoi ressemblerait une version si au lieu de «bruit blanc», vous utilisiez «bruit brun» comme angles?
ɐɔıʇǝɥʇuʎs
@Synthetica tu veux dire avec plus d'angles autour de 90 ° et moins à 0 et 180?
Martin Ender
@Synthetica Similaire à cela . Je n'ai pas pu implémenter un bruit de marche aléatoire réel, car cela nécessite de prendre un paramètre d'entrée (la dernière valeur aléatoire), de l'ajuster et de le transmettre. Cela rendrait la grammaire contextuelle et n'est donc pas pris en charge par CFDG. Je l'ai légèrement simulé, en poussant simplement les valeurs aléatoires un peu plus vers π / 2 en utilisant une simple fonction cubique sur l'échantillon aléatoire.
Martin Ender
Je pense que votre lien imgur est cassé, et aussi bien que j'apprécie la couleur et la forme, je pense que je dois disqualifier celui-ci pour la raison que vous avez mentionnée
alexander-brett
@ ali0sha vous avez raison, voici le lien fixe . Disqualifier celui-ci est absolument juste, je voulais juste partager Context Free Art avec certaines personnes et cela semblait être une approche soignée du problème. ;) ... Eh bien, j'ai toujours la réponse Mathematica ^^
Martin Ender
4

Postscript, 322 270

Edit: Il semble que realtimecela ne peut pas être utilisé comme une graine de générateur aléatoire appropriée. Par conséquent, nous utiliserons la variable d'environnement à cet effet et exécuterons le programme comme ça:

gs -c 20 $RANDOM -f tree.ps

ou

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

Maintenant, nos arbres sont moins prévisibles. 14 octets sont ajoutés au nombre total. Autres modifications: 1) L'argument du programme est maintenant passé sur la ligne de commande. 2) Aucun compteur d'itération explicite - la taille de la pile sert à cet effet (l'angle de rotation de la branche gauche est stocké sur la pile, pour dessiner la branche droite, plus tard). 3) Il n'y a pas de variable nommée pour la profondeur requise - la taille de la pile est son décalage, sur la pile. Il est laissé là à la sortie, c'est-à-dire qu'il n'est pas consommé.

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

Je pense que c'est assez évident - l'état graphique est préparé et la fprocédure est appelée récursivement pour chaque niveau de profondeur consécutif, deux fois - pour les branches «gauche» et «droite». Travailler avec un rectangle de 1x1taille (voir l'échelle d'origine) évite de multiplier par la longueur du côté. L'angle de rotation de la branche gauche est randomisé - une des 5 divisions aléatoires également espacées est utilisée - je pense que cela empêche les cas laids possibles pour un caractère aléatoire uniforme.

Il peut être lent pour une profondeur requise supérieure à 20 environ.

Vient ensuite la version golfée, utilisant des jetons binaires encodés en ASCII (voir la réponse de luser droog du sujet lié). Notez cos, sin, randne peut pas utiliser cette notation.

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

entrez la description de l'image ici

user2846289
la source
Je pense que le style ici est que des arguments de ligne de commande doivent être ajoutés pour que cela marque 344 ... Je dois dire que même selon les normes de codegolf, cela a un aspect assez impressionnant. Jusqu'où pouvez-vous l'obtenir avec des jetons binaires? Vous n'êtes sûrement pas loin de Mathematica
alexander-brett
@ ali0sha, -dGraphicsAlphaBitsest un indicateur de sortie anti-alias pour éviter les bords irréguliers de carrés plus grands, il peut être omis (ou «caché» par exemple dans la variable d'environnement). Certaines personnes peuvent l'aimer davantage sans ce drapeau (les feuilles des arbres obtiennent plus de «volume»). Eh bien, ces 20 octets ne sont pas très importants. Je dirais 20-25% de réduction sur l'utilisation de jetons binaires codés en ascii (à en juger par la réponse du sujet lié). Peut-être 50% de réduction sans codage ascii, 2 octets binaires par jeton de nom de système. Ressemblera à certaines langues généralement gagnantes;)
user2846289
Je pense que vous devriez le faire - rendez-le un peu plus compétitif ici :)
alexander-brett
3

Coffeescript 377B 352B

Je me sens sale en écrivant un coffeescript mais je ne trouve pas de package de dessin décent pour 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

Un peu plus joli en javascript et je suis beaucoup plus heureux avec la boucle for mais sans la [x, y, z] = une syntaxe que je ne peux pas faire assez courte pour battre 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])}}

Je dois dire que je suis un peu fâché, c'est presque deux fois plus longtemps que la solution mathématique: - / voir en action: http://jsfiddle.net/FK2NX/3/

alexander-brett
la source
Quelques suggestions: vous pouvez enregistrer au moins 16 caractères en utilisant des points-virgules au lieu des sauts de ligne dans CoffeeScript. Dans les deux cas, si l'une des méthodes au Xretour X, vous pouvez les enchaîner. Et vous pouvez enregistrer un autre bon groupe de caractères en enregistrant M.sinet M.cosen variables à un seul caractère.
Martin Ender
Malheureusement, les opérations de contexte ne renvoient pas le contexte, ce qui m'a bouleversé. En outre, vous pouvez renommer M.sin en Ms, mais la ligne Ms = M.sin prend plus de caractères qu'elle n'en enregistre ... Je vais essayer de supprimer les espaces.
alexander-brett
Non, vous pouvez simplement le faire s=M.sin.
Martin Ender
Comment se fait-il que je puisse faire S = M.sin, mais pas R = X.rotate?
alexander-brett
Je suppose que ça rotatesert thiset sinnon. Vous auriez besoin de faire quelque chose comme ça R=X.rotate.bind(X), mais cela n'en vaut probablement plus la peine.
Martin Ender