ASCII Lシステムレンダラー


16

バックグラウンド

L-システム(又はLindenmayerシステム)は、とりわけ、容易にモデルフラクタルに使用することができ、平行書き換えシステムです。この質問は、決定論的でコンテキストのないLシステムに関するものです。これらは、アルファベットの記号、初期公理文字列、および各アルファベット記号を新しい文字列にマッピングする一連の書き換えルールで構成されています。ルールは公理に並行して適用され、新しい文字列が生成されます。その後、このプロセスが繰り返されます。

たとえば、公理「A」とルールA = ABA; B = BBBを使用するシステムは、文字列「ABA」、「ABABBBABA」、「ABABBBABABBBBBBBBBABABBBABA」などのシーケンスを生成します。簡潔にするために、明示的に言及しませんLシステムを定義するときのアルファベット。さらに、明示的な書き換えルールのないシンボルは変更されていないと見なされます(つまり、シンボルAのデフォルトルールはA = Aです)。

Lシステムは、タートルグラフィックスの形式を使用して視覚化できます。慣例により、亀は右向きになります。文字列は、そのシンボルを反復して描画されます。Fは「1単位前方に描画」、Gは「1単位前方に移動」、+は「1単位左に曲がる」、-は「1単位右に曲がる」ことを意味します単位"。文字列内の他のすべてのシンボルは無視されます。この質問のために、角度単位は常に90°であると想定されています。

仕事

Lシステムの仕様と反復回数が指定されている場合、プログラムは、ボックス描画文字を使用して、結果の文字列のASCIIレンダリング(上記の説明を参照)を出力する必要があります。

  • パラメーターは、公理、書き換え規則(方程式の;区切りのリストとして)、および書き換えの反復回数を含むスペース区切りの文字列として渡されます。たとえば、入力 "FF = FGF; G = GGG 2"は文字列 "FGFGGGFGF"を生成するため、適切なギャップで4本の線を描画します。
  • Lシステムで使用される記号は、スペースとセミコロンを除く任意のASCII文字にすることができます。シンボルごとに指定される明示的なルールは最大で1つです(上記のように、デフォルトの書き換えルールはIDマッピングです)。
  • 出力には常に少なくとも1つの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"

最初の2つは次のようになります(@ edc65の回答を使用して作成)。

ここに画像の説明を入力してください ここに画像の説明を入力してください

このページでシステムをテストできます

得点

最短コード(バイト単位)が優先されます。標準ルールが適用されます。

その他

このチャレンジは、スラッシュでランダムウォークを描くことに触発されました。実際、書き換え中に非決定論的に選択された展開で、シンボルごとに複数のルールを許可するようにシステムを拡張すると、ランダムウォークをLシステムとして表すことができます。1つの定式化は次のとおりです。

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

植物のモデリングによく使用されるもう1つの一般的な拡張は、[と]の文字を現在の位置と角度をプッシュおよびポップするものとして解釈することです。ほとんどの植物は90°より小さい角度を使用しますが、次のような例ではありません。

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

この課題では、これらの例のどちらもサポートする必要はありません。

この課題は、「申し訳ありませんが、若い男ですが、それはずっと亀です!」。ただし、この課題ではASCIIではなくラインレンダリングが使用され、より柔軟な構文が許可されました。

回答:


7

JavaScript(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の場合)


素晴らしく(そして迅速に!)答えてください。ドラゴンとヒルベルト曲線の出力のスクリーンショットを質問に追加しました。
ウリグランタ

6

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

使い方:

  • 書き換え(関数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.