สร้างรหัส Pyramid Scheme


32

พีระมิดเป็นภาษาที่ถูกพัฒนาโดย@ ConorO'Brien ใน Pyramid Scheme โค้ดที่คุณเขียนมีลักษณะดังนี้:

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

ตอนนี้รหัสนั้นมีคุณสมบัติที่ชัดเจนสองประการ: มันยากที่จะแยกวิเคราะห์และยากที่จะเขียน Conor ได้แก้ไขปัญหาแรกแล้วอย่างไรก็ตามงานของคุณคือการแก้ไขปัญหาที่สอง


โค้ดด้านบนนั้นประมวลผลโดยตัวแปล PyramidScheme ไปเป็นอาร์เรย์สตริงที่ซ้อนกันเช่นนี้

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

งานของคุณคือการเขียนโปรแกรมหรือฟังก์ชั่นซึ่งกำหนดสตริงที่ซ้อนกันเอาต์พุตหรือส่งคืนรหัส PyramidScheme ที่สร้างขึ้นใหม่ คุณอาจคิดว่าอาร์เรย์อินพุตจะใช้ได้เสมอ

ปิรามิดเป็นสามเหลี่ยมหน้าจั่ว ด้านบนเป็น^ที่ลาดชันด้านแนวทแยงมุมไปด้วย/และและด้านล่างเป็น\ -มุมด้านล่างทั้งสองว่างเปล่าหรือมีจุดเริ่มต้นของปิรามิดอื่นซึ่งเป็นข้อโต้แย้ง ตรงกลางเต็มไปด้วยชื่อของปิรามิดโดยไม่สนใจการแบ่งบรรทัด

นี่คือวิธีที่ parser แปลงรหัสเป็นรูปแบบที่ใช้งานได้ ก่อนอื่นมันจะตรวจหาปิรามิดระดับบนสุด หากไม่มีข้อโต้แย้งมันจะแสดงถึงมันด้วยสตริงเดียวและย้ายไป มิฉะนั้นมันหมายถึงเป็นอาร์เรย์หรือ["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 ที่พิมพ์ได้และไม่ใช่"หรือ[]) เพื่อกำหนดขอบเขตอาร์เรย์ คุณไม่จำเป็นต้องใส่วงเล็บล้อมรอบสิ่งทั้งปวงและใช้อาร์เรย์หลาย ๆ ตัวคั่นด้วยตัวคั่นของคุณ

ผลลัพธ์ของคุณไม่จำเป็นต้องถูกตีกอล์ฟคุณสามารถแทรกพื้นที่เพิ่มเติมหรือทำให้ปิรามิดของคุณใหญ่เกินความจำเป็น ปิรามิด Toplevel ควรอยู่ในบรรทัดแรก เอาต์พุตควรเป็นสตริงที่มีบรรทัดใหม่หรือรายการสตริง

ใครก็ตามที่ไม่รวมถึงรุ่นของรหัสของพวกเขาที่ดีที่สุด Golfs ปิรามิดที่อาจได้รับตัวแทนบางส่วนในรูปแบบของ upvotes / โปรดปราน ( แต่อาจจะเพียงแค่ upvotes)


8
Sierpinski จะรักภาษานี้
mbomb007

4
ทั้งหมดไม่ได้โพสต์ความท้าทายนี้เพราะฉันขี้เกียจเกินไปที่จะรูปแบบสามเหลี่ยมอย่างถูกต้อง ...
พาเวล

@KodosJohnson Input สามารถเป็นอาร์เรย์แบบเนทีฟ
Pavel

คุณจะมีฟังก์ชั่นที่มีมากกว่าสองข้อโต้แย้งได้อย่างไร?
มะนาวที่ถูกทำลายได้

@DestructibleWatermelon อินพุตจะไม่มีอาเรย์ที่จะต้องผ่านสองอาร์กิวเมนต์ไปยังพีระมิดเนื่องจากเป็นไปไม่ได้ใน Pyramid Scheme
Pavel

คำตอบ:


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: ในลูป "สำหรับ" ยังสามารถเขียนได้ "เป็น"; คุณสามารถลบช่องว่างก่อนและหลังวงเล็บและเครื่องหมายคำพูดคู่ คุณสามารถแทนที่ 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), ฯลฯ แต่นี่เป็นคำตอบที่ดีอยู่แล้ว
coredump

2
ชื่อเสียงจำนวน 350 รางวัลมีความสำคัญ ... แต่คำตอบนี้สมควรได้รับ Common Lisp ตอบคำถามเกี่ยวกับการสร้างคำถามสำหรับภาษา Lisp ... ว้าว
wizzwizz4
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.