Tạo mã Đề án Kim tự tháp


32

Pyramid Scheme là một ngôn ngữ đang được phát triển bởi @ ConorO'Brien . Trong sơ đồ Kim tự tháp, mã mà bạn viết trông như thế này:

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

Bây giờ, mã đó có hai phẩm chất rõ ràng: khó phân tích và khó viết. Conor đã giải quyết vấn đề thứ nhất, tuy nhiên công việc của bạn là giải quyết vấn đề thứ hai đó.


Đoạn mã trên được trình thông dịch PyramidScheme xử lý thành một chuỗi chuỗi lồng nhau, như sau:

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

Nhiệm vụ của bạn là viết một chương trình hoặc hàm, đưa ra một chuỗi các chuỗi lồng nhau, xuất ra hoặc trả về mã PyramidScheme được tạo lại. Bạn có thể cho rằng mảng đầu vào sẽ luôn hợp lệ.

Một hình chóp là một tam giác cân. Phía trên là ^, các cạnh dốc theo đường chéo với /\, và phía dưới là -. Hai góc dưới cùng trống hoặc chứa phần bắt đầu của các kim tự tháp khác, là đối số. Phần giữa chứa đầy tên của kim tự tháp, bỏ qua các ngắt dòng.

Dưới đây là cách trình phân tích cú pháp chuyển đổi mã thành định dạng có thể sử dụng. Đầu tiên, nó quét một kim tự tháp cấp cao nhất. Nếu nó không có đối số, nó đại diện cho nó bằng một chuỗi duy nhất và tiếp tục. Mặt khác, nó đại diện là một mảng ["name",[arg1,arg2]]hoặc ["name",[arg1]]. Các đối số là các kim tự tháp ở dưới cùng bên trái và dưới cùng bên phải của kim tự tháp, có thể là chuỗi hoặc nhiều mảng được mô tả như trên. Bạn có thể nhận thấy rằng điều này hơi giống với Lisp, trong trường hợp đó bạn cũng có thể nhận thấy cách chơi chữ khủng khiếp đó là tên ngôn ngữ. Sau khi kim tự tháp được thể hiện đầy đủ, trình phân tích cú pháp chuyển sang cái tiếp theo.

Đây là , mã thắng ngắn nhất!

Các trường hợp kiểm tra: Đây không phải là đầu ra hợp lệ duy nhất, đây là những ví dụ về đầu ra hợp lệ.

[["+", ["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\
       ---

Lưu ý trong trường hợp thử nghiệm thứ hai, outcả kim tự tháp thứ hai và thứ ba đều có ["chr", ["108"]]một tham số, được thu gọn thành một ngăn xếp kim tự tháp được chia sẻ bởi hai kim tự tháp cấp cao nhất. Đây là một tối ưu hóa hợp lệ mà mã của bạn có thể hỗ trợ, nhưng nó hoàn toàn không bắt buộc; chấm điểm không dựa trên độ dài của đầu ra của bạn.

Đối với người tò mò, trường hợp đầu tiên hiển thị 9126 3do in ngầm các kim tự tháp toplevel, trường hợp thứ hai in Hellovà trường hợp cuối cùng là lỗi cú pháp, bao gồm chỉ vì nó có cấu trúc gọn gàng.


Bạn có thể giả định rằng đầu vào chỉ chứa ASCII in được, không bao gồm khoảng trắng, ^, /, \, và -. Đầu vào sẽ luôn hợp lệ và chứa ít nhất một kim tự tháp. Không có giới hạn về kích thước của mảng hoặc chuỗi đầu vào, tuy nhiên bạn có thể viết mã của mình như thể loại số nguyên mặc định của ngôn ngữ của bạn là chính xác vô hạn và máy tính của bạn có bộ nhớ tùy ý. Nếu lấy đầu vào dưới dạng một chuỗi, bạn có thể sử dụng bất cứ thứ gì hợp lý (dấu phẩy, dấu cách, v.v ... miễn là nó có thể in ascii và không "hoặc []) để phân định mảng. Bạn không phải bao gồm các dấu ngoặc bao quanh toàn bộ, và thay vào đó lấy nhiều mảng được phân tách bằng dấu phân cách của bạn.

Đầu ra của bạn không cần phải đánh gôn, bạn có thể chèn thêm không gian hoặc làm cho kim tự tháp của bạn lớn hơn mức cần thiết. Kim tự tháp Toplevel nên ở dòng đầu tiên. Đầu ra phải là một chuỗi có dòng mới hoặc danh sách các chuỗi.

Bất cứ ai không bao gồm một phiên bản của mã của họ mà tối ưu Tất chơi gôn các kim tự tháp có thể nhận được một số đại diện theo hình thức upvotes / bounties (nhưng có lẽ chỉ upvotes).


8
Sierpinki sẽ thích ngôn ngữ này.
mbomb007

4
Hoàn toàn không đăng thử thách này vì tôi quá lười để định dạng hình tam giác đúng cách ...
Pavel

@KodosJohnson Input có thể là một mảng nguyên gốc.
Pavel

Làm thế nào bạn có thể có một hàm có nhiều hơn hai đối số?
Lemon phá hủy

@DeststallibleWateriwi Đầu vào sẽ không bao giờ chứa một mảng sao cho nó sẽ yêu cầu chuyển hai đối số cho một kim tự tháp, vì điều này là không thể trong Lược đồ Kim tự tháp.
Pavel

Câu trả lời:


26

Lisp thường gặp - 2524 1890 byte

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

Cảm ơn @coredump cho một số thủ thuật chơi gôn. Đầu ra mẫu từ câu hỏi:

> (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\   /   \     
/     \  -----     
-------            

Đây là phiên bản gốc, (hầu hết) không có bản quyền:

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

Hãy thử trực tuyến!


Bạn sẽ có thể loại bỏ rất nhiều byte bằng cách loại bỏ các khoảng trống không cần thiết.
clismique

2
Chào mừng bạn đến với PPCG và câu trả lời đầu tiên tốt đẹp!
Kritixi Lithos

Một số mẹo để chơi gôn CL: trong các vòng lặp, "cho" cũng có thể được viết "là"; bạn có thể xóa khoảng trắng trước và sau dấu ngoặc đơn và dấu ngoặc kép; bạn có thể thay thế NIL bằng cách (); đôi khi bạn cũng có thể sử dụng các biến độc giả
coredump

... loop while (not x)loop until x, (cdr (cdr x))(cddr x), (setf a b c d)ngắn hơn (setf a b)theo sau (setf c d), v.v. Nhưng đây đã là một câu trả lời hay
coredump

2
Tổng số tiền thưởng của 350 danh tiếng là rất đáng kể ... nhưng câu trả lời này xứng đáng. Câu trả lời chung của Lisp cho câu hỏi về cách xây dựng câu hỏi cho phương ngữ Lisp ... Wow.
wizzwizz4
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.