"Scusa, giovanotto, ma sono le tartarughe fino in fondo!"


21

Eseguire un sistema Lindenmayer

Un sistema Lindenmayer (o sistema L) è correlato ai sistemi Thue e Post e viene utilizzato nella modellazione botanica e nella generazione di frattali .

Un sistema L viene descritto mediante riscrittura delle stringhe in cui un simbolo dell'alfabeto simbolico è mappato su una sequenza sostitutiva di simboli. Una raccolta di queste mappature costituisce il sistema L proprio.

Il metodo di output grafico ideato da Prusinkiewicz interpreta la sequenza risultante dopo che le mappature sono state applicate a una sequenza iniziale per un numero specificato di iterazioni , come comandi Turtle-Drawing: avanti, indietro, sinistra, destra, quel tipo di cose. Ciò può richiedere un codice aggiuntivo per controllare la scala del disegno, poiché conteggi di iterazioni diverse possono produrre immagini di dimensioni drasticamente diverse.

Il tuo compito è quello di eseguire un sistema L nel minor numero di caratteri. Il tuo programma deve essere in grado di eseguire il rendering di Dragon Curve e Branching Stems dalla pagina di Wikipedia fornendo un input appropriato (file, riga di comando, ma esterno alla fonte, per favore).

Steli ramificati Dragon Curve

Questo è il codice golf.

Modifica: ecco alcuni esempi che ho pubblicato in giro per la città. risposta a SO / ruota-a-nord { Dove ho scoperto per la prima volta il sistema L } , risposta a SO / come-programmare-un-frattale , risposta a SO / ricorsion-in-postscript , comp.lang.postscript discussione / recital , raccolta l-system PostScript , codegolf.SE/draw-a-sierpinski-triangle {origine della competizione tra me e ThomasW} .


Saltato il sandbox. Questo sembra relativamente semplice e dovrebbe essere divertente.
Luser droog

A proposito, qualcuno conosce l'origine della citazione sopra? Ho sentito William James e ho sentito Faraday.
Luser droog

1
Wikipedia afferma che l'origine è in discussione, la migliore ipotesi è Bertrand Russel.
ugoren,

ITYM Bertrand Russell .
Paolo R

1
Esistono limiti alla dimensione dell'alfabeto, al numero di regole, al numero di giri o alle possibili regole (visualizzazione) (traccia una linea retta, spingi / pop posizione / angolo, ruota di quanti gradi ecc.) Se dobbiamo solo disegnare quei due quindi avremmo bisogno di spingere e scoppiare, disegnare linee rette e poter girare di 45 gradi in entrambe le direzioni, solo due regole e un alfabeto di dimensione 4.
shiona

Risposte:


31

Mathematica 200 198 188 171 168

Spazi aggiunti per maggiore chiarezza:

