Trình kết xuất hệ thống L của ASCII


16

Lý lịch

Một hệ thống L (hay hệ thống Lindenmayer) là một hệ thống viết lại song song, trong số những thứ khác, có thể dễ dàng được sử dụng để mô hình các fractals. Câu hỏi này liên quan đến các hệ thống L xác định, không bối cảnh . Chúng bao gồm một bảng chữ cái các ký hiệu, một chuỗi tiên đề ban đầu và một bộ quy tắc viết lại ánh xạ mỗi ký hiệu bảng chữ cái thành một chuỗi mới. Các quy tắc được áp dụng song song cho tiên đề, tạo ra một chuỗi mới. Quá trình này sau đó được lặp lại.

Ví dụ: hệ thống có tiên đề "A" và các quy tắc A = ABA; B = BBB tạo ra chuỗi các chuỗi "ABA", "ABABBBABA", "ABABBBABABBBBBBBBBABABABABAB", v.v. bảng chữ cái khi xác định hệ thống L. Hơn nữa, bất kỳ ký hiệu nào không có quy tắc viết lại rõ ràng được coi là không thay đổi (tức là quy tắc mặc định cho ký hiệu A là A = A).

Hệ thống L có thể được hình dung bằng cách sử dụng một hình thức đồ họa rùa. Theo quy ước, con rùa bắt đầu quay mặt sang phải. Sau đó, một chuỗi được vẽ bằng cách lặp qua các ký hiệu của nó: F có nghĩa là "vẽ về phía trước một đơn vị", G có nghĩa là "di chuyển về phía trước một đơn vị", + có nghĩa là "rẽ trái một đơn vị góc" và a - có nghĩa là "rẽ phải một góc đơn vị". Tất cả các biểu tượng khác trong chuỗi được bỏ qua. Đối với mục đích của câu hỏi này, các đơn vị góc được giả định luôn là 90 °.

Bài tập

Đưa ra một đặc điểm kỹ thuật của bất kỳ hệ thống L nào và một số lần lặp, chương trình của bạn sẽ xuất ra kết xuất ASCII của chuỗi kết quả (như được mô tả ở trên) bằng cách sử dụng các ký tự vẽ hộp.

  • Các tham số được truyền vào dưới dạng một chuỗi được phân tách bằng dấu cách bao gồm các tiên đề, viết lại các quy tắc (dưới dạng một danh sách các phương trình được phân tách) và số lần lặp lại. Ví dụ: đầu vào "FF = FGF; G = GGG 2" tạo ra chuỗi "FGFGGGFGF" và do đó rút ra bốn dòng với các khoảng trống thích hợp.
  • Các ký hiệu được sử dụng bởi hệ thống L có thể là bất kỳ ký tự ASCII nào ngoài dấu cách và dấu chấm phẩy. Có nhiều nhất một quy tắc rõ ràng được chỉ định cho mỗi biểu tượng (với quy tắc viết lại mặc định là ánh xạ định danh như được mô tả ở trên).
  • Bạn có thể giả sử rằng đầu ra sẽ luôn chứa ít nhất một F.
  • Đầu ra phải sử dụng các ký tự vẽ hộp UNICODE sau đây để thể hiện trực quan hóa: ─ (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) và ╷ (U + 2577). Xem bên dưới để biết ví dụ.
  • Đầu ra không được chứa các dòng trống phía trên ký tự hộp trên cùng hoặc bên dưới ký tự dưới cùng. Nó cũng không được chứa bất kỳ khoảng trắng nào ở bên trái của trình sắp xếp hộp ngoài cùng bên trái hoặc bên phải của hộp ngoài cùng bên phải. Các dòng có dấu cách không vượt quá ký tự hộp ngoài cùng bên phải được cho phép.

Bạn có thể viết chương trình hoặc hàm, lấy đầu vào qua STDIN (hoặc thay thế gần nhất), đối số dòng lệnh hoặc đối số hàm. Kết quả phải được in thành STDOUT (hoặc thay thế gần nhất), được lưu vào một tệp hoặc được trả lại dưới dạng chuỗi.

Ví dụ

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

Các ví dụ khác để kiểm tra chương trình của bạn bao gồm:

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

Hai trong số đó trông như sau (được tạo bằng câu trả lời của @ edc65):

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

Bạn có thể kiểm tra bất kỳ hệ thống nào tại trang này .

Chấm điểm

Mã ngắn nhất (tính bằng byte) sẽ thắng. Quy tắc tiêu chuẩn áp dụng.

Miscellania

Thử thách này được lấy cảm hứng từ Draw a Random Walk with Slashes . Trên thực tế, có thể biểu diễn bước đi ngẫu nhiên dưới dạng hệ thống L nếu chúng tôi mở rộng hệ thống để cho phép nhiều quy tắc cho mỗi biểu tượng, với phần mở rộng được chọn không xác định trong quá trình viết lại. Một công thức là:

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

Một phần mở rộng phổ biến khác, thường được sử dụng khi mô hình hóa các nhà máy, là để giải thích các ký tự [và] là đẩy và bật vị trí và góc hiện tại. Hầu hết các nhà máy sử dụng các góc nhỏ hơn 90 °, nhưng đây là một ví dụ không:

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

Cả hai ví dụ này đều cần được hỗ trợ trong thử thách này.

Thử thách này cũng tương tự như "Xin lỗi, chàng trai trẻ, nhưng đó là Rùa suốt chặng đường!" . Tuy nhiên, thách thức đó đã sử dụng kết xuất dòng thay vì ASCII và cho phép cú pháp linh hoạt hơn.

Câu trả lời:


7

JavaScript (ES6), 440 byte (410 ký tự)

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

Ít chơi gôn

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

Kiểm tra đoạn mã để kiểm tra (trong Firefox)


Câu trả lời tuyệt vời (và nhanh chóng!). Tôi đã thêm ảnh chụp màn hình của đầu ra đường cong rồng và hilbert vào câu hỏi.
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

Chạy thử nghiệm:

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

Làm thế nào nó hoạt động:

  • viết lại (hàm g): Tôi phân tích các quy tắc thành một danh sách liên kết (chữ cái -> chuỗi thay thế) và liên tục ánh xạ nó qua tiên đề.
  • tạo đường dẫn (chức năng ucho một bước duy nhất): Tôi không lưu trữ các con đường trong một ma trận nhưng trong một danh sách liên kết với (x, y) vị trí như các phím và các mẫu bit của 4 khối cơ bản ( , , ) như các giá trị . Trên đường đi, tôi theo dõi vị trí và hướng hiện tại.
  • vẽ đường dẫn (hàm f): đầu tiên tôi tính các kích thước tối đa / phút từ danh sách đường dẫn và sau đó tôi lặp lại [max y -> min y] và [min x -> max x] và tra cứu các khối để vẽ.

0

ES7, 394 ký tự, 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`
`
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.