/*
* 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;
/**
* A <code>Critter</code> 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 for <code>act</code>. When you override these methods, be sure to
* preserve the postconditions. <br />
* 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;
ArrayList<Actor> actors = getActors();
processActors(actors);
ArrayList<Location> 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.<br />
* Postcondition: The state of all actors is unchanged.
* @return a list of actors that this critter wishes to process.
*/
public ArrayList<Actor> getActors()
{
return getGrid().getNeighbors(getLocation());
}
/**
* Processes the elements of <code>actors</code>. 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. <br />
* Postcondition: (1) The state of all actors in the grid other than this
* critter and the elements of <code>actors</code> is unchanged. (2) The
* location of this critter is unchanged.
* @param actors the actors to be processed
*/
public void processActors(ArrayList<Actor> actors)
{
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.<br />
* Postcondition: The state of all actors is unchanged.
* @return a list of possible locations for the next move
*/
public ArrayList<Location> getMoveLocations()
{
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
* <code>locs</code> has size 0. Override this method in subclasses that
* have another mechanism for selecting the next move location. <br />
* Postcondition: (1) The returned location is an element of
* <code>locs</code>, this critter's current location, or
* <code>null</code>. (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(ArrayList<Location> locs)
{
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 <code>loc</code>, or removes
* this critter from its grid if <code>loc</code> is <code>null</code>.
* An actor may be added to the old location. If there is a different actor
* at location <code>loc</code>, 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). <br />
* Postcondition: (1) <code>getLocation() == loc</code>. (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);
}
}