在LispWorks中进行编程19:动物
Category:UI界面编写动物
动物程序已经在许多编程教程中使用,因为它实现起来既有趣又简单,并演示了计算机如何使用用户的输入以交互方式构建数据库。通过利用语言强大的列表处理功能,它可以在Lisp中非常优雅地编写。
完整列表
描述
动物游戏试图猜测你正在考虑的动物。要玩游戏,您只需输入:
CL-USER > (play-animals)
然后程序会询问一系列问题,例如:
你酌情回答是或否。最终它猜测了这只动物:
如果它是正确的,游戏结束。然而,如果你点击任何程序提示:
然后,系统会提示您向树中添加问题:
最后,程序需要知道新动物的正确答案:
由于这种互动,新动物已被添加到数据库中,下次您播放该程序时将了解新动物。
设计程序
我们将数据库表示为问题和动物的树。该计划以一个问题和两个动物开始:
我们将树表示为Lisp列表,形式如下:
(question yes-answer no-answer)
因此,对于上面显示的树,列表将是:
(“Does it live in the sea?” “a dolphin” “a horse”)
我们将数据库树存储在一个名为* tree *的变量中,因此我们将首先定义:
(defparameter animals-tree ‘(“Does it live in the sea?” “a dolphin” “a horse”))
在用另外两只动物训练之后,树可能看起来像这样:
这是Lisp表示,缩进以使结构更清晰:
(“Does it live in the sea?” “a dolphin” (“Does it have 4 legs?” “a horse” (“Can it fly?” “a raven” “a human”)))
我们将用四个独立的功能构建动物程序:学习动物,猜测,提问和动物。虽然我们可以结合其中的一些功能,但将其分解为小的独立构建块的优点是我们可以独立地测试每个功能。
学习一种新动物
首先让我们定义学习新动物的程序:
(defun learn-animal (animal new-animal) (let ((question (capi:prompt-for-string (format nil “Give me a yes/no question to distinguish between ~a and ~a” new-animal animal)))) (if (capi:prompt-for-confirmation (format nil “What would the answer be for ~a?” new-animal)) (list question animal new-animal)) (list question new-animal animal)))
这需要两个参数:现有动物和新动物。它会提示问题,以及新动物的正确答案,并以正确的顺序返回问题和答案的列表。例如:
(learn-animal “a cat” “a dog”)
会提示:
给我一个是/否的问题来区分狗和猫
和
狗的答案是什么?
并返回适当的清单; 例如
(“Does it bark?” “a dog” “a cat”)
猜猜看
当我们到达树上的动物时,会调用下一个程序make-guess。它以动物为参数,并将其作为答案。如果它是正确的,它只是返回动物。如果不正确,则调用learn-animal创建包含新问题和两个答案的列表。
(defun make-guess (animal) (if (capi:prompt-for-confirmation (format nil “Is it ~a?” animal)) (let ((message (capi:display-message “Ho ho!”))) animal) (learn-animal animal (capi:prompt-for-string “What were you thinking of?”))))
问一个问题
当我们在树上的问题时,会调用下一个程序,即提问。它提示问题,并且根据答案是肯定还是否,它分别调用树的左分支或右分支上的动物。
(defun ask-question (tree) (if (capi:prompt-for-confirmation (first tree)) (list (first tree) (animals (second tree)) (third tree)) (list (first tree) (second tree) (animals (third tree)))))
它返回完整的树,经过修改以添加新动物(如果添加了一个)。
主要程序- 动物
最后这里是主要程序,动物。它以树上的当前位置作为参数调用,如果参数是一个列表,只需调用ask-question,表示需要询问更多问题,或者猜测它是否是动物,表明我们是在分支的底部。
(defun animals (tree) (if (listp tree) (ask-question tree) (make-guess tree)))
要保存修改后的树,我们需要将其保存为* tree *。这是一个常规游戏动物,为我们这样做:
(defun play-animals () (setf animals-tree (animals animals-tree)))
保存树
请注意,如果要保留使用新动物训练数据库的结果,则应将* tree *的值保存到磁盘。这是一个修改后的游戏动物版本(相当粗略),将数据保存在硬盘顶层的名为tree的文件中。请注意,这使用了我们在这些教程中没有解释的函数,因此您必须信任它们:
(defun play-animals () (when (probe-file “tree”) (with-open-file (stream “tree” :direction :input) (setq animals-tree (read stream)))) (setq animals-tree (animals animals-tree)) (with-open-file (stream “tree” :direction :output :if-exists :supersede) (write animals-tree :stream stream)))
http://mip.i3geek.com