f[i_, b_, h_, j_, r_, n_] :=
 (a = h; p = j; s = k = {}; t = Flatten;
  (Switch[#,
      6, s = {a, p, s},
      8, {a, p, s} = s,
      _C, k = {k, Line@{p, p += {Cos@a, Sin@a}}}];
     If[# < 9, a += I^# b ]) & /@ t@Nest[# /. r &, i, n];
  Graphics@t@k)

Dove:

i: stato iniziale;
b: angolo di rotazione
h: angolo iniziale
j: posizione iniziale
r: regole di produzione
n: iterazioni

Grammatica delle regole di produzione:

2 = svolta a sinistra (-);
4 = svolta a destra (+);
6 = Premi e gira a sinistra ("[");
8 = Pop e girare a destra ("]");
C [i] = Disegna (qualsiasi numero di simboli)
Qualsiasi altro simbolo = Non fare nulla, basta usarlo per produrre il prossimo stato (Qualsiasi numero di simboli)

La sequenza {2,4,6,8} è lì perché sto usando I^n( I= unità immaginaria) per fare i turni.

Esempi:

f[{C[1], X}, Pi/2, 0, {0, 0}, {X -> {X, 4, Y, C[1]}, Y -> {C[1], X, 2, Y}}, 10]

Grafica Mathematica

f[{C@1}, Pi/2, 0, {0,0}, {C@1->{C@1, 2, C@1, 4, C@1, 4, C@1, 2, C@1}}, 6]

Grafica Mathematica

f[{C[1]}, Pi/4, Pi/2, {0, 0}, {C[2] -> {C[2], C[2]}, C[1] -> {C[2], 6, C[1], 8, C[1]}}, 10]

Grafica Mathematica

f[{C[1]}, Pi/3, 0, {0, 0}, {C@1 -> {C@2, 4, C@1, 4, C@2}, C@2 -> {C@1, 2, C@2, 2, C@1}}, 10]

Grafica Mathematica

f[{X},5/36 Pi, Pi/3, {0,0},{X->{C@1, 4, 6, 6, X, 8, 2, X, 8, 2, C@1, 6, 2, C@1, X, 8, 4, X},
                            C@1->{C@1, C@1}}, 6]

Grafica Mathematica


Basta modificare Graphics@kda Graphics@Flatten@kse si prevede di utilizzare molte iterazioni. Altrimenti un limite di ricorsione ti morderà e la tua sessione di Mma si interromperà.
Dr. belisarius,

Il mio metodo di macro-espansione aveva un problema simile con iterazioni più elevate. Le stringhe diventano semplicemente enormi. Ma la soluzione non c'era , non appiattire. :)
luser droog

2
+1 davvero molto bello;) Potrebbe essere una bella dimostrazione. Li invii?
Vitaliy Kaurov,

@VitaliyKaurov No, ma sentiti libero di usarlo se pensi che valga la pena
Dr. belisarius


9

Python, 369 294

Non un vincitore, ma posterò comunque quello che ho provato.

from turtle import*
I=open('l').read().split()
s,S,p=I[0],'',[]
for j in range(8):
    for i in s:S+=eval('{'+I[1]+'}')[i]
    s,S=S,''
for k in s:
    if k=='[':p+=[heading(),pos()];continue
    if k==']':pu();goto(p.pop());seth(p.pop());pd();continue
    try:{'f':fd,'F':fd,'+':rt,'-':lt}[k](5)
    except:pass

Non è bravo a giocare a golf in Python ...... Forse qualcun altro può farlo.

Ingresso

L'input proviene da un file esterno chiamato "l" (senza estensione), con il seguente formato:
Riga 1 : stato iniziale (assioma)
Riga 2 : regole separate da virgola

Simboli
f e F: Disegna in avanti
+: gira a destra di 5 gradi
-: gira a sinistra di 5 gradi
[: salva posizione e direzione
]: posizione pop e direzione Gli
altri simboli vengono ignorati dalla funzione di disegno.

Regole
Una regola è nel formato "predecessor":"successor(s)"
Nota che le virgolette sono necessarie, singole o doppie.
predecessordeve essere un singolo personaggio.
Inoltre, non ci sono costanti implicite: è necessario specificare esplicitamente una regola di non modifica per quelle.

Esempi

Steli ramificati

------------------f
'-':'-','+':'+','[':'[',']':']','F':'FF','f':'F[+++++++++f]---------f'

Uscita

Si noti che la sorgente viene modificata per ottenere questo messo SOLO PER SCALARE IL GRAFICO ALL'AREA VISIBILE. La console viene anche utilizzata per nascondere la "tartaruga".

Curva del drago

fx
'-':'-','+':'+','[':'[',']':']','f':'f','x':'x++++++++++++++++++yf','y':'fx------------------y'

Output

Ancora, la console viene utilizzata per nascondere la "tartaruga".

Triangolo di Sierpinski

f------------------------F------------------------F
'-':'-','+':'+','[':'[',']':']','f':'f------------------------F++++++++++++++++++++++++f++++++++++++++++++++++++F------------------------f','F':'FF'



Generazioni di output ridotte a 5 qui.


3
È possibile ottenere un risparmio decente (lo faccio 32 caratteri) togliendo le funzioni f, r, l; aggiungendo un parametro fittizio a oe c; e poi cambiando lo pseudo-switch in{'f':fd,'F':fd,'+':rt,'-':lt,'[':o,']':c}[k](5)
Peter Taylor,

Puoi anche inline g, e penso oche cvalga la pena eliminarlo con ifdichiarazioni inline (più economiche della globaldichiarazione)
Peter Taylor,

@PeterTaylor buon lavoro. Ho avuto l'intuizione che alcune di quelle funzioni potevano essere integrate, ma non conoscevo abbastanza Python per suggerirlo in modo articolato.
Luser droog

1
@luserdroog, non conosco nemmeno Python: ho appena fatto prove ed errori per vedere cosa ha funzionato - vale a dire alcune delle cose che ho provato (ad esempio usando lambdas per oe cdirettamente nello pseudo-switch) hanno dato errori di sintassi, ma altri no t.
Peter Taylor,

Suggerimenti per ulteriori golf: 1. Cambia formato di input: richiede parentesi attorno alle regole e assioma separato dalle regole di uno spazio (non una nuova riga). 2. Leggi dal stdin: s,R,*p=input().split(). 3. Generare il valore finale di sdi exec('s="".join(map(eval(R).get,s));'*8). 4. Lasciare fuori continue. 5. Rientra solo 1 spazio. 6. Salvare lo spazio dopo il ifcommutando i lati del test. 7. Inserire k:intla dict(prima voce) e non è necessario except: try:. (Ricevo 215 caratteri.)
Reinstalla Monica il

7

Javascript (179 byte)

Non sono del tutto sicuro che ciò si qualifichi, poiché l'oggetto rules esegue tutto il disegno effettivo.

Demo (Dragon, animato):
- Espanso: http://jsfiddle.net/SVkMR/9/show/light
- Con codice: http://jsfiddle.net/SVkMR/9/

minified:

function L(c,r,n){o=(function g(d,s,o,i){for(o=i='';a=d&&s[i++];)o+=r.r[a]?g(d-1,r.r[a]):a;return o||s;})(n,r.r[r.s]);(function z(i){r[s=o[i]]&&r[s](c)||setTimeout(z,10,i+1)})(0)}

Leggibile (ish):

function L(c,r,n){
    o=(function g(d,s,o,i){
        for(o=i='';a=d&&s[i++];)o+=r.r[a]?g(d-1,r.r[a]):o+=a
        return o||s
    })(n,r.r[r.s]);

    (function p(i){
        r[s=o[i]]&&r[s](c)||setTimeout(p,10,i+1)
    })(0)
}

Ingresso:

var sierspinski = {
    r:{'A':'B-A-B','B':'A+B+A'},
    '+':function(c){c.rotate(-this.a);c.rotate(this.a-=Math.PI/3)},
    '-':function(c){c.rotate(-this.a);c.rotate(this.a+=Math.PI/3)},
    'A':function(c){c.beginPath();c.moveTo(0,0);c.translate(this.m,0);c.lineTo(0,0);c.stroke()},
    'B':function(c){this['A'](c)},
    s:'A',
    a:0,
    m:1
};

var koch = {
    r: {'F':'F+F-F-F+F'},
    '+':function(c){c.rotate(-this.a);c.rotate(this.a-=Math.PI/2)},
    '-':function(c){c.rotate(-this.a);c.rotate(this.a+=Math.PI/2)},
    'F':function(c){c.beginPath();c.moveTo(0,0);c.translate(this.m,0);c.lineTo(0,0);c.stroke()},
    s:'F',
    a:0,
    m:2
};
var dragon = {
    r: {'X':'X+YF','Y':'FX-Y'},
    '+':function(c){c.rotate(-this.a);c.rotate(this.a-=Math.PI/2)},
    '-':function(c){c.rotate(-this.a);c.rotate(this.a+=Math.PI/2)},
    'F':function(c){c.beginPath();c.moveTo(0,0);c.translate(this.m,0);c.lineTo(0,0);c.stroke()},
    s:'X',
    a:0,
    m:5
};

var algae = {
    r: {'A':'B[A]A','B':'BB'},
    '[':function(c){c.save();c.rotate(Math.PI/4);},  // save/restore will push/pop current state of context. 
    ']':function(c){c.restore();c.rotate(-Math.PI/4);},
    'A':function(c){c.beginPath();c.moveTo(0,0);c.translate(this.m,0);c.lineTo(0,0);c.stroke()},
    'B':function(c){this['A'](c);},
    s:'A',
    a:-Math.PI/2,
    m:1
};

var tree = {
    r:{'X':'F-[[X]+X]+F[+FX]-X','F':'FF'},
    '+':function(c){c.rotate(-this.a);c.rotate(this.a+=Math.PI/180*25)},
    '-':function(c){c.rotate(-this.a);c.rotate(this.a-=Math.PI/180*25)},
    '[':function(c){c.save();},
    ']':function(c){c.restore();},
    'F':function(c){c.beginPath();c.moveTo(0,0);c.translate(this.m,0);c.lineTo(0,0);c.stroke()},
    s:'X',
    a:-Math.PI/180*25,
    m:5
};

Uso:

var ctx = document.getElementById('l').getContext('2d'); // grab context
ctx.translate(299.5,199.5); // start drawing from center, fractional pixels because the canvas draws lines centered on the x/y coord specified
L(ctx, dragon, 8); // pass in context, rules object, and recursion cap

Bonus: Golden Spiral http://jsfiddle.net/SVkMR/35/show/light/

var golden = {
    r:{'A':'FT[TT]A','T':'+F'},
    'F':function(c){c.beginPath();c.moveTo(0,0);c.translate(this.m,0);c.lineTo(0,0);c.stroke()},
    '[':function(c){c.save();},
    ']':function(c){
        c.restore();

        c.beginPath();
        c.arc(0,-this.m,this.m,Math.PI/2,Math.PI);
        c.stroke();

        this.m+=this.d;this.d=this.m-this.d
    },
    '+':function(c){c.rotate(-Math.PI/2);},
    s:'A',
    a:-Math.PI/2,
    m:1,
    d:0
};

Penso che l'animazione compensi più di ogni libertà con le regole. Buon lavoro! +1
drouser luser

:) Cose divertenti! .
Shmiddty,

