Try to answer these questions on your own. Use pp. 16-19 and Appendix B page B-1.
It is usually not a good idea to override the act method in a Critter subclass. The Critter class was designed to represent actors that process other actors and then move. If you find the act method unsuitable for your actors, you should consider extending Actor, not Critter. Usually we will override how to process the actors. The default Critters are described on page 31.
There is a Critter Folder already in the Gridworld Code folder, but for your convenience, here is the basic code for a CritterRunner. The gridworld.jar library already has Critter code, so you don't need the Critter class in your project folder, but I include it below so you can see it if you wish. Run this and obseverve how a default Critter works.
/* * AP(r) Computer Science GridWorld Case Study: * Copyright(c) 2005-2006 Cay S. Horstmann (http://horstmann.com) * * This code is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * @author Chris Nevison * @author Barbara Cloud Wells * @author Cay Horstmann */ import info.gridworld.actor.ActorWorld; import info.gridworld.actor.Critter; import info.gridworld.actor.Flower; import info.gridworld.actor.Rock; import info.gridworld.grid.Location; import java.awt.Color; /** * This class runs a world that contains critters.
* This class is not tested on the AP CS A and AB exams. */ public class CritterRunner { public static void main(String[] args) { ActorWorld world = new ActorWorld(); world.add(new Location(7, 8), new Rock()); world.add(new Location(3, 3), new Rock()); world.add(new Location(2, 8), new Flower(Color.BLUE)); world.add(new Location(5, 5), new Flower(Color.PINK)); world.add(new Location(1, 5), new Flower(Color.RED)); world.add(new Location(7, 2), new Flower(Color.YELLOW)); world.add(new Location(4, 4), new Critter()); world.add(new Location(5, 8), new Critter()); world.show(); } }
/* * AP(r) Computer Science GridWorld Case Study: * Copyright(c) 2005-2006 Cay S. Horstmann (http://horstmann.com) * * This code is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * @author Cay Horstmann */ package info.gridworld.actor; import info.gridworld.grid.Location; import java.util.ArrayList; /** * ACritter
is an actor that moves through its world, processing * other actors in some way and then moving to a new location. Define your own * critters by extending this class and overriding any methods of this class * except foract
. When you override these methods, be sure to * preserve the postconditions.
* The implementation of this class is testable on the AP CS A and AB exams. */ public class Critter extends Actor { /** * A critter acts by getting a list of other actors, processing that list, * getting locations to move to, selecting one of them, and moving to the * selected location. */ public void act() { if (getGrid() == null) return; ArrayListactors = getActors(); processActors(actors); ArrayList moveLocs = getMoveLocations(); Location loc = selectMoveLocation(moveLocs); makeMove(loc); } /** * Gets the actors for processing. Implemented to return the actors that * occupy neighboring grid locations. Override this method in subclasses to * look elsewhere for actors to process.
* Postcondition: The state of all actors is unchanged. * @return a list of actors that this critter wishes to process. */ public ArrayListgetActors() { return getGrid().getNeighbors(getLocation()); } /** * Processes the elements of actors
. New actors may be added * to empty locations. Implemented to "eat" (i.e. remove) selected actors * that are not rocks or critters. Override this method in subclasses to * process actors in a different way.
* Postcondition: (1) The state of all actors in the grid other than this * critter and the elements ofactors
is unchanged. (2) The * location of this critter is unchanged. * @param actors the actors to be processed */ public void processActors(ArrayListactors) { for (Actor a : actors) { if (!(a instanceof Rock) && !(a instanceof Critter)) a.removeSelfFromGrid(); } } /** * Gets a list of possible locations for the next move. These locations must * be valid in the grid of this critter. Implemented to return the empty * neighboring locations. Override this method in subclasses to look * elsewhere for move locations.
* Postcondition: The state of all actors is unchanged. * @return a list of possible locations for the next move */ public ArrayListgetMoveLocations() { return getGrid().getEmptyAdjacentLocations(getLocation()); } /** * Selects the location for the next move. Implemented to randomly pick one * of the possible locations, or to return the current location if * locs
has size 0. Override this method in subclasses that * have another mechanism for selecting the next move location.
* Postcondition: (1) The returned location is an element of *locs
, this critter's current location, or *null
. (2) The state of all actors is unchanged. * @param locs the possible locations for the next move * @return the location that was selected for the next move. */ public Location selectMoveLocation(ArrayListlocs) { int n = locs.size(); if (n == 0) return getLocation(); int r = (int) (Math.random() * n); return locs.get(r); } /** * Moves this critter to the given location loc
, or removes * this critter from its grid ifloc
isnull
. * An actor may be added to the old location. If there is a different actor * at locationloc
, that actor is removed from the grid. * Override this method in subclasses that want to carry out other actions * (for example, turning this critter or adding an occupant in its previous * location).
* Postcondition: (1)getLocation() == loc
. (2) The state of * all actors other than those at the old and new locations is unchanged. * @param loc the location to move to */ public void makeMove(Location loc) { if (loc == null) removeSelfFromGrid(); else moveTo(loc); } }
Before you try to answer the Set 8 Questions, get the next two files and see how this subclass of Critter works. Note how only certain methods are overloaded, and the act method is untouched.
/* * AP(r) Computer Science GridWorld Case Study: * Copyright(c) 2005-2006 Cay S. Horstmann (http://horstmann.com) * * This code is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * @author Chris Nevison * @author Barbara Cloud Wells * @author Cay Horstmann */ import info.gridworld.actor.Actor; import info.gridworld.actor.Critter; import info.gridworld.grid.Location; import java.util.ArrayList; /** * AChameleonCritter
takes on the color of neighboring actors as * it moves through the grid.
* The implementation of this class is testable on the AP CS A and AB exams. */ public class ChameleonCritter extends Critter { /** * Randomly selects a neighbor and changes this critter's color to be the * same as that neighbor's. If there are no neighbors, no action is taken. */ public void processActors(ArrayListactors) { int n = actors.size(); if (n == 0) return; int r = (int) (Math.random() * n); Actor other = actors.get(r); setColor(other.getColor()); } /** * Turns towards the new location as it moves. */ public void makeMove(Location loc) { setDirection(getLocation().getDirectionToward(loc)); super.makeMove(loc); } }
/* * AP(r) Computer Science GridWorld Case Study: * Copyright(c) 2005-2006 Cay S. Horstmann (http://horstmann.com) * * This code is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * @author Chris Nevison * @author Barbara Cloud Wells * @author Cay Horstmann */ import info.gridworld.actor.ActorWorld; import info.gridworld.actor.Rock; import info.gridworld.grid.Location; import java.awt.Color; /** * This class runs a world that contains chameleon critters.
* This class is not tested on the AP CS A and AB exams. */ public class ChameleonRunner { public static void main(String[] args) { ActorWorld world = new ActorWorld(); world.add(new Location(7, 8), new Rock()); world.add(new Location(3, 3), new Rock()); world.add(new Location(2, 8), new Rock(Color.BLUE)); world.add(new Location(5, 5), new Rock(Color.PINK)); world.add(new Location(1, 5), new Rock(Color.RED)); world.add(new Location(7, 2), new Rock(Color.YELLOW)); world.add(new Location(4, 4), new ChameleonCritter()); world.add(new Location(5, 8), new ChameleonCritter()); world.show(); } }
/* * AP(r) Computer Science GridWorld Case Study: * Copyright(c) 2005-2006 Cay S. Horstmann (http://horstmann.com) * * This code is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * @author Chris Nevison * @author Barbara Cloud Wells * @author Cay Horstmann */ import info.gridworld.actor.Actor; import info.gridworld.actor.Critter; import info.gridworld.grid.Grid; import info.gridworld.grid.Location; import java.awt.Color; import java.util.ArrayList; /** * ACrabCritter
looks at a limited set of neighbors when it eats and moves. *
* This class is not tested on the AP CS A and AB exams. */ public class CrabCritter extends Critter { public CrabCritter() { setColor(Color.RED); } /** * A crab gets the actors in the three locations immediately in front, to its * front-right and to its front-left * @return a list of actors occupying these locations */ public ArrayListgetActors() { ArrayList actors = new ArrayList (); int[] dirs = { Location.AHEAD, Location.HALF_LEFT, Location.HALF_RIGHT }; for (Location loc : getLocationsInDirections(dirs)) { Actor a = getGrid().get(loc); if (a != null) actors.add(a); } return actors; } /** * @return list of empty locations immediately to the right and to the left */ public ArrayList getMoveLocations() { ArrayList locs = new ArrayList (); int[] dirs = { Location.LEFT, Location.RIGHT }; for (Location loc : getLocationsInDirections(dirs)) if (getGrid().get(loc) == null) locs.add(loc); return locs; } /** * If the crab critter doesn't move, it randomly turns left or right. */ public void makeMove(Location loc) { if (loc.equals(getLocation())) { double r = Math.random(); int angle; if (r < 0.5) angle = Location.LEFT; else angle = Location.RIGHT; setDirection(getDirection() + angle); } else super.makeMove(loc); } /** * Finds the valid adjacent locations of this critter in different * directions. * @param directions - an array of directions (which are relative to the * current direction) * @return a set of valid locations that are neighbors of the current * location in the given directions */ public ArrayList getLocationsInDirections(int[] directions) { ArrayList locs = new ArrayList (); Grid gr = getGrid(); Location loc = getLocation(); for (int d : directions) { Location neighborLoc = loc.getAdjacentLocation(getDirection() + d); if (gr.isValid(neighborLoc)) locs.add(neighborLoc); } return locs; } }
/* * AP(r) Computer Science GridWorld Case Study: * Copyright(c) 2005-2006 Cay S. Horstmann (http://horstmann.com) * * This code is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * @author Chris Nevison * @author Barbara Cloud Wells * @author Cay Horstmann */ import info.gridworld.actor.ActorWorld; import info.gridworld.actor.Bug; import info.gridworld.actor.Flower; import info.gridworld.actor.Rock; import info.gridworld.grid.Location; /** * This class runs a world that contains crab critters.
* This class is not tested on the AP CS A and AB exams. */ public class CrabRunner { public static void main(String[] args) { ActorWorld world = new ActorWorld(); world.add(new Location(7, 5), new Rock()); world.add(new Location(5, 4), new Rock()); world.add(new Location(5, 7), new Rock()); world.add(new Location(7, 3), new Rock()); world.add(new Location(7, 8), new Flower()); world.add(new Location(2, 2), new Flower()); world.add(new Location(3, 5), new Flower()); world.add(new Location(3, 8), new Flower()); world.add(new Location(6, 5), new Bug()); world.add(new Location(5, 3), new Bug()); world.add(new Location(4, 5), new CrabCritter()); world.add(new Location(6, 1), new CrabCritter()); world.add(new Location(7, 4), new CrabCritter()); world.show(); } }
import java.util.ArrayList; import java.awt.Color; import info.gridworld.actor.*; public class AgingChameleon extends ChameleonCritter { // instance variables - replace the example below with your own private double DARKENING_FACTOR; public AgingChameleon() { DARKENING_FACTOR = 0.05; } /** * Randomly selects a neighbor and changes this critter's color to be the * same as that neighbor's. If there are no neighbors, no action is taken. */ public void processActors(ArrayListactors) { int n = actors.size(); if (n == 0) { darken(); return; } int r = (int) (Math.random() * n); Actor other = actors.get(r); setColor(other.getColor()); } /** * Darkens this critter's color by DARKENING_FACTOR. */ private void darken() { Color c = getColor(); int red = (int) (c.getRed() * (1 - DARKENING_FACTOR)); int green = (int) (c.getGreen() * (1 - DARKENING_FACTOR)); int blue = (int) (c.getBlue() * (1 - DARKENING_FACTOR)); setColor(new Color(red, green, blue)); } }
import info.gridworld.actor.ActorWorld; import info.gridworld.actor.Rock; import info.gridworld.grid.Location; import java.awt.Color; /** * This class runs a world that contains chameleon critters.
* This class is not tested on the AP CS A and AB exams. */ public class ChameleonRunner { public static void main(String[] args) { ActorWorld world = new ActorWorld(); world.add(new Location(5, 5), new Rock(Color.PINK)); world.add(new Location(7, 2), new Rock(Color.YELLOW)); world.add(new Location(4, 4), new AgingChameleon()); world.add(new Location(5, 8), new AgingChameleon()); world.show(); } }
/** * Override the getActors method to only return actors that are in front and behind the * ChameleonCritterKid. This solution uses the getLocationsInDirections method found in * CrabCritter to find the actors in the required directions and uses the CrabCritterÕs version of * getActors. */ import info.gridworld.actor.Actor; import info.gridworld.actor.Critter; import info.gridworld.actor.Flower; import info.gridworld.grid.Location; import info.gridworld.grid.Grid; import java.util.ArrayList; /** * AChameleonKid
takes on the color of neighboring actors * that are in front or behind as it moves through the grid.
*/ public class ChameleonKid extends ChameleonCritter { /** * Gets the actors for processing. The actors must be contained in the * same grid as this critter. Implemented to return the actors that * occupy neighboring grid locations in front or behind this critter. * @return a list of actors that are neighbors of this critter */ public ArrayListgetActors() { ArrayList actors = new ArrayList (); int[] dirs = { Location.AHEAD, Location.HALF_CIRCLE }; for (Location loc : getLocationsInDirections(dirs)) { Actor a = getGrid().get(loc); if (a != null) actors.add(a); } return actors; } /** * Finds the valid adjacent locations of this critter in different * directions. * @param directions - an array of directions (which are relative to the * current direction) * @return a set of valid locations that are neighbors of the current * location in the given directions */ public ArrayList getLocationsInDirections(int[] directions) { ArrayList locs = new ArrayList (); Grid gr = getGrid(); Location loc = getLocation(); for (int d : directions) { Location neighborLoc = loc.getAdjacentLocation(getDirection() + d); if (gr.isValid(neighborLoc)) locs.add(neighborLoc); } return locs; } }
/* * Override processActors to remove all rocks * from the list of neighboring locations. */ import info.gridworld.actor.Actor; import info.gridworld.actor.Rock; import info.gridworld.actor.Critter; import info.gridworld.grid.Location; import java.util.ArrayList; public class RockHound extends Critter { /** * Processes the actors. Implemented to "eat" (i.e. remove) all rocks *
* Precondition: All objects inactors
are contained in the * same grid as this critter. * @param actors the actors to be processed */ public void processActors(ArrayListactors) { for (Actor a : actors) { if (a instanceof Rock) a.removeSelfFromGrid(); } } }
import info.gridworld.actor.Actor; import info.gridworld.actor.Rock; import info.gridworld.actor.Critter; import info.gridworld.grid.Location; import java.util.ArrayList; import java.awt.Color; public class BlusterCritter extends Critter { private int courageFactor; public BlusterCritter(int c) { super(); courageFactor = c; } /** * Gets the actors for processing. The actors must be contained in the * same grid as this critter. Implemented to return the actors that * occupy neighboring grid locations within two steps of this critter * @return a list of actors that are neighbors of this critter */ public ArrayListgetActors() { ArrayList actors = new ArrayList (); Location loc = getLocation(); for(int r = loc.getRow() - 2; r <= loc.getRow() + 2; r++ ) for(int c = loc.getCol() - 2; c <= loc.getCol() + 2; c++) { Location tempLoc = new Location(r,c); if(getGrid().isValid(tempLoc)) { Actor a = getGrid().get(tempLoc); if(a != null && a != this) actors.add(a); } } return actors; } /** * Processes the actors. Implemented to count all the actors within * 2 locations of this critter. If there are fewer than courageFactor * critters in these locations, this BlusterCritter lightens, otherwise * it darkens. * Precondition: All objects in actors
are contained in the * same grid as this critter. * @param actors the actors to be processed */ public void processActors(ArrayListactors) { int count = 0; for(Actor a: actors) if(a instanceof Critter) count++; if(count < courageFactor) lighten(); else darken(); } /** * Darkens this critter's color by subtracting 1 from red, green, and * blue components if they are greater than 0. To darken the color * faster, subtract a slightly larger value. */ private void darken() { Color c = getColor(); int red = c.getRed(); int green = c.getGreen(); int blue = c.getBlue(); if(red > 0) red--; if(green > 0) green--; if(blue > 0) blue--; setColor(new Color(red, green, blue)); // this segment of code uses same logic as the flower class to darken // an object's color // to use this technique add DARKENING_FACTOR as a class instance // variable; then replace the active code for darken with the // following five lines of code // private static final double DARKENING_FACTOR = 0.05; // Color c = getColor(); // int red = (int) (c.getRed() * (1 - DARKENING_FACTOR)); // int green = (int) (c.getGreen() * (1 - DARKENING_FACTOR)); // int blue = (int) (c.getBlue() * (1 - DARKENING_FACTOR)); // setColor(new Color(red, green, blue)); } /* * Lightens this critter's color by adding 1 to the red, green, and blue * components if they are less than 255. To lighten the color faster, * add a slightly larger value. */ private void lighten() { Color c = getColor(); int red = c.getRed(); int green = c.getGreen(); int blue = c.getBlue(); if(red < 255) red++; if(green < 255) green++; if(blue < 255) blue++; setColor(new Color(red, green, blue)); } }
import info.gridworld.actor.Actor; import info.gridworld.actor.Critter; import info.gridworld.grid.Grid; import info.gridworld.grid.Location; import java.awt.Color; import java.util.ArrayList; /** * AQuickCrab
looks at a limited set of neighbors when it * eats and moves.
*/ public class QuickCrab extends CrabCritter { public QuickCrab() { setColor(Color.CYAN); } /** * @return list of empty locations * two locations to the right and two locations to the left */ public ArrayListgetMoveLocations() { ArrayList locs = new ArrayList (); Grid g = getGrid(); addIfGoodTwoAwayMove(locs,getDirection() + Location.LEFT); addIfGoodTwoAwayMove(locs,getDirection() + Location.RIGHT); if (locs.size() == 0) return super.getMoveLocations(); return locs; } /** * Adds a valid and empty two away location in direction dir to the * ArrayList locs. * To be a valid two away location, the location that is one away in * direction dir must also be valid and empty. */ private void addIfGoodTwoAwayMove(ArrayList locs,int dir) { Grid g = getGrid(); Location loc = getLocation(); Location temp = loc.getAdjacentLocation(dir); if(g.isValid(temp) && g.get(temp) == null) { Location loc2 = temp.getAdjacentLocation(dir); if(g.isValid(loc2) && g.get(loc2)== null) locs.add(loc2); } } }
import info.gridworld.actor.Actor; import info.gridworld.actor.Critter; import info.gridworld.grid.Grid; import info.gridworld.grid.Location; import java.awt.Color; import java.util.ArrayList; /** * AKingCrab
looks at a limited set of neighbors when it * eats and moves.
*/ public class KingCrab extends CrabCritter { public KingCrab() { setColor(Color.PINK); } /** * Computes the rounded integer distance between two given locations. */ public int distanceFrom(Location loc1, Location loc2) { int x1 = loc1.getRow(); int y1 = loc1.getCol(); int x2 = loc2.getRow(); int y2 = loc2.getCol(); double dist = Math.sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)) + .5; return (int)Math.floor(dist); } /* * This method moves the Actor to a location that is one location * further away from this KingCrab and returns true. If there is no * location that is one location further away, the method returns false. */ private boolean moveOneMoreAway(Actor a) { ArrayListlocs = getGrid().getEmptyAdjacentLocations(a.getLocation()); for(Location loc:locs) { if(distanceFrom(getLocation(), loc) > 1) { a.moveTo(loc); return true; } } return false; } /* * Each actor in the list actors is told to move one location further * away from this KingCrab. If that is not possible, the actor is * removed from the grid. */ public void processActors(ArrayList actors) { for (Actor a : actors) { if (!moveOneMoreAway(a)) { a.removeSelfFromGrid(); } } } }