(defun string-replace-all (string substring replacement)
(let ((s string)
(x substring)
(x-len (length substring)))
(loop for pos1 = 0 then (+ pos2 x-len)
for pos2 = (search x s :start2 pos1)
while pos2
append (list (subseq s pos1 pos2)
replacement)
into result
finally (return (format nil "~{~A~}~A"
result (subseq s pos1))))))
(defun max-length (sequence)
(apply #'max (map 'list (lambda (x) (length x)) sequence)))
(defun odai-pt13-681 (n &key (justify :center)
(dot "::")
(dot-display-width (length (string dot)))
&aux (placeholder (make-string dot-display-width
:initial-element #\*)))
(labels ((r (n lines)
(if (= n 0)
lines
(r (1- n)
(append (mapcar (lambda (line)
(format nil "~@?"
(ecase justify
(:center "~v:@<~A~>")
(:left "~v@<~A~>")
(:right "~v:<~A~>"))
(+ (max-length lines)
(length line))
line))
lines)
(mapcar (lambda (line)
(format nil "~A~A" line line))
lines))))))
(format nil "~{~A~%~}"
(mapcar (lambda (s) (string-replace-all s placeholder dot))
(r n (list placeholder))))))
(loop for n from 0 upto 5
do (format t "~%n=~D~%~A~%"
n (odai-pt13-681 n :dot #\木 :dot-display-width 2)))
(loop for justify in '(:left :center :right)
do (format t "~A~%" (odai-pt13-681 4 :dot "##" :justify justify)))