这就是我的作品wason-deck:
((15 . D) (35 . H) (3 . B) (19 . K) (L . 15) (A . 16) (T . 23) (R . 53)
(N . 13) (M . 7) (I . 52) (35 . Q) (S . 19) (Y . 29) (45 . G) (44 . W)
(11 . V) (J . 25) (21 . F) (39 . Z) (25 . X) (50 . E) (5 . P) (33 . C)
(O . 34))
Run Code Online (Sandbox Code Playgroud)
这是代表Wason牌组的对子列表.(见下文,例6).在牌组中,应该有所有字母与偶数或奇数相匹配的字母,分别取决于元音或辅音.我可以随意随意洗牌并翻转牌.然后我(可选)通过偶尔打破元音随机污染甲板:偶数,辅音:奇数规则.这是我提出的代码:
(defun wason-deck (&optional (p 0))
"This `consolst` and `vowlist` building is unnecessary, but a good exercise"
(let* ((alphab '(a b c d e f g h i j k l m n o p q r s t u v w x y z))
(consonents '(b c d f g h j k l m n p q r s t v w x y z))
(consolst (remove 'NIL (mapcar (lambda (x) (find x consonents)) alphab)))
(vowlst (remove 'NIL (mapcar (lambda (x) (find x '(a e i o))) alphab)))
(wdeck '()))
(labels ((make-consodeck ()
(mapcar (lambda (x) (let ((num (random 54)))
(cons x (if (evenp num)
(1+ num)
num)))) consolst))
(make-voweldeck ()
(mapcar (lambda (x) (let ((num (random 54)))
(cons x (if (oddp num)
(1+ num)
num)))) vowlst))
(swap (slst el1 el2)
(let ((tmp (elt slst el1)))
(setf (elt slst el1) (elt slst el2))
(setf (elt slst el2) tmp)))
(shuffle (slst)
(loop for i in (reverse (range (length slst) :min 1))
do (let ((j (random (+ i 1))))
(swap slst i j)))
slst)
(flip (flst)
(mapcar (lambda (x) (let ((num (random 2)))
(if (zerop num)
(cons (cdr x) (car x))
x))) flst)))
(setf wdeck (flip (shuffle (append (make-consodeck) (make-voweldeck)))))
(if (zerop p) wdeck
(mapcar (lambda (x) (let ((num (random 6)))
(cond ((and (zerop num) (numberp (car x))) (cons (1+ (car x)) (cdr x)))
((and (zerop num) (numberp (cdr x))) (cons (car x) (1+ (cdr x))))
(t x)))) wdeck)))))
Run Code Online (Sandbox Code Playgroud)
它的工作原理,但我担心是不是真的知道我在做什么,也就是我滥用labels的做了,以及setf在代码中.如果一些更高级的人能告诉我这是否完全偏离了错误的方向.
附录:
这是我在得到以下建议后得到的结果:
(defun wason-deck3 (&optional (p 0))
(let* ((consonents '(b c d f g h j k l m n p q r s t v w x y z))
(vowels '(a e i o u))
(conso-deck (mapcar (lambda (x)
(cons x (1+ (* 2 (random 27)))))
consonents))
(vowel-deck (mapcar (lambda (x)
(cons x (* 2 (random 27))))
vowels))
(wdeck '()))
(labels
((shuffle (slst)
(loop :for i :from (1- (length slst)) :downto 1
:do (rotatef (nth i slst)
(nth (random (1+ i)) slst)))
slst)
(flip (flst)
(mapcar (lambda (x) (let ((num (random 2)))
(if (zerop num)
(cons (cdr x) (car x))
x))) flst)))
(setf wdeck (flip (shuffle (append conso-deck vowel-deck)))))
(if (zerop p) wdeck
(mapcar (lambda (x) (let ((num (random 6)))
(cond ((and (zerop num) (numberp (car x))) (cons (1+ (car x)) (cdr x)))
((and (zerop num) (numberp (cdr x))) (cons (car x) (1+ (cdr x))))
(t x)))) wdeck))))
Run Code Online (Sandbox Code Playgroud)
请添加任何新建议.
使用labels完全没问题,而且您的代码并非完全不合理.
几点建议:
我将角色表示为角色: '(#\a #\b #\c …)
我会在其他地方进行我的列表练习,或至少使用set-difference.
当您只为一个调用创建一个函数时,您也可以保存结果:
(let ((consonant-deck (mapcar (lambda (c)
(cons c (1+ (* 2 (random 27)))))
consonants))
(vowel-deck (mapcar (lambda (c)
(cons c (* 2 (random 27))))
vowels)))
…)
Run Code Online (Sandbox Code Playgroud)对于交换,有rotatef:(rotatef (nth i list) (nth j list)).这些东西在列表上相当昂贵,所以我更喜欢使用矢量.然后它派上用场,字符串只是一个字符向量...
Loop 可以为你做计数,你不需要创建列表:
(loop :for i :from (1- (length list)) :downto 1
:do (rotatef (nth i list)
(nth (random (1+ i)) list)))
Run Code Online (Sandbox Code Playgroud)
(使用关键字作为循环关键字是可选的,但缩进应该是这样的.)
如果你把它放在labels周围let,你可以立即绑定wdeck,这样你就不需要setf它了.
您链接到的练习不需要此功能.