; Because case doesn't like quotes (defconstant yes 'yes) (defconstant no 'no) (defconstant it 'it) (defun random-elt (list) "Choose a random element from the given list." (if (null list) nil (elt list (random (length list))))) (defun query-if (question &optional (pred (lambda (answer) t))) "Ask until receive a proper answer." (princ question) (let ((answer (read))) (if (funcall pred answer) answer (query-if question pred)))) (defun twenty-questions (db n) "Guess what's in the user's mind and return the updated database." (if (or (null db) (= n 0)) (let ((answer (query-if "What is it? "))) (if (assoc answer db) db (cons (list answer) db))) (let* ((guess (random-elt db)) (word (first guess)) (remain (remove guess db))) (case (query-if (format nil "Is it a kind of ~a? " word) (lambda (answer) (member answer (list yes no it)))) (yes (cons (cons word (twenty-questions (rest guess) (1- n))) remain)) (no (cons guess (twenty-questions remain (1- n)))) (it db))))) (defun play (&optional (db nil)) "Play again and again." (let ((n (query-if "How many questions can be asked? " #'integerp))) (if (>= n 0) (play (twenty-questions db n)) (print db)))) (play)