about summary refs log tree commit diff
path: root/paip/twenty-questions.lisp
diff options
context:
space:
mode:
Diffstat (limited to 'paip/twenty-questions.lisp')
-rw-r--r--paip/twenty-questions.lisp43
1 files changed, 43 insertions, 0 deletions
diff --git a/paip/twenty-questions.lisp b/paip/twenty-questions.lisp
new file mode 100644
index 0000000..fed4997
--- /dev/null
+++ b/paip/twenty-questions.lisp
@@ -0,0 +1,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)