Attack of the Robots
Published on May 09, 2012
Powerful format
format又是一个在common lisp中灵活“过头”,争议超多的一个宏。它十分强大。
基本用法如下
(princ (reverse (format nil "Add onion rings for only ~$ dollars more!" 1.5))) ;;;Control sequences for printing lisp values ;;(prin1 "foo") (format t "I am printing ~s in the middle of this sentence" "foo") ;;(princ "foo") (format t "I am printing ~a in the middle of this sentence" "foo") ;;第一个参数,右边补白 (format t "I am printing ~10a within ten spaces of room." "foo") ;;第二个参数,分成3部分,补白9格 (format t "I am printing ~10,3a within ten (or more) spaces of room." "foo") ;;第三个参数,右边补白4格 (format t "I am printing ~,,4a in the middle of this sentence." "foo") ;;第四个参数,补充符号 (format t "The world ~,,4,'!a feels very important." "foo") (format t "The world ~,,4,'!@a feels very important." "foo") ;;;Control Sequences for formatting numbers ;;Integers (format t "The number 1000 in hexadrcimal is ~x" 1000) (format t "The number 1000 in hexadrcimal is ~b" 1000) (format t "The number 1000 in hexadrcimal is ~d" 1000) ;digit group separators (format t "Numbers with commas in them are ~:d times better." 1000000) (format t "I am printing ~10d within ten spaces of room." 1000000) (format t "I am printing ~10,'xd within ten spaces of room." 1000000) ;;;Control Sequences for formatting Floating-point numbers ;;default (format t "PI can be estimated as ~4f" 3.141593) ;;小数点后数位 (format t "PI can be estimated as ~,4f" pi) ;;Percentage (format t "Percentages are ~,,2f percent better than fractions" 0.77) ;;Format currency (format t "I wish I had ~$ dollars in my bank account." 1000000.2) ;;;Print multiple lines of output ;;terpri (progn (princ 22) (terpri) (princ 33)) ;;fresh-line (progn (princ 22) (fresh-line) (fresh-line) (princ 33)) ;;~% like terpri ;;~& like fresh-line (progn (format t "This is on one line ~%") (format t "~%This is on another line")) (progn (format t "This is on one line ~&") (format t "~&This is on another line")) ;;there can be a number in front of them (format t "this will print ~5%on two lines spread far apart") (format t "this will print ~5&on two lines spread far apart") ;;;Justifying output ;;for example a function (defun random-animal () (nth (random 5) '("dog" "tick" "tiger" "walrus" "kangaroo"))) ;;equally width (loop repeat 10 do (format t "~5t~a ~15t~a ~25t~a~%" (random-animal) (random-animal) (random-animal))) ;;equally apart (loop repeat 10 do (format t "~30<~a~;~a~;~a~>~%" (random-animal) (random-animal) (random-animal))) ;;center (loop repeat 10 do (format t "~30:@<~a~>~%" (random-animal))) (loop repeat 10 do (format t "~30:@<~a~;~a~;~a~>~%" (random-animal) (random-animal) (random-animal))) ;;still wavy?to make it like this (loop repeat 10 do (format t "~10:@<~a~>~10:@<~a~>~10:@<~a~>~%" (random-animal) (random-animal) (random-animal))) ;;;Iterating Through Lists Using Control Sequences ;;Lets create a list of animals (defparameter *animals* (loop repeat 10 collect (random-animal))) ;;loop through sequenses (format t "~{I see a ~a! ~%~}" *animals*) ;;not only one item (format t "~{I see a ~a... or was it a ~a?~%~}" *animals*) ;;;A crazy formatting trick for creating pretty tables of data (format t "|~{~<|~%|~,33:;~2d ~>~}|" (loop for x below 100 collect x))
可以看到,format的参数多的……而且像perl一样有很多“奇怪”的符号。
Attack by robots
让我们接下来看看一个被作者称作可怕的游戏,It's really drive me crazy!!
;;;整个界面大小为16x64,产生个1024长度序列 (defun robots () (loop named main;便于跳出 ;;方向 with directions = '((q . -65) (w . -64) (e . -63) (a . -1) (d . 1) (z . 63) (x . 64) (c . 65)) ;;初始位置 for pos = 544 then (progn (format t "~%qwe/asd/zxc to move, (t)eleport, (l)eave:") (force-output);clean any output not waiting return (let* ((c (read)) (d (assoc c directions))) (cond (d (+ pos (cdr d))) ((eq 't c) (random 1024)) ((eq 'l c) (return-from main 'bye)) (t pos)))) ;;获得monster的位置 for monsters = (loop repeat 10 collect (random 1024)) then (loop for mpos in monsters collect (if (> (count mpos monsters) 1) mpos ;;都走了一遍。 (cdar (sort (loop for (k . d) in directions for new-mpos = (+ mpos d) ;行与列距离和与新位置cons collect (cons (+ (abs (- (mod new-mpos 64) (mod pos 64))) (abs (- (ash new-mpos -6) (ash pos -6)))) new-mpos)) '< :key #'car)))) when (loop for mpos in monsters always (> (count mpos monsters) 1)) return 'player-wins do (format t "~%|~{~<|~%|~,65:;~A~>~}|" (loop for p below 1024 collect (cond ((member p monsters) (cond ((= p pos) (return-from main 'player-loses)) ((> (count p monsters) 1) #\#) (t #\A))) ((= p pos) #\@) (t #\ ))))))
整个游戏就一个函数,由loop和format这种强大的lisp异类来完成。
写在最后
挺好玩的一个游戏。挺难理解的代码……
为了看懂又回头看看作者的loop周期表,再次见识了format和loop的强大之处,也感受到了它们的复杂。