about summary refs log tree commit diff
path: root/paip/twenty-questions.lisp
blob: fed499786c2140b2ac20c4be6be58443139e43fc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
; 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)