Renderer sistem L ASCII

16

Latar Belakang

Sistem L (atau sistem Lindenmayer) adalah sistem penulisan ulang paralel yang, antara lain, dapat dengan mudah digunakan untuk memodelkan fraktal. Pertanyaan ini menyangkut deterministik, sistem-L-bebas konteks . Ini terdiri dari alfabet simbol, string aksioma awal dan seperangkat aturan penulisan ulang yang memetakan setiap simbol alfabet ke string baru. Aturan diterapkan pada aksioma secara paralel, menghasilkan string baru. Proses ini kemudian diulang.

Sebagai contoh, sistem dengan aksioma "A" dan aturan A = ABA; B = BBB menghasilkan urutan string "ABA", "ABABBBABA", "ABABBBABABBBBBBBBABABBBABA", dll. Untuk keringkasan, kami tidak secara eksplisit menyebutkan alfabet saat mendefinisikan sistem-L. Lebih lanjut, simbol apa pun tanpa aturan penulisan ulang eksplisit diasumsikan tidak berubah (yaitu aturan default untuk simbol A adalah A = A).

Sistem-L dapat divisualisasikan menggunakan bentuk grafik penyu. Dengan kebiasaan, kura-kura mulai menghadap ke kanan. Sebuah string kemudian digambar dengan mengulangi simbolnya: F berarti "menggambar maju satu unit", G berarti "bergerak maju satu unit", a + berarti "belok kiri satu unit sudut" dan a - berarti "belok kanan satu sudut satuan". Semua simbol lain dalam string diabaikan. Untuk tujuan pertanyaan ini, unit sudut diasumsikan selalu 90 °.

Tugas

Diberikan spesifikasi dari setiap sistem-L dan sejumlah iterasi, program Anda harus menampilkan rendering ASCII dari string yang dihasilkan (seperti dijelaskan di atas) menggunakan karakter gambar kotak.

  • Parameter dilewatkan sebagai string yang dipisahkan oleh spasi yang terdiri dari aksioma, aturan penulisan ulang (sebagai; - daftar persamaan yang dipisah) dan jumlah iterasi yang ditulis ulang. Misalnya, input "FF = FGF; G = GGG 2" menghasilkan string "FGFGGGFGF" dan karenanya menggambar empat garis dengan celah yang sesuai.
  • Simbol yang digunakan oleh sistem-L dapat berupa karakter ASCII selain dari ruang dan titik koma. Paling banyak ada satu aturan eksplisit yang ditentukan per simbol (dengan aturan penulisan ulang default menjadi pemetaan identitas seperti dijelaskan di atas).
  • Anda dapat mengasumsikan bahwa output akan selalu mengandung setidaknya satu F.
  • Outputnya harus menggunakan karakter gambar kotak UNICODE berikut untuk mewakili visualisasi: ─ (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) dan ╷ (U + 2577). Lihat contoh di bawah ini.
  • Output tidak boleh berisi baris kosong di atas karakter kotak paling atas atau di bawah yang paling bawah. Seharusnya juga tidak mengandung spasi di sebelah kiri kotak characer paling kiri atau di sebelah kanan yang paling kanan. Garis dengan spasi tambahan yang tidak melampaui karakter kotak paling kanan diizinkan.

Anda dapat menulis program atau fungsi, mengambil input melalui STDIN (atau alternatif terdekat), argumen baris perintah atau argumen fungsi. Hasil harus dicetak ke STDOUT (atau alternatif terdekat), disimpan ke file atau dikembalikan sebagai string.

Contohnya

# 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"
    ┌┐
   ┌┘└┐
  ┌┘  └┐
 ┌┼┐  ┌┼┐
╶┘└┘  └┘└╴

Contoh lain untuk menguji program Anda dengan termasuk:

# 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"

Dua yang pertama terlihat sebagai berikut (diproduksi menggunakan jawaban @ edc65):

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

Anda dapat menguji salah satu sistem di halaman ini .

Mencetak gol

Kode terpendek (dalam byte) menang. Aturan standar berlaku.

Lain-lain

Tantangan ini terinspirasi oleh Draw a Random Walk with Slashes . Bahkan, mungkin untuk merepresentasikan jalan acak sebagai sistem-L jika kita memperluas sistem untuk memungkinkan banyak aturan per simbol, dengan ekspansi yang dipilih secara non-determis selama penulisan ulang. Salah satu formulasinya adalah:

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

Ekstensi umum lainnya, yang sering digunakan ketika memodelkan pabrik, adalah untuk menafsirkan karakter [dan] sebagai mendorong dan muncul posisi dan sudut saat ini. Sebagian besar tanaman menggunakan sudut yang lebih kecil dari 90 °, tetapi di sini ada satu contoh yang tidak:

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

Tak satu pun dari contoh ini yang perlu didukung dalam tantangan ini.

Tantangan ini juga mirip dengan "Maaf, anak muda, tetapi Turtles sepenuhnya turun!" . Namun, tantangan itu menggunakan render garis daripada ASCII dan memungkinkan sintaks yang lebih fleksibel.

Uri Granta
sumber

Jawaban:

7

JavaScript (ES6), 440 byte (410 karakter)

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')

Kurang 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')
}

Cuplikan Kode Uji untuk diuji (di Firefox)

edc65
sumber
Jawaban yang bagus (dan cepat!). Saya telah menambahkan tangkapan layar dari keluaran kurva naga dan hilbert ke pertanyaan.
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

Uji coba:

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

Bagaimana itu bekerja:

  • menulis ulang (fungsi g ): Saya menguraikan aturan ke dalam daftar asosiasi (surat -> string pengganti) dan berulang kali memetakannya di atas aksioma.
  • menciptakan jalur (fungsi uuntuk satu langkah): Saya tidak menyimpan jalan di matriks tetapi dalam daftar asosiasi lain dengan (x, y) posisi sebagai kunci dan pola bit dari 4 blok dasar ( , , dan ) sebagai nilai-nilai . Sepanjang jalan saya melacak posisi dan arah saat ini.
  • menggambar path (fungsi f): pertama saya menghitung dimensi max / min dari daftar path dan kemudian saya mengulangi [max y -> min y] dan [min x -> max x] dan mencari blok untuk menggambar.
nimi
sumber
0

ES7, 394 karakter, 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`
`
pengguna74131
sumber