피라미드 체계 코드 생성


32

Pyramid Scheme@ ConorO'Brien 가 개발 한 언어 입니다. Pyramid Scheme에서 작성하는 코드는 다음과 같습니다.

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

이제이 코드에는 두 가지 명백한 특성이 있습니다. 구문 분석하기가 어렵고 작성하기가 어렵습니다. Conor는 첫 번째 문제를 해결했지만 두 번째 문제를 해결하는 것이 귀하의 임무입니다.


위 코드는 PyramidScheme 인터프리터에서 다음과 같이 중첩 된 문자열 배열로 처리됩니다.

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

작업은 중첩 된 문자열 배열, 출력 또는 재생성 된 PyramidScheme 코드를 반환하는 프로그램 또는 함수를 작성하는 것입니다. 입력 배열이 항상 유효하다고 가정 할 수 있습니다.

피라미드는 이등변 삼각형입니다. 상단은 ^대각선 거리와 경사 변, /\, 상기 아래쪽이다 -. 두 개의 하단 모서리는 비어 있거나 다른 피라미드의 시작을 포함합니다. 가운데 부분은 줄 바꿈을 무시하고 피라미드 이름으로 채워져 있습니다.

파서가 코드를 사용 가능한 형식으로 변환하는 방법은 다음과 같습니다. 먼저 최상위 피라미드를 스캔합니다. 인수가 없으면 단일 문자열로 표시하고 계속 진행합니다. 그렇지 않으면,는 배열 ["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\
       ---

두 번째 테스트 사례에서 두 번째 및 세 번째 out피라미드는 모두 ["chr", ["108"]]매개 변수로 두 개의 최상위 스택이 공유하는 하나의 피라미드 스택으로 축소됩니다. 이것은 코드가 지원할 수있는 유효한 최적화이지만 완전히 선택적입니다. 점수는 출력 길이를 기준으로하지 않습니다.

궁금한 점 9126 3은 최상위 피라미드의 암시 적 인쇄로 인해 첫 번째 경우가 표시되고 두 번째 경우가 인쇄 Hello되며 마지막 것은 깔끔한 구조를 가지고 있기 때문에 구문 오류입니다.


당신은 입력이 인쇄 가능한 ASCII 제외한 공백이 포함되어 있다고 가정 할 수있다 ^, /, \,와 -. 입력은 항상 유효하며 하나 이상의 피라미드를 포함합니다. 배열 또는 입력 문자열의 크기에는 제한이 없지만 언어의 기본 정수 유형이 무한정 정밀도이고 컴퓨터에 임의의 메모리가있는 것처럼 코드를 작성할 수 있습니다. 입력을 단일 문자열 로 사용하는 경우 배열을 구분하기 위해 인쇄 가능한 ASCII 형식으로되어 "있거나 아닌 한 합리적 (쉼표, 공백 등 [])을 사용할 수 있습니다. 전체를 둘러싼 대괄호를 포함 할 필요는 없으며 대신 구분 기호로 구분 된 여러 배열을 가져옵니다.

출력물을 골퍼 할 필요가 없습니다. 여분의 공간을 추가하거나 피라미드를 필요 이상으로 크게 만들 수 있습니다. 최상위 피라미드 첫 번째 줄에 있어야 합니다. 출력은 줄 바꿈이있는 문자열이거나 문자열 목록이어야합니다.

누구 않는 최적의 피라미드를 골프를 친다 자신의 코드의 버전을 포함는 upvotes / 상금 (그러나 아마 upvotes)의 형태로 일부 담당자를받을 수 있습니다.


8
시 에르 핀 스키는이 언어를 좋아할 것입니다.
mbomb007

4
삼각형을 올바르게 포맷하기에는 너무 게으 르기 때문에 완전히이 도전을 게시하지 않았습니다 ...
Pavel

@KodosJohnson 입력은 기본 배열 일 수 있습니다.
Pavel

두 개 이상의 인수를 가진 함수를 어떻게 가질 수 있습니까?
Destructible Lemon

@DestructibleWatermelon 피라미드 배열에서는 불가능하기 때문에 입력에는 배열에 두 개의 인수를 전달해야하는 배열이 포함되지 않습니다.
Pavel

답변:


26

공통 리스프 -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\   /   \     
/     \  -----     
-------            

다음은 원래 (구체적으로) ungolfed 버전입니다.

(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을 다음과 같이 대체 할 수 있습니다 (). 때때로 리더 변수를 사용할 수도 있습니다
coredump

... 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 방언에 대한 질문을 구성하는 것에 대한 질문에 대한 일반적인 Lisp 답변 ... 와우.
wizzwizz4
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.