项目 3:搭档共同练习

Project 3 第 1、2 题:两位搭档都要完成的基础练习,熟悉冒险游戏的对象交互与消息机制。

说明

本部分的前两道练习需要两位搭档都做!你们可以两人结对完成,只要双方都充分理解练习及其涵盖的概念。(当然,最终仍只提交一份双方都认可的解答。)其余练习的编号形如「A3」,表示「A 方的第 3 题」。

本项目分为两大部分。双方搭档各自完成第一部分的练习后,请合并成果,确保每位搭档都理解对方的工作。由于项目第二部分依赖于第一部分能正常工作的代码,请仔细合并你们的 adv.scm 和 adv-world.scm。

第 1 题

实例化一个新的 Person 对象来代表你自己。把你自己放进一个叫做 dormitory(或者你住的地方)的新地点,并把它和校园连接起来,使它成为一个可达的地方。在 soda 的北边创建一个叫 kirin 的地点。(它其实在 Solano 大街上。)在那里放一个叫 potstickers 的物品。然后输入必要的命令,把你的角色移动到 kirin,拿走 potstickers,再移动到 Brian 所在的地方,放下 potstickers,并让 Brian 拿走它们。然后回到实验室继续干活。(传闻说你在真实生活里这么做就能在本课拿 A——这纯属谣言!)这一切只是为了确保你掌握了冒险程序的语言。

请列出这个过程中发出的所有消息。 建议你先试着在脑子里理出头绪,至少把其中一部分行为想明白;当然,你也可以通过追踪 ask 过程拿到完整的列表。这份消息列表不必提交。(但你必须提交一份不带追踪过程的该事件操作记录。)本练习的目的是让你熟悉不同对象各司其职、互通消息的方式。

[提示:我们提供了一个 move-loop 过程,你可能会发现它有助于调试你的工作。你可以用它来反复移动一个人物。]

第 2 题

认真思考并理解冒险游戏中涉及的对象类型,这一点非常重要。请回答以下问题:

a) 变量 Brian 的值是什么类型的东西?提示: STk 在下面这种情况下会返回什么:

> Brian    

b) 列出 Place 能理解的所有消息。(不妨为每种对象类型都维护这样一份列表,方便你调试。)

c) 我们一直用变量来持有世界中的每个对象。例如,我们这样定义 bagel:

> (define bagel (instantiate thing 'bagel))

这只是为了方便。并非每个对象都必须有顶层定义。但每个对象确实必须被构造出来并连接到世界中。例如,假设我们这样做:

> (can-go Telegraph-Ave 'east (instantiate place 'Peoples-Park))

;;; 假设 Brian 在 Telegraph
> (ask Brian 'go 'east)

下面这些表达式会返回什么?为什么?

> (ask Brian 'place)

> (let ((where (ask Brian 'place)))
       (ask where 'name))

> (ask Peoples-park 'appear bagel)

d) 这一切的含义是:对象可以有多个名字。一个是对象内部 name 变量的值。此外,我们可以在顶层定义变量来指向一个对象。而且,一个对象还可以给另一个对象起私有名字。例如,Brian 有个变量 place,它当前绑定到代表 People’s Park 的对象。以下是一些值得思考的例子:

> (eq? (ask Telegraph-Ave 'look-in 'east) (ask Brian 'place))

> (eq? (ask Brian 'place) 'Peoples-Park)

> (eq? (ask (ask Brian 'place) 'name) 'Peoples-Park)

好,假设我们往 STk 里输入:

> (define computer (instantiate thing 'Durer))

下面哪种写法是正确的?为什么?

(ask 61a-lab 'appear computer)

还是

(ask 61a-lab 'appear Durer)

还是

(ask 61a-lab 'appear 'Durer)

(computer 'name) 返回什么?为什么?

e) 我们提供的 Thing 类定义没有使用讲义中描述的面向对象语法。请把它翻译成新的写法。

f) 有时候交互式调试对象很不方便,因为对象的方法返回的是对象,而我们想看的是对象的名字。你可以创建一些辅助过程,仅供交互式使用(而不是在对象方法内部使用),把需要的信息以可打印的形式提供出来。例如:

(define (name obj) (ask obj 'name))
(define (inventory obj)
    (if (person? obj)
        (map name (ask obj 'possessions))
        (map name (ask obj 'things))))

请写一个过程 whereis,接受一个人物作为参数,返回该人物所在地点的名字。再写一个过程 owner,接受一个物品作为参数,返回拥有它的人物的名字。(确保它对无主的物品也能正常工作。)

像这样的过程对调试项目后面的部分非常有用,欢迎随手多写一些自用。现在,是时候对冒险游戏做第一处修改了。从这里开始,你们要分工各自行动。