5

poscritto 264 298 295 255

Ecco il mio tentativo di farlo diversamente. Piuttosto che la macro-espansione che di solito uso, questa controlla la dimensione dello stack di esecuzione per limitare la ricorsione. Se il limite viene superato, smette di esaminare in modo ricorsivo la procedura e cerca di interpretare i comandi delle tartarughe (e scarta pop popaltrimenti). Un vantaggio di questo metodo è che non richiede enormi quantità di memoria. Uno svantaggio è che il controllo della ricorsione è piuttosto goffo, poiché la dimensione dello stack aumenta di oltre 1 da un livello di ricorsione a quello successivo.

Modifica: +34 caratteri per la ramificazione.
Modifica: -3 caratteri. Riprogettato per utilizzare lo stack di operandi per il controllo della ricorsione. Questo rende il sistema di base molto più semplice. Ma le parentesi necessitano di uno stack indipendente, quindi ho inserito la posizione salvata nello stack del dizionario e ho quasi rimborsato tutti i risparmi.

Inoltre, riprogettato per utilizzare stringhe e numeri interi anziché matrici e nomi.

Modifica: -40 caratteri. Aggiunte due procedure per chiamare i nomi dei sistemi in base al numero (non riesco a far funzionare i token binari non elaborati. Ma questo idioma funziona per me.)

