Rendering ASCII L-system


16

sfondo

Un sistema L (o sistema Lindenmayer) è un sistema di riscrittura parallela che, tra le altre cose, può essere facilmente utilizzato per modellare i frattali. Questa domanda riguarda i sistemi L deterministici e senza contesto . Sono costituiti da un alfabeto di simboli, una stringa di assioma iniziale e un insieme di regole di riscrittura che associano ciascun simbolo dell'alfabeto a una nuova stringa. Le regole vengono applicate all'assioma in parallelo, generando una nuova stringa. Questo processo viene quindi ripetuto.

Ad esempio, il sistema con l'assioma "A" e le regole A = ABA; B = BBB genera la sequenza di stringhe "ABA", "ABABBBABA", "ABABBBABABBBBBBBBBABABBBABA", ecc. Per concisione, non menzioniamo esplicitamente il alfabeto quando si definisce il sistema L. Inoltre, si presume che qualsiasi simbolo senza una regola di riscrittura esplicita sia invariato (ovvero la regola predefinita per un simbolo A è A = A).

I sistemi L possono essere visualizzati utilizzando una forma di grafica tartaruga. Per convenzione, la tartaruga inizia rivolta verso destra. Una stringa viene quindi disegnata ripetendo i suoi simboli: una F significa "trascina avanti di un'unità", una G significa "sposta avanti di un'unità", un + significa "gira a sinistra di un'unità ad angolo" e un - significa "gira a destra di un angolo unità". Tutti gli altri simboli nella stringa vengono ignorati. Ai fini di questa domanda, si presume che le unità angolari siano sempre di 90 °.

Compito

Data una specifica di qualsiasi sistema L e un numero di iterazioni, il tuo programma dovrebbe produrre un rendering ASCII della stringa risultante (come descritto sopra) usando caratteri di disegno a scatola.

  • I parametri vengono passati come una stringa separata dallo spazio comprendente l'assioma, le regole di riscrittura (come un elenco separato di equazioni;) e il numero di iterazioni di riscrittura. Ad esempio, l'ingresso "FF = FGF; G = GGG 2" genera la stringa "FGFGGGFGF" e quindi disegna quattro linee con spazi adeguati.
  • I simboli utilizzati dal sistema L possono essere qualsiasi carattere ASCII a parte spazio e punto e virgola. Esiste al massimo una regola esplicita specificata per simbolo (la regola di riscrittura predefinita è la mappatura dell'identità come descritto sopra).
  • Si può presumere che l'output conterrà sempre almeno una F.
  • L'output dovrebbe usare i seguenti caratteri UNICODE per rappresentare la visualizzazione: ─ (U + 2500), │ (U + 2502), ┌ (U + 250C), ┐ (U + 2510), └ (U + 2514) , ┘ (U + 2518), ├ (U + 251C), ┤ (U + 2524), ┬ (U + 252C), ┴ (U + 2534), ┼ (U + 253C), ╴ (U + 2574), ╵ (U + 2575), ╶ (U + 2576) e ╷ (U + 2577). Vedi sotto per esempi.
  • L'output non deve contenere righe vuote sopra il carattere della casella più in alto o sotto quello più in basso. Inoltre, non deve contenere spazi alla sinistra del riquadro più a sinistra o alla destra di quello più a destra. Sono consentite le linee con spazi finali che non si estendono oltre il carattere del riquadro più a destra.

È possibile scrivere un programma o una funzione, prendendo l'input tramite STDIN (o l'alternativa più vicina), argomento della riga di comando o argomento della funzione. I risultati devono essere stampati su STDOUT (o alternativa più vicina), salvati su un file o restituiti come stringa.

Esempi

# Cantor dust
>> "F F=FGF;G=GGG 0"
╶╴
>> "F F=FGF;G=GGG 1"
╶╴╶╴
>> "F F=FGF;G=GGG 2"
╶╴╶╴  ╶╴╶╴
>> "F F=FGF;G=GGG 3"
╶╴╶╴  ╶╴╶╴        ╶╴╶╴  ╶╴╶╴

