(defun print-diamond (str x &optional c a (max (1+ x)) (star "*"))
(format str "~&~[~:;~:*~vT~v@{~A ~:*~}~3@*~v,v/print-diamond/~:*~v[~:;~@*~vT~v@{~A ~:*~}~%~]~]"
x (- max x) star max star (1- x)))
Now for an explanation of that format string.
Bear with me this is hairy.
- ~& : Conditional newline (insert newline if we aren't at the start of a line)
- ~[ : Process the nth clause (seperated by ~:). ~:; specifies a default clause. This consumes the argument x. This directive causes print-diamond to stop processing when x is zero.
- ~:* : Backup 1 argument (unconsumes the argument x)
- ~vT : Insert arg number of spaces (this reconsumes the first argument ie. x)
- ~v@{ : Iterate v times, v is (- max x).
- ~A : Print 1 element
- ~:* : Backup 1 element (The effects of the last 3 directives is to print star (- max x) times)
- ~} : End loop
- ~3@ : Move to the 3rd argument (star)
- ~v,v/print-diamond/ : The recursive call. invoke print-diamond again with max, star and (1- x), This is equivalent to calling (print-diamond stream (1- x) nil nil max star)
- ~:* : Backup 1 argument (unconsumes (1- x))
- ~v[ : Conditional processing based (1- x).
- ~@* : Go to the start of the argument list.
- ~vT : Insert arg number of spaces (this consumes the first argument again)
- ~v@{ : Iterate v times, v is (- max x).
- ~A : Print 1 element
- ~:* : Backup 1 element (The effects of the last 3 directives is to print star (- max x) times)
- ~} : End loop
- ~% : Insert a new line
- ~] : End conditional processing
- ~] End conditional processing
Whew, brain freeze.
now we can do
(print-diamond t 10)
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *
* * * * * * * * * *
* * * * * * * * *
* * * * * * * *
* * * * * * *
* * * * * *
* * * * *
* * * *
* * *
* *
*