thinkapjava 5.1.2 documentation

GridWorld: Part 2

«  Mutable objects   ::   Contents   ::   Create your own objects  »

GridWorld: Part 2

Part 2 of the GridWorld case study uses some features we haven’t seen yet, so you will get a preview now and more details later. As a reminder, you can find the documentation for the GridWorld classes here.

When you install GridWorld, you should have a folder named projects/boxBug, which contains BoxBug.java, BoxBugRunner.java and BoxBug.gif.

Copy these files into your working folder and import them into your development environment. There are instructions that might help here.

Here is the code from BoxBugRunner.java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
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();
    }
}

Everything here should be familiar, with the possible exception of Location, which is part of GridWorld, and similar to java.awt.Point.

BoxBug.java contains the class definition for BoxBug.

1
2
3
4
5
6
7
8
9
public class BoxBug extends Bug {
    private int steps;
    private int sideLength;

    public BoxBug(int length) {
        steps = 0;
        sideLength = length;
    }
}

The first line says that this class extends Bug, which means that a BoxBug is a kind of Bug.

The next two lines are instance variables. Every Bug has variables named sideLength, which determines the size of the box it draws, and steps, which keeps track of how many steps the Bug has taken.

The next line defines a constructor, which is a special method that initializes the instance variables. When you create a Bug by invoking new, Java invokes this constructor.

The parameter of the constructor is the side length.

Bug behavior is controlled by the act method. Here is the act method for BoxBug:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public void act() {
    if (steps < sideLength && canMove()) {
        move();
        steps++;
    }
    else {
        turn();
        turn();
        steps = 0;
    }
}

If the BoxBug can move, and has not taken the required number of steps, it moves and increments steps.

If it hits a wall or completes one side of the box, it turns 90 degrees to the right and resets steps to 0.

Run the program and see what it does. Did you get the behavior you expected?

Termites

I wrote a class called Termite that extends Bug and adds the ability to interact with flowers. To run it, download these files and import them into your development environment:

Termite.java, Termite.gif, TermiteRunner.java, and EternalFlower.java.

Because Termite extends Bug, all Bug methods also work on Termites. But Termites have additional methods that Bugs don’t have.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
 * Returns true if the termite has a flower.
 */
public boolean hasFlower();

/**
 * Returns true if the termite is facing a flower.
 */
public boolean seeFlower();

/**
 * Creates a flower unless the termite already has one.
 */
public void createFlower();

/**
 * Drops the flower in the termites current location.
 *
 * Note: only one Actor can occupy a grid cell, so the effect
 * of dropping a flower is delayed until the termite moves.
 */
public void dropFlower();

/**
 * Throws the flower into the location the termite is facing.
 */
public void throwFlower();

/**
 * Picks up the flower the termite is facing, if there is
 * one, and if the termite doesn't already have a flower.
 */
public void pickUpFlower();

For some methods Bug provides one definition and Termite provides another. In that case, the Termite method overrides the Bug method.

For example, Bug.canMove returns true if there is a flower in the next location, so Bugs can trample Flowers. Termite.canMove returns false if there is any object in the next location, so Termite behavior is different.

As another example, Termites have a version of turn that takes an integer number of degrees as a parameter. Finally, Termites have randomTurn, which turns left or right 45 degrees at random.

Here is the code from TermiteRunner.java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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());
        }
    }
}

Everything here should be familiar. TermiteRunner creates an ActorWorld with 20 EternalFlowers and two Termites.

An EternalFlower is a Flower that overrides act so the flowers don’t get darker.

public class EternalFlower extends Flower {
    public void act() {}
}

If you run TermiteRunner.java you should see two termites moving at random among the flowers.

MyTermite.java demonstrates the methods that interact with flowers. Here is the class definition:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class MyTermite extends Termite {

    public void act() {
        if (getGrid() == null)
            return;

        if (seeFlower()) {
            pickUpFlower();
        }
        if (hasFlower()) {
            dropFlower();
        }

        if (canMove()) {
            move();
        }
        randomTurn();
    }
}

MyTermite extends Termite and overrides act. If MyTermite sees a flower, it picks it up. If it has a flower, it drops it.

Langton’s Termite

Langton’s Ant is a simple model of ant behavior that displays surprisingly complex behavior. The Ant lives on a grid like GridWorld where each cell is either white or black. The Ant moves according to these rules:

  • If the Ant is on a white cell, it turns to the right, makes the cell black, and moves forward.
  • If the Ant is on a black cell, it turns to the left, makes the cell white, and moves forward.

Because the rules are simple, you might expect the Ant to do something simple like make a square or repeat a simple pattern. But starting on a grid with all white cells, the Ant makes more than 10,000 steps in a seemingly random pattern before it settles into a repeating loop of 104 steps.

You can read more about Langton’s Ant at Wikipedia.

It is not easy to implement Langton’s Ant in GridWorld because we can’t set the color of the cells. As an alternative, we can use Flowers to mark cells, but we can’t have an Ant and a Flower in the same cell, so we can’t implement the Ant rules exactly.

Instead we’ll create what I’ll call a LangtonTermite, which uses seeFlower to check whether there is a flower in the next cell, pickUpFlower to pick it up, and throwFlower to put a flower in the next cell. You might want to read the code for these methods to be sure you know what they do.

Exercises

Exercise

Now you know enough to do the exercises in the Student Manual, Part 2. Go do them, and then come back for more fun.

Exercise

The purpose of this exercise is to explore the behavior of Termites that interact with flowers.

Modify TermiteRunner.java to create MyTermites instead of Termites. Then run it again. MyTermites should move around at random, moving the flowers around. The total number of flowers should stay the same (including the ones MyTermites are holding).

In Termites, Turtles and Traffic Jams, Mitchell Resnick describes a simple model of termite behavior:

  • If you see a flower, pick it up. Unless you already have a flower; in that case, drop the one you have.
  • Move forward, if you can.
  • Turn left or right at random.

Modify MyTermite.java to implement this model. What effect do you think this change will have on the behavior of MyTermites?

Try it out. Again, the total number of flowers does not change, but over time the flowers accumulate in a small number of piles, often just one.

This behavior is an an emergent property, which you can read about at Wikipedia. MyTermites follow simple rules using only small-scale information, but the result is large-scale organization.

Experiment with different rules and see what effect they have on the system. Small changes can have unpredicable results!

Exercise

  1. Make a copy of Termite.java called LangtonTermite and a copy of TermiteRunner.java called LangtonRunner.java. Modify them so the class definitions have the same name as the files, and so LangtonRunner creates a LangtonTermite.
  2. If you create a file named LangtonTermite.gif, GridWorld uses it to represent your Termite. You can download excellent pictures of insects from here. To convert them to GIF format, you can use an application like ImageMagick.
  3. Modify act to implement rules similar to Langton’s Ant. Experiment with different rules, and with both 45 and 90 degree turns. Find rules that run the maximum number of steps before the Termite starts to loop.
  4. To give your Termite enough room, you can make the grid bigger or switch to an UnboundedGrid.
  5. Create more than one LangtonTermite and see how they interact.

«  Mutable objects   ::   Contents   ::   Create your own objects  »