**第10章 GridWorld:第二部分**
GridWorld案例研究的第二部分使用了一些咱们以前没有用到的功能,你如今就能够预览,以后会有更多细节。提醒一下,能够在http://www.greenteapress.com/thinkapjava/javadoc/gridworld/找到关于GridWorld类的文档。
安装GridWorld时,必须有一个叫projects/boxBug的文件夹,其中包含BoxBug.java,BoxBugRunner.java和BoxBug.gif。
把这些文件复制到你的工做文件夹中,并把它们引入你的开发环境中。http://www.collegeboard.com/prod_downloads/student/testing/ap/compsci_a/ap07_gridworld_installation_guide.pdf.这里的说明可能会有帮助。
BoxBugRunner.java代码片断:
import info.gridworld.actor.ActorWorld;
import info.gridworld.grid.Location;
import java.awt.Color;
public class BoxBugRunner {
public static void main(String[] args) {
ActorWorld world = new ActorWorld();
BoxBug alice = new BoxBug(6);
alice.setColor(Color.ORANGE);
BoxBug bob = new BoxBug(3);
world.add(new Location(7, 8), alice);
world.add(new Location(5, 5), bob);
world.show();
}
}
除了Location方法之外,其他应该都很熟悉了。Location方法是GridWorld的一部分,与java.awt.Point相似。
BoxBug.java包含BoxBug类的定义。
public class BoxBug extends Bug {
private int steps;
private int sideLength;
public BoxBug(int length) {
steps = 0;
sideLength = length;
}
}
第一行代表这个类继承自Bug父类,也就是说BoxBug类是Bug类的一种。
下面两行是实例变量。每一个Bug类都有sideLength变量和steps变量,前者肯定画出的box的尺寸。后者记录Bug走了多少步。
下一行定义了构造函数,它是初始化实例变量的特殊方法。经过调用new而新建Bug类时,Java机制会调用构造函数。
构造函数的参数是边长(length)。
act方法控制Bug类的行为。BoxBug类的act方法:
public void act() {
if (steps < sideLength && canMove()) {
move();
steps++;
}
else {
turn();
turn();
steps = 0;
}
}
若是BoxBug类能够移动而且移动的步数小于sideLength,那么移动而且stepd加1。
若是碰到墙或者完成box的一条边,向右转90°,steps重置为0。
运行程序,观察它作了什么。获得你所期待的行为了么?
**练习10.1**
如今你应该知道如何作学生手册第二部分的练习了。作完它们,回来学习更多乐趣。
**10.1 Termites(白蚁)**
我写了一个叫Termite的类,它继承自Bug父类,增长了和flowers的交互能力。
为了运行它,下载下面这些文件,并把它们引入你的开发环境中:
http://thinkapjava.com/code/Termite.java
http://thinkapjava.com/code/Termite.gif
http://thinkapjava.com/code/TermiteRunner.java
由于Termite类继承自Bug父类,Termite类可使用Bug类的方法。Termite类有一些Bug类所不具备的方法。
/**
*若是白蚁拥有花,返回true
*/
public boolean hasFlower();
/**
*若是白蚁面对花,返回true
*/
public boolean seeFlower();
/**
*除非白蚁拥有花,新建花
*/
public void createFlower();
/**
*在白蚁当前位置抛弃花
*
*记录:仅有一个角色能够占居一个单元格,因此直到白蚁移动时,抛弃花才起做用。
*/
public void dropFlower();
/**
*把花扔到白蚁将要来临的位置
*
*/
public void throwFlower();
/**
*若是有一朵而且白蚁没有花,摘取花。
*/
public void pickUpFlower();
对于有些方法,Bug类提供了定义,Termite类也提供了一个定义。在这种状况下,Termite类的方法会重写Bug类中的方法。
例如,若是下一个位置有花,Bug.canMove方法返回true,Bugs能够伤害Flowers。若是下一个位置有任何物体,Termite.canMove返回false,所以Termite的行为是不一样的。
又例如, Termites有以整数记录转动角度做为参数的版本。Termites 有randomTurn方法,随机向左或右转动45°。
TermiteRunner.java代码片断:
public class TermiteRunner
{
public static void main(String[] args)
{
ActorWorld world = new ActorWorld();
makeFlowers(world, 20);
Termite alice = new Termite();
world.add(alice);
Termite bob = new Termite();
bob.setColor(Color.blue);
world.add(bob);
world.show();
}
public static void makeFlowers(ActorWorld world, int n) {
for (int i=0; i<n; i++) {
world.add(new EternalFlower());
}
}
}
上面的每一点都应该很熟悉了。TermiteRunner类新建了一个包含20个EternalFlowers和2个Termites的ActorWorld类的实例。
EternalFlower是一个重写了act方法的Flower类,所以flowers不会变暗。
class EternalFlower extends Flower {
public void act() {}
}
若是运行TermiteRunner.java,能够看到两只白蚁(termites)在花丛(flowers)中随机移动。
MyTermite.java阐明了与花丛(Flowers)相互做用的方法。类的定义:
public class MyTermite extends Termite {
public void act() {
if (getGrid() == null)
return;
if (seeFlower()) {
pickUpFlower();
}
if (hasFlower()) {
dropFlower();
}
if (canMove()) {
move();
}
randomTurn();
}
}
MyTermite类继承自Termite父类并重写了act方法。若是MyTermite看见了一株花,它会摘下花。若是它自己拥有花,就丢弃。
**练习10.2**
这个练习的目的是探索Termites和Flowers的相互做用的行为。
修改TermiteRunner.java新建MyTermites代替Termites。而后再运行。MyTermites随机移动,围绕flowers移动。flowers的总数保持不变(包括MyTermites拥有的花)。
在Termites,Turtles和Traffic Jams,Mitchell Resnick 描述了一个termite行为的简单模型:
若是你看到一朵花,摘下它。除非你已经拥有一朵花了;那么的话,扔掉你拥有的花。
若是能够的话,向前移动。
随机的向左或右转弯。
修改MyTermite.java来实现这个模型。你认为MyTermites的行为变化会有什么影响?
尝试一下。flowers的总数没有改变,可是随着时间推移,flowers在少数桩上积累,一般状况下是在一个桩上。
这种行为是一种天然属性,能够在http: // en. wikipedia. org/ wiki/ Emergence阅读相关知识。
MyTermites按照简单的规则,仅使用小规模信息,但结果倒是大规模组织的。
实验不一样的规则,观察系统的反映。小的改动可能有意想不到的结果。
**10.2Langton’s Termite**
Langton’s Ant是一个简单的蚂蚁行为模式,显示了惊人的复杂行为。蚂蚁生活在像GridWorld同样的网格里,每个单元格是黑色的或白色的。蚂蚁根据如下规则移动:
若是蚂蚁在白单元格中,向右转,单元格变黑,蚂蚁向前移动。
若是蚂蚁在黑单元格中,向左转,单元格变白,蚂蚁向前移动。
因为规则很简单,你可能会期待蚂蚁能够作诸如方形或者重复简单模式这样简单的事。可是在白单元格开始,蚂蚁必须在看似随机模式下,在它落入104步循环以前,走超过10000步。
能够在http://en.wikipedia.org/wiki/Langton_ant阅读更多关于Langton’s Ant的信息。
在GridWorld中实现Langton’s Ant不并简单,由于咱们不能设置单元格的颜色。做为替代方式,咱们可使用Flowers来标记单元格,可是在一个单元格内不能同时有Ant和Flower,所以咱们不能准确的实现Ant规则。
相反,新建一个LangtonTermite类,使用seeFlower来检查下个单元格是否有flower,使用pickUpFlower来摘花,使用throwFlower来在下个单元格放花。你可能想要阅读这些方法的代码来确保你知道他们作了什么。
**练习10.3**
1.复制Termite.java重命名为LangtonTermite.java,复制TermiteRunner.java重命名为LangtonRunner.java。进行修改使类名和文件名相同,LangtonRunner建立LangtonTermite。
2.若是新建了LangtonTermite.gif,GridWorld使用它来表明你的Termite。你能够从http: // www. cksinfo. com/ animals/ insects/realisticdrawings/ index. html下载精美的图片。可使用ImageMagic工具把下载的图片转化为gif格式。
3.修改act方法来实现与Langton’s Ant类似的规则。尝试不一样的规则,转45°或90°。找到Termite开始循环前最大步数的规则。
4.经过使grid变大或者变成UnboundedGrid,能够给Termite足够大的空间。
5.新建多于一个LangtonTermite,看他们如何相互做用。