# Koch curve
>> "F F=F+F−F−F+F 1"
 ┌┐
╶┘└╴
>> "F F=F+F-F-F+F 2"
    ┌┐
   ┌┘└┐
  ┌┘  └┐
 ┌┼┐  ┌┼┐
╶┘└┘  └┘└╴

Altri esempi con cui testare il programma includono:

# Dragon curve
>> "FX X=X+YF+;Y=-FX-Y n"

# Hilbert curve
>> "A A=-BF+AFA+FB-;B=+AF-BFB-FA+ n"

# Sierpinski carpet
>> "F F=F+F-F-F-G+F+F+F-F;G=GGG n"

I primi due sono i seguenti (prodotti utilizzando la risposta di @ edc65):

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

Puoi testare qualsiasi sistema in questa pagina .

punteggio

Vince il codice più breve (in byte). Si applicano le regole standard.

Miscellania

Questa sfida è stata ispirata da Draw a Random Walk with Slash . In effetti, è possibile rappresentare una camminata casuale come sistema L se si estende il sistema per consentire più regole per simbolo, con l'espansione scelta in modo non deterministico durante la riscrittura. Una formulazione è:

"F F=FF;F=F+F;F=F++F;F=F+++F"

Un'altra estensione comune, spesso usata quando si modellano le piante, è interpretare i caratteri [e] come spingere e schioccare la posizione e l'angolazione attuali. La maggior parte delle piante usa angoli inferiori a 90 °, ma ecco un esempio che non:

"FAX X=[-FAX][FAX][+FAX];A=AFB;B=A"

Nessuno di questi esempi deve essere supportato in questa sfida.

Questa sfida è anche simile a "Mi dispiace, giovanotto, ma sono le tartarughe fino in fondo!" . Tuttavia, quella sfida utilizzava il rendering delle linee anziché ASCII e consentiva una sintassi più flessibile.

Risposte:


7

JavaScript (ES6), 440 byte (410 caratteri)

F=p=>([a,r,n]=p.split(' '),t=>{r.split(';').map(x=>r[x[0]]=x.slice(2),r={});for(;n--;)a=[...a].map(c=>r[c]||c).join('');u=x=y=0,g=[];for(c of a)c=='+'?[t,u]=[u,-t]:c=='-'?[u,t]=[t,-u]:c<'F'|c>'G'?0:((y+=u)<0?(g=[[],...g],++y):g[y]=g[y]||[],(x+=t)<0?(g=g.map(r=>[,...r]),++x):0,c>'F'?0:g[g[f=t?0.5:2,y][x]|=(3+t-u)*f,y-u][x-t]|=(3+u-t)*f)})(1)||g.map(r=>[for(c of r)' ╶╴─╵└┘┴╷┌┐┬│├┤┼'[~~c]].join('')).join('\n')

Meno golf

F=p=>{
  [a,r,n]=p.split(' '),
  r.split(';').map(x=>r[x[0]]=x.slice(2),r={}); // set rules
  for(;n--;)a=[...a].map(c=>r[c]||c).join(''); // build string
  t=1,u=x=y=0, // start pos 0,0 start direction 1,0
  g=[[]]; // rendering in bitmap g
  for(c of a)
    c=='+'?[t,u]=[u,-t] // left turn
    :c=='-'?[u,t]=[t,-u] // right turn
    :c=='F'|c=='G'?(     // move or draw
      (y+=u)<0?(g=[[],...g],++y):g[y]=g[y]||[], // move vertical, enlarge grid if needed
      (x+=t)<0?(g=g.map(r=>[,...r]),++x):0, // move horizontal, enlarge grid if needed
      c=='F'&&( // draw: set bits
        f=t?0.5:2,
        g[y][x]|=(3+t-u)*f,
        g[y-u][x-t]|=(3+u-t)*f
      )
    ):0;
  // render bits as box characters
  return g.map(r=>[' ╶╴─╵└┘┴╷┌┐┬│├┤┼'[~~c]for(c of r)].join('')).join('\n')
}

