Critter differs from Actor in that a critter eats specific types of other actors adjacent to it. Critter randomly picks one of its valid adjacent empty locations and moves to that location. The result is that Critter moves around the grid and eats specific Actors. ActorWorld world = new ActorWorld(); Critter thing = new Critter(); world.add(new Location(1,1), thing); world.show(); ActorWorld world = new ActorWorld(); Critter thing = new Critter(); thing.setColor(Color.GREEN); thing.setDirection(180); Location loc = new Location(2,2); world.add(loc, thing); world.show(); Critter extends Actor frequently used methods from Actor Method name How is it used? getColor() gets the critter's color getDirection() gets the critter's direction getLocation() gets the critter's location setColor(col) sets the critter's color to col setDirection(dir) sets the critter's direction to dir import info.gridworld.actor.Critter; Different types of critters may select move locations in different ways, may have different ways of processing the actors, and may vary the actions they take when they make the move. Examples: • One type of critter might get all its neighboring actors and perform some action on each one of them (change color, change direction, make them move, etc.) • Another critter may only select actors in front of it to process public void act() { if (getGrid() == null) return; ArrayList<Actor> actors = getActors(); processActors(actors); ArrayList<Location> moveLocs = getMoveLocations(); Location loc = selectMoveLocation(moveLocs); makeMove(loc); } Critter extends Actor frequently used methods – Critter specific Method name How is it used? act() calls the methods listed below getActors() returns an ArrayList of all actors around this location processActors(actors) does something to selected actors getMoveLocations() returns an ArrayList of possible move locations selectMoveLocation(locs) picks location to move to makeMove(loc) moves this critter to location loc or removes itself from grid if loc is null if no grid present – stop • call getActors to get an array list of actors to process • call processActors to process the array list of actors received from getActors • call getMoveLocations to get an array list of locations where the critter might move • call selectMoveLocation to select new location from the array list of possible locations • call makeMove to move to selected location • Compile and run CritterRunner.java. After one step The getActors method returns an ArrayList containing all of the actors around this critter using the 4 cardinal (N,S,E,W) and 4 intercardinal directions (NE, NW, SE, SW). In order to change which actors are returned by getActors, override this method and provide a different approach of selecting actors. getActors must not modify any actors; that is the job of processActors public ArrayList<Actor> getActors() { return getGrid().getNeighbors(getLocation()); } Gets all neighbors adjacent to it Use the GW quick reference! What has to change if you want a critter to only get actors in front and behind? Make sure you satisfy the post conditions of each method you override!! public class GetInFrontBehindCritter extends Critter { //constructor } public ArrayList<Actor> getActors() { ArrayList<Actor> actors = new ArrayList<Actor>(); Grid<Actor> grid = getGrid(); Location inFront = getLocation().getAdjacentLocation(getDirection()); Location behind = getLocation().getAdjacentLocation(getDirection() + 180); if(grid.isValid(inFront) && grid.get(inFront) != null) actors.add(grid.get(inFront)); if(grid.isValid(behind) && grid.get(behind) != null) actors.add(grid.get(behind)); return actors; } What code is needed? The processActors method will do something to some or all of the actors around this critter. The processActors receives a list of all actors around this actor based on this actor’s getActors method. The critter act method calls getActors and passes the returned ArrayList to processActors. processActors must only change the actors received in the ArrayList parameter. public void processActors(ArrayList<Actor> actors) { for (Actor a : actors) { if(!(a instanceof Rock) && !(a instanceof Critter)) a.removeSelfFromGrid(); } } Removes all neighbors adjacent to it Use the GW quick reference! What has to change if you want a critter to only eat flowers? public class FlowerEatingCritter extends Critter { //constructor public void processActors(ArrayList<Actor> actors) { for(Actor a : actors) { if(a instanceof Flower) a.removeSelfFromGrid(); } } } What code is needed? The getMoveLocations method returns a list of all empty adjacent locations to which this critter could move. In order to change which locations are returned by getMoveLocations, override the method and provide a different method of selecting move locations. getMoveLocations must not modify any actors. public ArrayList<Location> getMoveLocations() { return getGrid().getEmptyAdjacentLocations(getLocation()); } Gets all possible locations where the critter could move The selectMoveLocation method selects a possible move location from the list of locations returned by getMoveLocations. The selectMoveLocation receives a list of all actors around this actor based on this actor’s getMoveLocations method. The critter act method calls getMoveLocations and passes the returned ArrayList to selectMoveLocation. selectMoveLocation must not modify any actors. public Location selectMoveLocation(ArrayList<Location> locs) { int n = locs.size(); if (n==0) return getLocation(); int r = (int) (Math.random() * n); return locs.get(r); } Selects the one location where the critter will move The makeMove method receives a location parameter. If the parameter is null, the critter is removed from the grid. If the parameter is not null, the critter moves to the new location. If an actor was in the location the critter is moving to, the actor is removed. makeMove must only modify the actors at this critter’s new and old locations. public void makeMove(Location loc) { if (loc == null) removeSelfFromGrid(); else moveTo(loc); } Moves the critter to the selected location Exercise Set 7 1. What methods are implemented in Critter? What does each do? – – – – act() checks that the Critter is in a grid and if so calls the other methods getActors() gets the neighboring Actors processActors() eats (removes) actors that are not Rocks or Critters getMoveLocations() returns valid empty neighboring locations (1 cell away) – selectMoveLocation() returns current location if no empty neighbors or a random empty neighbor – makeMove() if the location is null remove self from grid otherwise move to the location 2. What are the 5 basic actions common to all Critters when they act? – Get actors to process, process the actors, get a list of locations, select a location, move 3. Should subclasses of Critter override the getActors() method? – Yes, if they want to control the type of actors to interact with or to get more than just the neighboring Actors (one cell away) 4. Describe some ways a Critter could process actors? – Change their color, Change their direction, remove them from the grid, etc 5. What 3 methods must be invoked to make a Critter move? – getMoveLocations(), selectMoveLocation(), makeMove() 6. Why is there no Critter constructor? – Because it inherits from Actor and Actor has a no-arg constructor so by not providing any constructors the compiler will add a no-arg constructor that calls super() Extending the Critter Class • ChameleonCritter p. C-6 – Overrides processActors to pick a random actor and change its current color to the actor’s color – Overrides makeMove to also Tested turn toward the new location • CrabCritter – Overrides getActors to get actors straight ahead, diagonal left, and diagonal right (from front) – Overrides getMoveLocations to only move to the left or right – Overrides makeMove so that if it doesn’t move it randomly turns left or right Not Tested Exercise Answers Set 8 1. Why does act cause a ChameleonCritter to act differently than a Critter even though act is not overridden? • Because some of the methods called in act are overridden 2. Why does the makeMove method of ChameleonCritter call super.makeMove? • Because it wants to do the same actions as the parent class 3. How would you make a ChameleonCritter drop a flower in the old location when it moves? • Save the current location before you move and then create a flower and add it to this saved location just like in Bug 4. Why doesn’t ChameleonCritter override the getActors method? • It wants the same behavior 5. Which class contains the getLocation method? • Actor 6. How can a Critter access its own grid? • The inherited getGrid method (from Actor) Exercise Set 9 1. Why doesn’t CrabCritter override the processActors method? • Because it wants to eat the selected actors (except rocks and other critters) which is what the method in Critter does 2. Describe the process CrabCritter uses to find and eat actors. 1. Does it always eat all neighboring actors? • No. Only the ones in front, or diagonally left or right 2. Explain. • It overrides getActor() to only get these and then calls processActors() to eat them 3. Why is the getLocationsInDirections method used in CrabCritter? • To get the locations in front, diagonally left and right to get Actors in these locations 4. If a CrabCritter has location (3,4) and faces south what are the possible locations for actors returned by getActors? • (4,4), (4, 3), (4,5) Exercise Set 9 5. What are the similarities and differences between the movements of a CrabCritter and a Critter? • If a CrabCritter can’t move it randomly turns left or right, if it can move it moves like a Critter 6. How does a CrabCritter determine when it turns instead of moving? • It turns only if it can’t move 7. Why don’t the CrabCritter objects eat each other? • Because processActors in Critter won’t eat other Critters and a CrabCritter is a type of Critter Overview of GridWorld Creatures • Actors – Bugs • extending Bug: override Act – Rocks – Flowers – Critters • DO NOT OVERRIDE ACT!!! • extending Critter normally means that you are overriding one or more of the 5 methods Summary of what is tested API • • • • • Actor Flower Rock Grid Location API stands for “Application Programming Interface”. In Java, an API is the definition of how a programmer can access the functionality contained within a code library. Summary of what is tested Implementation • • • • Bug BoxBug Critter ChameleonCritter An Implementation is a class that implements or extends the given API in order to perform a specific function. Exercises 1. Create a class named EnhancedChameleon that extends ChameleonCritter. If there are no actors around this critter to process, its color should darken (like a flower). Hint: get the color of the critter and use some of the Color methods to darken each of its RGB values by subtracting .05 from each of them. 2. Create a class named ChameleonKid that extends ChameleonCritter as modified in exercise 1. A ChameleonKid changes its color to the color of one of the actors immediately in front or behind. If there is no actor in either of these locations, then the ChameleonKid darkens like the modified EnhancedChameleon. Exercises 3. Create a class called RockHound that extends Critter. A RockHound gets the actors to be processed in the same way as a Critter. It removes any rocks in that list from the grid. A RockHound moves like a Critter. 4. Create a class called BlusterCritter that extends Critter. A BlusterCritter looks at all of the neighbors within two steps of its current location. (For a BlusterCritter not near an edge, this includes 24 locations). It counts the number of critters in those locations. If there are fewer than c critters, the BlusterCritter’s color gets brighter (color values increase). If there are c or more critters, the BlusterCritter’s color darkens (color values decrease). Here c is a value that indicates the courage of the critter. It should be set in the constructor. Exercises 5. Create a class QuickCrab that extends CrabCritter. A QuickCrab processes actors the same way a CrabCritter does. A QuickCrab moves to one of the two locations, randomly selected, that are two spaces to its right or left, if that location and the intervening location are both empty. Otherwise a QuickCrab moves like a CrabCritter. 6. Create a class KingCrab that extends CrabCritter. A KingCrab gets the actors to be processed in the same way a CrabCritter does. A KingCrab causes each actor that it processes to move one location further away from the KingCrab. If the actor cannot move away, the KingCrab removes it from the grid. When the KingCrab has completed processing the actors, it moves like a CrabCritter. Group Activity • Specify – Create a new creature that extends Critter • Design – What variables are needed? What algorithms are needed? • Code – Implement the code • Test – Write test cases for the creature specified