Pyramid Schemeコードを生成する


32

Pyramid Scheme@ ConorO'Brienによって開発されている言語です。Pyramid Schemeでは、作成するコードは次のようになります。

      ^         ^
     / \       /3\
    /   \      ---
   /  +  \
  ^-------^
 /9\     /3\
/123\    ---
-----

さて、このコードには2つの明らかな性質があります。解析するのが難しく、書くのが難しいということです。Conorは最初の問題を解決しましたが、2番目の問題を解決するのはあなたの仕事です。


上記のコードは、PyramidSchemeインタープリターによって、次のようにネストされた文字列配列に処理されます。

[["+", ["9123", "3"]], "3"]

あなたの仕事は、ネストされた文字列の配列を与え、再作成されたPyramidSchemeコードを出力または返すプログラムまたは関数を書くことです。入力配列は常に有効であると想定できます。

ピラミッドは二等辺三角形です。上部は、^斜めに離れると辺傾き、/及び\、下です-。下の2つの角は空であるか、引数である他のピラミッドの開始点を含んでいます。中央には、改行を無視してピラミッドの名前が表示されます。

パーサーがコードを使用可能な形式に変換する方法を次に示します。まず、最上位のピラミッドをスキャンします。引数をとらない場合、単一の文字列でそれを表し、先に進みます。それ以外の場合は、配列["name",[arg1,arg2]]またはとして表現され["name",[arg1]]ます。引数は、ピラミッドの左下および右下のピラミッドです。これは、上記の文字列または複数の配列のいずれかです。これはLispにやや似ていることに気付くかもしれません。その場合、言語名であるひどいしゃれに気づいたかもしれません。ピラミッドが完全に表示された後、パーサーは次のピラミッドに進みます。

これは、最短のコードが勝ちます!

テストケース:これらは有効な出力だけではなく、有効な出力の例です。

[["+", ["9123", "3"]], "3"]

      ^         ^
     / \       /3\
    /   \      ---
   /  +  \
  ^-------^
 /9\     /3\
/123\    ---
-----

[["out", [["chr", ["72"]], ["chr", ["101"]]]], ["out", [["chr", ["108"]]]], ["out", [["chr", ["108"]]]], ["out", [["chr", ["111"]]]]]

        ^      ^     ^     ^
       / \    / \   / \   / \
      /out\  /out\ /out\ /out\
     ^-----^ -----^----- -----^
    / \   / \    / \         / \
   /chr\ /chr\  /chr\       /chr\
  ^----- -----^ -----^     ^-----
 / \         / \    / \   / \
/72 \       /101\  /108\ /111\
-----       -----  ----- -----

[ ["+", [ ["asdfghjkl"], ["do", [ "1" ]] ]] ]

       ^
      / \
     / + \
    /     \
   ^-------^
  /a\     /d\
 /sdf\   /o  \
/ghjkl\ ^-----
-------/1\
       ---

2番目のテストケースでは、2番目と3番目のoutピラミッドの両方に["chr", ["108"]]パラメーターとしてa があり、2つのトップレベルのピラミッドで共有される1つのピラミッドスタックに折りたたまれています。これは、コードがサポートする有効な最適化ですが、完全にオプションです。スコアリングは、出力の長さに基づいていません。

不思議なことに、9126 3トップレベルピラミッドの暗黙的な印刷のために最初のケースが表示され、2番目のケースが印刷されHello、最後の1つは構文エラーです。


