ASCII L 시스템 렌더러


16

배경

L 시스템 (또는 시스템 인 Lindenmayer)는 다른 것들 중에서, 쉽게 모델 도형을 사용할 수 있고, 병렬 재기록 시스템이다. 이 질문은 결정 론적이며 맥락이없는 L- 시스템에 관한 것이다. 이들은 알파벳 기호, 초기 공리 문자열 및 각 알파벳 기호를 새 문자열에 매핑하는 다시 쓰기 규칙 세트로 구성됩니다. 규칙은 공리에 병렬로 적용되어 새 문자열을 생성합니다. 그런 다음이 과정이 반복됩니다.

예를 들어, 공리가 "A"이고 규칙 A = ABA; B = BBB 인 시스템은 문자열 "ABA", "ABABBBABA", "ABABBBABABBBBBBBBBBBABABABABA"등의 시퀀스를 생성합니다. 간결성을 위해 L 시스템을 정의 할 때 알파벳. 또한, 명시적인 다시 쓰기 규칙이없는 모든 기호는 변경되지 않은 것으로 간주됩니다 (즉, 기호 A의 기본 규칙은 A = A 임).

L 시스템은 거북이 그래픽 형식을 사용하여 시각화 할 수 있습니다. 일반적으로 거북이는 오른쪽을 향합니다. 그런 다음 문자열은 기호를 반복하여 그려집니다. F는 "한 단위 앞으로 이동"을 의미하고, G는 "한 단위 앞으로 이동"을 의미하고, +는 "한 단위 왼쪽으로 회전"을 의미하고-는 "한 각도 오른쪽으로 회전"을 의미합니다 단위". 문자열의 다른 모든 기호는 무시됩니다. 이 질문의 목적으로, 각도 단위는 항상 90 ° 인 것으로 가정합니다.

직무

L 시스템의 사양과 여러 반복이 주어지면 프로그램은 상자 그리기 문자를 사용하여 결과 문자열의 ASCII 렌더링을 출력해야합니다 (위에서 설명한 것처럼).

  • 매개 변수는 공리, 재 작성 규칙 (;-분리 된 방정식 목록으로) 및 재 작성 반복 횟수를 포함하는 공백으로 구분 된 문자열로 전달됩니다. 예를 들어, 입력 "FF = FGF; G = GGG 2"는 문자열 "FGFGGGFGF"를 생성하므로 적절한 간격으로 4 개의 선을 그립니다.
  • L 시스템에서 사용하는 기호는 공백 및 세미콜론을 제외한 ASCII 문자 일 수 있습니다. 심볼 당 최대 하나의 명시 적 규칙이 지정됩니다 (기본 재 작성 규칙은 위에서 설명한대로 ID 매핑 임).
  • 출력에 항상 하나 이상의 F가 포함된다고 가정 할 수 있습니다.
  • 출력은 시각화를 나타내는 다음 UNICODE 상자 그리기 문자 를 사용해야합니다 . ─ (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) 및 ╷ (U + 2577). 예는 아래를 참조하십시오.
  • 출력은 맨 위 상자 문자 위 또는 맨 아래 문자 아래에 빈 줄을 포함해서는 안됩니다. 또한 가장 왼쪽 상자 문자 왼쪽이나 오른쪽 가장 오른쪽에 공백이 없어야합니다. 맨 오른쪽 상자 문자 이상으로 확장되지 않는 후행 공백이있는 행은 허용됩니다.

STDIN (또는 가장 가까운 대안), 명령 행 인수 또는 함수 인수를 통해 입력을받는 프로그램 또는 함수를 작성할 수 있습니다. 결과는 STDOUT (또는 가장 가까운 대안)으로 인쇄되거나 파일로 저장되거나 문자열로 리턴되어야합니다.

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

프로그램을 테스트하는 다른 예는 다음과 같습니다.

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

처음 두 개는 다음과 같이 보입니다 (@ edc65의 답변을 사용하여 생성됨).

여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오

이 페이지 에서 모든 시스템을 테스트 할 수 있습니다 .

채점

가장 짧은 코드 (바이트)가 이깁니다. 표준 규칙이 적용됩니다.

기타

이 도전은 슬래시로 랜덤 워크 그리기 에서 영감을 얻었습니다 . 실제로 재 작성하는 동안 확장이 비 결정적으로 선택된 상태에서 심볼 당 여러 규칙을 허용하도록 시스템을 확장하는 경우 무작위 보행을 L- 시스템 으로 표현할 수 있습니다. 한 가지 공식은 다음과 같습니다.

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

플랜트를 모델링 할 때 자주 사용되는 또 다른 확장은 [및] 문자를 현재 위치 및 각도를 밀고 터뜨리는 것으로 해석하는 것입니다. 대부분의 식물은 90 °보다 작은 각도를 사용하지만 다음은 그렇지 않은 예입니다.

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

이 과제에서 이러한 예 중 어느 것도 지원 될 필요는 없습니다.

이 도전은 또한 "죄송합니다. 청년이지만 거북입니다!" 와 비슷 합니다. . 그러나이 문제는 ASCII 대신 라인 렌더링을 사용했으며보다 유연한 구문을 허용했습니다.

답변:


7

자바 스크립트 (ES6), 440 바이트 (410 자)

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

덜 골프

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

테스트 할 코드 스 니펫 (Firefox에서)


대단하고 빠른 답변입니다. 드래곤과 힐버트 커브 출력의 스크린 샷을 질문에 추가했습니다.
Uri Granta

6

하스켈, 568 바이트

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

시운전 :

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

작동 방식 :

  • rewriting (function g) : 규칙을 연관 목록 (문자-> 대체 문자열)으로 구문 분석하고 반복적으로 공리에 맵핑합니다.
  • (함수 경로를 만들어 u단일 단계) : I 매트릭스뿐만 4 개 기본 블록의 키 비트 패턴 등 (x, y)의 위치와 다른 연관리스트에 경로를 저장하지 않는다 ( , , ) 값으로 . 그 길을 따라 현재 위치와 방향을 추적합니다.
  • 경로 그리기 (함수 f) : 먼저 경로 목록에서 최대 / 최소 치수를 계산 한 다음 [max y-> min y] 및 [min x-> max x]를 반복하고 그릴 블록을 찾습니다.

0

ES7, 394 자, 424 바이트

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`
`
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.