1引言卡雷尔是一个生活在非常简单的世界中的非常简单的机器人。在它的世界中,你可以通过给卡雷尔一组命令,直接让卡雷尔执行某些任务。卡雷尔的世界被定义为水平的街(东西方向),垂直的道(南北方向),街和道的交点被称为街角。卡雷尔只能定位在街角,而且只能面对四个标准罗盘方向(北,南,东,西)。一个简单的卡雷尔世界显示如下,卡雷尔目前位于第一大街和第一大道相交的街角,面朝东边。在上图中,我们还可以看到卡雷尔世界中其他的几件东西。卡雷尔前面的物体是个蜂鸣器,只有当卡雷尔和蜂鸣器位于同一个街角上的时候,卡雷尔才能感知这个蜂鸣器。图中的实线是墙壁,墙是卡雷尔世界的屏障,卡雷尔不能穿过墙壁,而只能在墙的周边行走。卡雷尔的世界总是被作为边界的墙包围起来,但是,随着卡雷尔需要解决不同的具体问题,卡雷尔的世界也有不同的尺寸。2.概述2.1背景介绍2.1.1Karel介绍在二十世纪七十年代,一位名字叫RichPattis的斯坦福研究生觉得,在编程基础的2教学中,如果学生可以在某种简单的环境中,摆脱大多数编程语言复杂的特性,学习基本的编程思想,可以取得更好的效果。麻省理工SeymourPapert’sLOGO计划的成功,启发了灵感,Rich设计了一个入门编程环境,(这个编程环境)让学生教一个机器人来解决简单的问题。这个机器人名字叫卡雷尔。因为捷克剧作家KarelCapek在1923年公演了R.U.R(Rossum’sUniversalRobots)后,为英语带来了机器人这个英语单词--Robot。机器人卡雷尔相当成功。卡雷尔被用于全国的计算机科学入门课程,到了Rich的教科书畅销超过10万份的地步。许多学习CS106A的学生,通过设计卡雷尔的行为,学会了如何让程序工作在20世纪90年代中期,我们曾经使用的机器人卡雷尔模拟器停止工作了。但是,我们很快就得到了一个Thetis编译的卡雷尔升级版供那时使用。但是,一年以前,CS106A课程转向到Java,卡雷尔再次从课堂上消失了。虽然在过去的三个季度,由于卡雷尔的离去产生的空白,已经完全被NickParlante的Binkyworld填了但现在是带卡雷尔回来的时候了。新完工的卡雷尔设计得完全兼容Java和Eclipse编程环境,这就意味着,你将在这门课程的开始,就可以练习使用Eclipse的编辑器和调试器。卡雷尔是一个生活在非常简单的世界中的非常简单的机器人。在它的世界中,你可以通过给卡雷尔一组命令,直接让卡雷尔执行某些任务。指定这些命令的过程称为编程。最初,卡雷尔只明白极少数预定义的命令,但编程(学习)过程的一个重要内容,就是教卡雷尔可以扩展它的能力的新命令。当你谋划让卡雷尔执行某项任务的时候,你必需用非常精确的方式写出这些必需的命令,以便这个机器人能够正确的理解你交待它做的事情。(另外)特别(注意的)是,你写的程序必须遵守语法规则,它规定了什么样的命令和语言形式是合法的。二者合在一起,预定义的命令和语法规则(一起)定义了卡雷尔编程语言。卡雷尔编程语言被设计的尽可能类似于Java语言,这样便于顺利过渡到(Java)这门你将时刻使用的语言上。卡雷尔程序具有和Java程序相同的结构,也涉及到相同的基本元素。最关键的区别是,卡雷尔的编程语言非常的小,从这个意义上讲,只具有非常少的命令和规则。它非常容易,例如,教授卡雷尔语言只需要几个小时,这也正是我们在CS106A中做的。在(课程)结束的时候,你将知道卡雷尔能做的一切事情,以及如何在一个程序中实现它。这些细节是容易掌握的。即便此,你会发现,(需要)解决的问题可能是极其具挑战性的。解决问题是编程的本质;在这一学习过程中,对规则的关注是次要的。在复杂的语言里,如Java,有许多的细节,这些细节往往成为学习的课程的重点。当这种情况发生时,对解决问题的更关键的东西,往往会在得到一片混乱中失去。通过从卡雷尔入手开始学习,你可以在一开始的时候,就把精力集中在解决问题上面。2.1.2Karel语言当卡雷尔出厂的时候,它只能响应非常小的命令集:move()要求卡雷尔向前推进一步。当一堵墙挡在卡雷尔面前的时候,卡雷尔不能响应move()这个命令。turnLeft()要求卡雷尔向左转90度(逆时针转动)。3pickBeeper()要求卡雷尔捡起街角上的蜂鸣器,把这个蜂鸣器放到它的蜂鸣器收藏包里,这个包可容纳无限多的蜂鸣器。除非这个蜂鸣器恰好在卡雷尔所在的街角上,卡雷尔不能响应这个pickBeeper()命令。putBeeper()要求卡雷尔从蜂鸣器收藏包里拿出一个蜂鸣器,放在卡雷尔所在的街角上。除非卡雷尔的蜂鸣器收藏包里有蜂鸣器,卡雷尔不能响应这个putBeeper()命令。出现在这些命令后面的一对空括号,是卡雷尔和Java相同语法的一部分,通过这个(一对空括号),来指定命令的调用。最终的时候,在你写的(Java)程序里,空括号之间会包含一些额外的内容,但是,这些额外的内容并不是卡雷尔原始世界的一部分。将这些括号之间留空,才是标准的卡雷尔程序,虽然括号里什么也没有,但你一定要记着把它们写在命令里。需要特别注意的是,这几个命令对卡雷尔的行为进行了限制。如果卡雷尔试图做些非法的举动,像穿墙或者捡起一个不存在的蜂鸣器,一个错误就发生了。在这时,卡雷尔会显示一条错误的信息,同时拒绝执行剩余的命令。2.1.3Karel与面向对象模式在卡雷尔被引入的二十世纪七十年代,采用的计算机编程方法是过程模式。在很大程度上,过程编程是把一个大规模的程序问题分解为小的过程,这些更易于管理的,定义了必要操作的单元称为过程。这种把程序分割成小单元的谋划,是编程风格的重要组成部分,而现代语言例如Java,强调了不同的编程模式,叫面向对象模式。在面向对象模式下,程序员的注意力被从关注特定操作的过程单元中转移出来,侧重到:为被称为对象的单元,抽象建模的行为上。在编程语言中,“对象”有时和真实世界的物理对象相对应,但更多的时候是抽象的概念。是真实对象的核心特性或代表(事物)整体的一种抽象。面向对象模式的主要优势之一是,它鼓励程序员认识到一个对象的状态和其行为的基本关系。一个对象的状态,涉及到一组和该对象相关,并可能随时间而改变的特性。一个对象可以被它在空间的位置,它的颜色,它的名字,其它一些主要特性来特别指定出来。一个对象的行为是指它在它的世界中响应事件或响应来自其它对象的命令的方法。在面向对象编程的语言中,触发指定对象的行为的通用词叫消息--message(虽然从卡雷尔的上下文上看,命令--command这个词可能更让人明白点)。对一个消息的响应,通常需要改变一个对象的状态。例如,如果定义一个对象状态的特性的之一是它的颜色,它就可以通过响应setColor(BLUE)这条消息把它的颜色改变成蓝色。在许多方面,卡雷尔代表了讲述“面向对象方法”的理想环境。虽然实际上没有人建立一个机器来执行卡雷尔,但却非常容易把卡雷尔想象为一个真实世界的对象。卡雷尔毕竟是一个机器人,机器人是真实世界存在的实体。定义卡雷尔状态的特性是它在它的世界中的位置,它面对的方向,在它蜂鸣器收藏包里的蜂鸣器数目。定义卡雷尔行为的是它响应的move(),turnLeft(),pickBeeper(),和putBeeper()这些命令。move()命令可以改变卡雷尔的位置,turnLeft()命令可以改变它面朝的方向,剩下的两个命令,会同时影响到收藏包里的蜂鸣器数量和当前街角上的蜂鸣器数量。卡雷尔的环境还提供了面向对象编程的核心概念之一--一个有用的框架。无论卡雷尔还是Java,一个对象和一个类之间概念的区分是很有必要的。最容易理解这种分别的方法是把类认为是一些对象(共同)的模式或模板,4这些对象都有一个共同的行为和状态属性的集合。在你将看到的下一章中,在卡雷尔程序里出现的“karel这个词,代表一个完整的机器人的类,这个类知道怎么去响应move(),turnLeft(),pickBeeper(),和putBeeper()这些命令。但只要你在卡雷尔的世界里有了一个实际的机器人,那么,这个机器人就是一个对象,这个机器人它代表了卡雷尔这个类的特定实例。尽管在CS106A课程里,你将不会有机会去做这样一个类,但有一个以上的卡雷尔类的实例,运行在同一个世界里,还是有可能的。即使只有一个单独机器人的时候,在你的脑海里,深刻记得类和对象是不同的概念,还是很重要的。2.2课程设计题目Karel机器人程序设计2.3课程设计目的在卡雷尔简单的世界中,我们可以通过给卡雷尔一组命令,直接让卡雷尔执行某些任务。指定这些命令的过程称为编程。最初,卡雷尔只明白极少数预定义的命令,但编程(学习)过程的一个重要内容,就是教卡雷尔可以扩展它的能力的新命令。当我们谋划让卡雷尔执行某项任务的时候,我们必须用非常精确的方式写出这些必需的命令,以便这个机器人能够正确的理解我们交待它做的事情。另外,我们写的程序必需遵守语法规则,它规定了什么样的命令和语言形式是合法的。预定义的命令和语法规则合在一起定义了卡雷尔编程语言。在复杂的语言里,如Java,细节往往成为学习课程的重点。当这种情况发生时,对解决问题更关键的东西,往往会在我们忽略。从卡雷尔入手学习编程,可以让我们在一开始的时候,就把精力集中在解决问题上面。而且,卡雷尔的学习鼓励想象力和创造力,在学习过程中,我们会收获不少乐趣。2.4开发环境斯坦福提供eclipsejre-6u2-windows-i586-p.zip卡雷尔机器人开发包52.5设计目标2.5.1地图寻宝在地图的某个位置上放置一个蜂鸣器,也就是Karel的宝藏。Karel从起始位置出发,四处寻找宝藏。找到宝藏后跳出显示“我找到宝藏啦!哦也!下面我要把宝藏带回家。”的对话框,然后Karel捡起宝藏,回到家,放下宝藏。2.5.2排序如图所示是卡雷尔机器人初始运行环境图:由图可知卡雷尔机器人刚开始时处于右下角的地方(1,1),在它的前方可以看到有5个由鸣蜂器的组成的塔,卡雷尔机器人所要做的是,以此将所有的塔的鸣蜂器捡起,在每个塔的鸣蜂器被捡起的是偶要记录每个塔所有的鸣蜂器的数量,在捡起所有的塔后就要对塔的高度进行排序。然后卡雷尔机器人要做的就是根据排序然后将塔再重新绘制出来,从左至右从低到高依次绘制出来,绘制塔的过程其实就是要根据塔的高度来放置蜂鸣器的数量。最后返回原点(1,1)绘制程序结束的标志,一个绘制一个黑色的方格。63.概要设计3.1相关知识3.1.1Karel基础指令Karel基础指令有四个:1)move()要求卡雷尔向前推进一步。当一堵墙挡在卡雷尔面前的时候,卡雷尔不能响应move()这个命令;2)turnLeft()要求卡雷尔向左转90度(逆时针转动);3)pickBeeper()要求卡雷尔捡起街角上的蜂鸣器,把这个蜂鸣器放到它的蜂鸣器收藏包里,这个包可容纳无限多的蜂鸣器。除非这个蜂鸣器恰好在卡雷尔所在的街角上,否则卡雷尔不能响应pickBeeper()命令;4)要求卡雷尔从蜂鸣器收藏包里拿出一个蜂鸣器,放在卡雷尔所在的街角上。除非卡雷尔的蜂鸣器收藏包里有蜂鸣器,否则卡雷尔不明响应putBeeper()命令。3.1.2Karel可判断的环境条件测试条件相反的测试条件判断的内容frontIsClear()面前无墙返回肯定值frontIsBlocked()面前被挡返回肯定值面前是否有墙leftIsClear()左面无墙返回肯定值leftIsBlocked()左面被挡返回肯定值左面是否有墙rightIsClear()右面无墙返回肯定值rightIsBlocked()右面被挡返回肯定值右面是否有墙beepersPresent()所在位置有方块返回肯定值noBeepersPresent()所在位置无方块返回肯定值所在位置是否有方块beepersInBag()包里目前有方块返回肯定值noBeepersInBag()包里目前无方块返回肯定值包里是否有方块facingNorth()面朝北返回肯定值noFacingNorth()没有面朝北返回肯定值是否面朝北facingEast()面