あなたは、入力はスペースのみを除く、印刷可能なASCIIが含まれていると仮定して^/\、と-。入力は常に有効で、少なくとも1つのピラミッドが含まれます。配列または入力文字列のサイズに制限はありませんが、言語のデフォルトの整数型が無限精度であり、コンピューターに任意のメモリがあるかのようにコードを書くことができます。入力を単一の文字列として取得する場合、配列を区切るのに適切なもの(カンマ、スペースなど、印刷可能なasciiであり、not "または[])を使用できます。全体を囲む括弧を含める必要はなく、代わりに区切り文字で区切られた複数の配列を使用します。

出力はゴルフする必要はありません。余分なスペースを挿入するか、ピラミッドを必要以上に大きくすることができます。トップレベルのピラミッド最初の行になければなりません。出力は、改行を含む文字列または文字列のリストでなければなりません。

ピラミッドを最適にゴルフするコードのバージョンを含む人誰でも、賛成票/報奨金の形でいくらかの担当者を受け取ることができます(ただし、おそらく賛成票だけです)。


8
シェルピンスキーはこの言語が大好きです。
mbomb007

4
私は三角形を適切にフォーマットするのが面倒なので、このチャレンジを全く投稿しませんでし
パベル

@KodosJohnson入力はネイティブ配列にすることができます。
パベル

3つ以上の引数を持つ関数を作成するにはどうすればよいですか?
破壊可能なレモン

@DestructibleWatermelon入力には、ピラミッドスキームでは不可能なため、2つの引数をピラミッドに渡す必要があるような配列が含まれることはありません。
パベル

回答:


26

Common Lisp- 2524 1890バイト

(defun f(i)(let((s(loop as r in i collect(g r)))(n())(output""))(loop until n do(setf n T)(loop as r in s do(if(cdr r)(progn(setf output(c output(e r))(cdr r)(cdr(cdr r)))(setf n()))(setf output(c output(b(car r))))))(setf output(c output(format()"~%"))))output))(defun g(r)(if(stringp r)(d(m(length r))r)(if(<(length r)2)(d(m(length(car r)))(car r))(if(=(length(e r))1)(let((h(g(car(e r))))(p(d(m(length(car r)))(car r))))(let((o(+ 1(position #\^(e h))))(parent_length(car p)))(if(<(-(car h)o)parent_length)(l(cons(+ o parent_length)())(loop as n in(butlast(cdr p))collect(c(b o)n))(cons(c(subseq(e h)0 o)(car(last p)))())(loop as n in(cdr(cdr h))collect(c n(b (- parent_length(-(car h)o))))))(let((i(-(- o 1)parent_length)))(l(cons(car h)())(loop as n in(butlast(cdr p))collect(c(b o)n(b i)))(cons(c(subseq(nth 1 h)0 o)(car(last p))(b i))())(cddr h))))))(let((l-h(g(car(e r))))(r-h(g(e(e r)))))(let((ll(position #\^(e l-h)))(rl(position #\^(e r-h))))(let((lr(-(car l-h)ll 1))(rr(-(car r-h)rl 1)))(let((p(d(max(m(length(car r)))(ceiling(+ lr rl)2))(car r))))(let((m-pad(if(>(car p)(+ lr rl))(-(car p)lr rl)0)))(l(cons(+ ll 1(car p)1 rr)())(loop as n in(butlast(cdr p))collect(c(b(+ 1 ll))n(b(+ 1 rr))))(cons(c(subseq(e l-h)0(+ 1 ll))(car(last p))(subseq(e r-h)rl))())(loop as y in(append(cddr l-h)(make-list(length l-h):initial-element(b(car l-h))))as z in(append(cdr(cdr r-h))(make-list(length r-h):initial-element(b(car r-h))))collect(c y(b m-pad)z))))))))))))(defun d(r n)(cons(+(* 2 r)1)(l(cons(c(b r)"^"(b r))())(loop as i from 1 to r collect(c(b(- r i))"/"(subseq(c n(b(expt i 2)))(expt(- i 1)2)(expt i 2))"\\"(b(- r i))))(cons(make-string(+ 1(* 2 r)):initial-element #\-)()))))(defun m(l)(+ 1(floor(sqrt l))))(defun b(n)(make-string n :initial-element #\space))(defun c(&rest a)(apply 'concatenate 'string a))(defun l(&rest a)(apply 'concatenate 'list a))(defun e(tree)(nth 1 tree))

いくつかのゴルフトリックを提供してくれた@coredumpに感謝します。質問からのサンプル出力:

> (f '(("out" (("chr" ("72")) ("chr" ("101")))) ("out" (("chr" ("108")))) ("out" (("chr" ("108")))) ("out" (("chr" ("111"))))))
          ^               ^          ^          ^  
         /o\             /o\        /o\        /o\ 
        /ut \           /ut \      /ut \      /ut \
       /     \         ^-----     ^-----     ^-----
      /       \       /c\        /c\        /c\    
     ^---------^     /hr \      /hr \      /hr \   
    /c\       /c\   ^-----     ^-----     ^-----   
   /hr \     /hr \ /1\        /1\        /1\       
  ^-----    ^-----/08 \      /08 \      /11 \      
 /7\       /1\    -----      -----      -----      
/2  \     /01 \                                    
-----     -----                                    










> (f '( ("+" ( ("asdfghjkl") ("do" ( "1" )) )) ))
          ^        
         /+\       
        /   \      
       /     \     
      /       \    
     /         \   
    ^-----------^  
   /a\         /d\ 
  /sdf\       /o  \
 /ghjkl\     ^-----
/       \   /1\    
---------  /   \   
           -----   








> (f '(("+" ("9123" "3")) "3"))
       ^        ^  
      /+\      /3\ 
     /   \    /   \
    /     \   -----
   ^-------^       
  /9\     /3\      
 /123\   /   \     
/     \  -----     
-------            

以下は、元の(ほとんど)改変されていないバージョンです。

(defun f (input)
    (let ((trees (loop for tree in input collect (g tree)))
          (done nil)
          (output ""))
        (loop while (not done)
            do  (setf done T) 
                (loop for tree in trees
                    do  (if (cdr tree)
                            (progn
                                (setf output (conStr output (car (cdr tree))))
                                (setf (cdr tree) (cdr (cdr tree)))
                                (setf done nil))
                            (setf output (conStr output (blank (car tree))))))
                (setf output (conStr output  (format nil "~%"))))
        output))

;creates a single tree
;output is a list, first element is the length of each line, the rest are the lines of text
(defun g (tree)
    (if (stringp tree)
        ;strings should be drawn as just the pyramid for the name
        (draw-body (min-rows (length tree)) tree)

        (if (< (length tree) 2)
            ;lists with no arguments should be drawn as just the pyramid for the name
            (draw-body (min-rows (length (car tree))) (car tree))
            (if (= (length (car (cdr tree))) 1)
                ;single child
                (let ((child (g (car (car (cdr tree))))) (parent (draw-body (min-rows (length (car tree))) (car tree))))
                    (let ((parent_offset (+ 1 (position #\^ (first-line child)))) (parent_length (car parent)))
                        (if (< (- (car child) parent_offset) parent_length)
                            (let ((child-fill (- parent_length (- (car child) parent_offset))))
                                (concatenate 'list 
                                    (cons (+ parent_offset parent_length) nil)
                                    (loop for line in (butlast (cdr parent))
                                        collect (conStr (blank parent_offset) line))
                                    (cons (conStr (subseq (nth 1 child) 0 parent_offset) (car (last parent))) nil)
                                    (loop for line in (cdr (cdr child))
                                        collect (conStr line (blank child-fill)))))
                            (let ((parent-fill (- (- parent_offset 1) parent_length)))
                                (concatenate 'list 
                                    (cons (car child) nil)
                                    (loop for line in (butlast (cdr parent))
                                        collect (conStr (blank parent_offset) line (blank parent-fill)))
                                    (cons (conStr (subseq (nth 1 child) 0 parent_offset) (car (last parent)) (blank parent-fill)) nil)
                                    (cdr (cdr child)))))))
                ;two children
                (let ((l-child (g (car (car (cdr tree))))) (r-child (g (car (cdr (car (cdr tree)))))))
                    (let ((lc-l-width (position #\^ (first-line l-child))) (rc-l-width (position #\^ (first-line r-child))))
                        (let ((lc-r-width (- (car l-child) lc-l-width 1)) (rc-r-width (- (car r-child) rc-l-width 1)))
                            (let ((parent (draw-body (max (min-rows (length (car tree))) (ceiling (+ lc-r-width rc-l-width) 2)) (car tree))))
                                (let ((m-pad (if (> (car parent) (+ lc-r-width rc-l-width))
                                            (- (car parent) lc-r-width rc-l-width)
                                            0)))
                                    (concatenate 'list
                                        (cons (+ lc-l-width 1 (car parent) 1 rc-r-width) nil)
                                        (loop for line in (butlast (cdr parent))
                                            collect (conStr (blank (+ 1 lc-l-width)) line (blank (+ 1 rc-r-width))))
                                        (cons (conStr (subseq (first-line l-child) 0 (+ 1 lc-l-width)) (car (last parent)) (subseq (first-line r-child) rc-l-width)) nil)
                                        (loop for left in (append (cdr (cdr l-child)) (make-list (length l-child) :initial-element (blank (car l-child))))
                                            for right in (append (cdr (cdr r-child)) (make-list (length r-child) :initial-element (blank (car r-child))))
                                            collect (conStr left (blank m-pad) right))))))))))))


;create a single pyramid
; output is a list, first element is the length of each line, the rest are the lines of text
(defun draw-body (rows name)
    (print rows)
    (print name)
    (cons (+ (* 2 rows) 1)
        (concatenate 'list (cons (conStr (blank rows) "^" (blank rows)) nil)
            (loop for i from 1 to rows
                collect (conStr (blank (- rows i)) "/" (subseq (conStr name (blank (expt i 2))) (expt (- i 1) 2) (expt i 2)) "\\" (blank (- rows i))))
            (cons (make-string (+ 1 (* 2 rows)) :initial-element #\-) nil))))

(defun min-rows (l)
    (+ 1 (floor (sqrt l))))

(defun blank (n)
    (make-string n :initial-element #\space))

(defun conStr (&rest args)
    (apply 'concatenate 'string args))

(defun first-line (tree)
    (car (cdr tree)))

オンラインでお試しください!


不要なスペースを削除することで、多くのバイトをゴルフできるはずです。
clismique

2
PPCGへようこそ。
KritixiのLithos

CLのゴルフのヒント:ループでは、「for」は「as」と書くこともできます。括弧と二重引用符の前後のスペースを削除できます。NILを次のように置き換えることができ()ます。リーダー変数も使用できる場合があります
コアダンプ

... loop while (not x)loop until x(cdr (cdr x))され(cddr x)(setf a b c d)より短い(setf a b)が続く(setf c d)など、しかし、これはすでに良い答えです
コアダンプ

2
350件の評判の合計は重要です...しかし、この答えはそれに値します。Lisp方言の質問の作成に関する質問に対するCommon Lispの回答...うわー。
wizzwizz4
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.