Створення коду схеми піраміди


32

Схема пірамід - це мова, яку розробляє @ ConorO'Brien . У схемі пірамід код, який ви пишете, виглядає приблизно так:

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

Тепер цей код має дві очевидні якості: Важко розібратися, і складно написати. Конор вирішив перше, проте вирішити це друге питання буде ваша робота.


Вищевказаний код обробляється інтерпретатором 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
Загалом не опублікував цього завдання, тому що я лінивий правильно форматувати трикутники ...
Павло

@KodosJohnson Input може бути рідним масивом.
Павло

як ви можете мати функцію з більш ніж двома аргументами?
Руйнуючий лимон

@DestructibleWatermelon Вхід ніколи не буде містити масив, який потребує передачі двох аргументів у піраміду, оскільки це неможливо в схемі пірамід.
Павло

Відповіді:


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

Ось оригінальна (здебільшого) безгольова версія:

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

Спробуйте в Інтернеті!


Ви повинні мати можливість відігравати багато байтів, видаляючи зайві місця.
клісмік

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 репутацій є вагомою ... але ця відповідь заслуговує цього. Загальна відповідь Ліпса на запитання про побудову питань для діалекту Ліспа ... Нічого собі.
wizzwizz4
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.