/*{<920>dup 1 4 3 roll put cvx exec}def/${//* 73
*}def[/T[48{}49{}43{A<88>$}45{A<6e88>$}70{R
0<85>$}91{<1e39>$[/.[<286827>$]cvx>><0d0d>$}93{.<9c6b1e39390d>$}>>/S{dup
B eq{T<0d3e>${<643f>$}<4939>$}{exch{<643e>$ 1 add S}73 *}85 * 1 sub}>><0d6b>$
0 S<a7>$

Binario semi-commentato.

/*{<920>dup 1 4 3 roll put cvx exec}def/${//* 73 *}def %73=forall
[/T[70{R 0<85>$}48{}49{} %<85>=rlineto
43{A<88>$}45{A<6e88>$} %<88>=rotate <6e>=neg
91{<1e39>$ %<1e>=currentdict <39>=end
    [/.[<286827>$]cvx>> %<28>=currentpoint <68>=matrix <27>=currentmatrix
        <0d0d>$} %<0d>=begin
93{.<9c6b1e39390d>$}>> %<9c>=setmatrix <6b>=moveto
/S{dup B eq{T<0d3e>${<643f>$}<4939>$} %<3e>=exch <64>=load <3f>=exec <49>=forall
{exch{<643e>$ 1 add S}73 *}85 * 1 sub}>>
<0d6b>$ 0 S<a7>$  % 85=ifelse <a7>=stroke

Un- "binario".

[/T[70{R 0 rlineto}48{}49{}43{A rotate}45{A neg rotate}91{currentdict
end[/.[currentpoint matrix currentmatrix]cvx>>begin begin}93{. setmatrix
moveto currentdict end end begin}>>/S{dup B eq{T begin exch{load exec}forall
end}{exch{load exch 1 add S}forall}ifelse 1 sub }>>begin moveto 0 S stroke

Richiede che il sistema L sia definito in un dizionario sulla dictstack, con la stringa iniziale e la posizione iniziale della tartaruga sullo stack dell'operando (anteposto alla sorgente, ad es. gs dragon.sys lsys.ps).

Dragon Curve.

%!
[                     %begin dictionary construction
    % productions are described by integer-key/string-value pairs
    48(0+1F) %0       %ascii code for '0' defined as the string "0+1F"
    49(F0-1) %1       %  "     "   "  '1'   "     "   "    "    "F0-1"
    43(+) %+          %  "     "   "  '+' defined as itself
    45(-) %-          %  "     "   "  '-'   "     "   "
    70(F) %F          %  "     "   "  'F'   "     "   "
    % parameters
    /A 90 %angle
    /R 2  %radius
    /B 10 %maximum recursion-level
>>begin  % L-system dictionary on top of dictstack
(F0)     % initial string on stack
300 400  % starting position on stack

Steli ramificati.

[
    48(F[+0]-0) %0
    49(F0-1) %1
    43(+) %+
    45(-) %-
    70(FF) %F
    91([) %[
    93(]) %]
    /A 45 %angle
    /R 5  %radius
    /B 3 %recursion
>>begin
(++0)     % initial string
300 400  % starting position

Ungolf e commentato.

[                                 % begin dictionary construction
    /T[                           % /T is the Turtle dictionary containing
                                  % integer-key/procedure-value pairs
                                  % keyed to ascii values
        70{R 0 rlineto}        %F  
        48{}                   %0
        49{}                   %1  
        43{A rotate}           %+  
        45{A neg rotate}       %-  

          % For brackets, create a dictionary containing a single procedure '.' (dot)
          % which holds a saved matrix (orientation+size) and currentpoint.
          % Since this procedure is called while the Turtle dict is on top of the
          % dictstack, the temporary dictionary is placed just under the top.
        91{currentdict end[/.[currentpoint matrix currentmatrix]cvx>>begin begin} %[
          % Right bracket: reset position and orientation,
          % pop the dict just under the top.
        93{. setmatrix moveto currentdict end end begin}    %]  
    >>  
    /S{ % stack contains: string recursion-level
        dup B eq{ % hit recursion bound, interpret string as turtle commands
            T begin
                exch % level string
                %dup =
                {                      % iterate through string
                    load exec          % execute turtle command by integer code
                } forall % level       % string has been consumed
            end
            %(B)= pstack
        }{ % recurse
            %(A)= pstack
            exch % level string
            { % level char                   iterate through string
                load exch % string level   process production:load string by int code
                1 add S   % string level+1   increase level and call self
            } forall                       % string has been consumed
        }ifelse
        1 sub            % return level-1
        %(C)= pstack
    }
>>begin
moveto 0 S stroke

Per eseguirlo, questi 3 blocchi possono essere salvati come 3 file: dragon.ps, stems.ps, lsys.ps (uno qualsiasi dei blocchi di programma sopra funzionerà in modo identico). Quindi eseguire con gs: gs dragon.ps lsys.pso gs stems.ps lsys.ps. Possono anche essere concatenati per primi, se desiderato: cat dragon.ps lsys.ps | gs -o cat stems.ps lsys.ps | gs -.

curva del drago

Nessuna immagine derivata. Non diventa più interessante a profondità più elevate.


4

Mathematica 290

Questa implementazione bare-bone si concentra sull'output piuttosto che sull'elaborazione. Non utilizza le regole di produzione. Quindi potrebbe non essere una risposta adeguata alla sfida.

Steli ramificati adattati dalla dimostrazione di Theo Gray .

Codice

f@{a_, b_} := {{a, #}, {b, #}} &[a + (b - a)/2 + {{0, 1/2}, {-1/2, 0}}.(b - a)]; w = Flatten;
h[s_, g_] :=Graphics[If[s == 0,Line /@ Nest[w[f /@ #, 1] &, {{{0, 0}, {1, 0}}}, g], 
 MapIndexed[Line@# &, NestList[w[Map[{{#[[2]], #[[2]] + m.(#[[2]] - #[[1]])}, {#[[2]], 
 #[[2]] + ({{1, -1}, {-1,1}} m).(#[[2]] - #[[1]])}} &, #], 1] &, {{{0, -1}, {0, 0}}}, g]]]]

uso

Il primo parametro determina se verranno visualizzati Dragon Curve o Branch Stems. Il secondo termine si riferisce alla generazione.

h[0, 5]
h[1, 5]

seconda foto


Altri esempi

GraphicsGrid@Partition[Flatten[Table[h[j, k], {j, 0, 1}, {k, 10}]], 5]

fractal3


1
Molto bello. Ma non risparmierebbe alcuni byte per passare la regola come argomento?
Luser droog

Se questa fosse una soluzione generale, forse si potrebbe passare una regola piuttosto che parametri. Dovrei essere più informato sui sistemi Lindenmayer di quanto lo sia attualmente.
DavidC

Non leggo matematica. Dovrei andare a imparare un po '. (aggiungilo allo stack :) Ma puoi interpretarlo nel senso che "qualunque cosa costituisca la descrizione dell'immagine, distinta dal motore che la guida" può essere presa in considerazione. Se è quindi possibile modificare i dati per controllare alcune funzionalità dell'immagine, indipendentemente dal contatto del motore corretto ; Lo considererei "funzionalmente equivalente" a un sistema a L. [ Ciò dovrebbe darti molte lacune con cui lavorare;) ]. +1 comunque perché è così carino.
Luser droog

1
@dude Penso che sia perché i requisiti grafici non sono adatti a loro
Dr. belisarius

1
Alla fine ho capito il sistema a L per il tuo albero: A->F[+A][-A]dove Fsi sposta, +ruota a sinistra 30, -ruota a destra 30 e [/ ]sono push / pop
Shmiddty
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.