**第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,看他們如何相互做用。