Critter notes
Adapted from Cay Horstmann — thanks!
Critters are included in GridWorld to emphasize design. The act method calls five methods, and subclasses override some or all of them to achieve some desired behavior. (For those of you interested in digging deeper into programming and software engineering, the act method is an example of the “template method” design pattern. Design patterns are a powerful way of expressing common best-practices about code structure. Google it!)
When to use Critter
Not every actor can or should be represented as a
Critter. In the context of GridWorld, a Critter is not a warm and fuzzy
creature, but an actor that first processes actors and then makes a move. Trying to make Actors that don’t follow this pattern into Critters will generally result in overly-complicated logic.
Critter rules
Here are a few simple rules to remember when working with Critters (these don’t apply to bugs or other Actors!). They will be discussed in a little more detail below.
- Don’t override
act - A critter can change its state only in
processActorsor
makeMove - A critter can change the state of other actors in
processActors
Critter methods
Each of the five methods called from act has postconditions that restrict what it can do. The following table shows the postconditions as they are stated in the GridWorld documentation.
Here, the state of an actor includes
- the location
- the direction
- the contents of any other instance variables
getActors |
The state of all actors is unchanged. |
processActors |
(1) The state of all actors in the grid other than this critter and the elements of actors is unchanged. (2) The location ofthis critter is unchanged. |
getMoveLocations |
The state of all actors is unchanged. |
selectMoveLocation |
(1) The returned location is an element of locs (the parameter of type ArrayList<Location>), thiscritter’s current location, or null. (2) The state ofall actors is unchanged. |
makeMove |
(1) getLocation() == loc. (2) The state of all actorsother than those at the old and new locations is unchanged. |
If a critter wants to change its own state, it can only do so in processActors and makeMove. If it wants to change
its location (or remove itself), it can only do so in makeMove (Removing an actor changes its state: its location becomes null).
If a critter wants to change the state of another critter, it can only do so in processActors. (There is a teensy exception: makeMove removes the critter at the target location, and it may add a new critter to the old location.)
Note that getActors, getMoveLocations, and selectMoveLocation can’t change the state of any actor.
Also note that processActors can only mutate actors that were handed to it, and selectMoveLocations can only select from the locations that were handed to it. The makeMove method has even less choice—it must move to the location given in the
parameter.
These conditions significantly restrict what a critter can do, and how it can do it. When you design a particular critter, you need to distribute
responsibilities among the five methods that are called by act.