Test snippet di codice da testare (in Firefox)


Ottima (e veloce!) Risposta. Ho aggiunto schermate dei risultati della curva del drago e di Hilbert alla domanda.
Uri Granta,

6

Haskell, 568 byte

import Data.List.Split
p=splitOn
l=lookup
m=maximum
n=minimum
o[h,x]=(h,x)
Just x#_=x
_#x=x
g[s,r,i]=iterate((\c->lookup[c](map(o.p"=")(p";"r))#[c])=<<)s!!read i
u v@(a,x,y,d,e)c|c=='+'=(a,x,y,-e,d)|c=='-'=(a,x,y,e,-d)|c=='G'=(a,x+d,y+e,d,e)|c=='F'=(s(x,y)(d%e)a:s(x+d,y+e)(d?e)a:a,x+d,y+e,d,e)|1<2=v
s p n a=(p,n+(l p a)#0)
1%0=2;0%1=8;-1%0=1;0%(-1)=4
1?0=1;0?1=4;-1?0=2;0?(-1)=8
f z=unlines[[" ╴╶─╷┐┌┬╵┘└┴│┤├┼"!!(l(x,y)q#0)|x<-[n a..m a]]|y<-[m b,m b-1..n b]]where a=map(fst.fst)q;b=map(snd.fst)q;(q,_,_,_,_)=foldl u([],0,0,1,0)$g$p" "z

Prova:

*Main> putStr $ f "F F=F-F+F+F-F 3"
╶┐┌┐  ┌┐┌┐        ┌┐┌┐  ┌┐┌╴
 └┼┘  └┼┼┘        └┼┼┘  └┼┘
  └┐  ┌┼┼┐        ┌┼┼┐  ┌┘
   └┐┌┼┘└┘        └┘└┼┐┌┘
    └┼┘              └┼┘   
     └┐              ┌┘
      └┐┌┐        ┌┐┌┘
       └┼┘        └┼┘
        └┐        ┌┘
         └┐┌┐  ┌┐┌┘
          └┼┘  └┼┘
           └┐  ┌┘
            └┐┌┘
             └┘

Come funziona:

  • riscrittura (funzione g): analizzo le regole in un elenco di associazioni (lettera -> stringa di sostituzione) e le mappa ripetutamente sull'assioma.
  • creare il percorso (funzione uper un singolo passo): Non riporre il percorso in una matrice, ma in un altro elenco associazione con (x, y) posizioni come le chiavi e le sequenze di bit dei 4 blocchi di base ( , , e ) come valori . Lungo la strada tengo traccia della posizione e della direzione correnti.
  • disegnando il percorso (funzione f): prima calcolo le dimensioni massime / minime dall'elenco dei percorsi, quindi eseguo l'iterazione su [max y -> min y] e [min x -> max x] e cerco i blocchi da disegnare.

0

ES7, 394 caratteri, 424 byte

F=p=>([a,r,n]=p.split` `,t=>{r.split`;`.map(x=>r[x[0]]=x.slice(2),r={});for(;n--;)a=[...a].map(c=>r[c]||c).join``;u=x=y=0,g=[];for(c of a)c=='+'||c=='-'?[t,u]=[u,-t]:c<'F'|c>'G'?0:((y+=u)<0?(g=[[],...g],++y):g[y]=g[y]||[],(x+=t)<0?(g=g.map(r=>[,...r]),++x):0,c>'F'?0:g[g[f=t?0.5:2,y][x]|=(3+t-u)*f,y-u][x-t]|=(3+u-t)*f)})(1)||g.map(r=>[for(c of r)'╶╴─╵└┘┴╷┌┐┬│├┤┼'[~~c]].join``).join`
`
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.