Complete the GiraffeCritter practice problem before reviewing the solution.

Review the GiraffeCritter solution with AP CS Tutor Brandon Horn.

public class GiraffeCritter extends Critter
{
    private int hungrySteps = 0;

    public ArrayList<Actor> getActors()
    {
        ArrayList<Actor> flowers = new ArrayList<Actor>();

        for (int row = getLocation().getRow() - NECK_SIZE;
                row <= getLocation().getRow() + NECK_SIZE;
                row++)
        {
            for (int col = getLocation().getCol() - NECK_SIZE;
                    col <= getLocation().getCol() + NECK_SIZE;
                    col++)
            {
                Location loc = new Location(row, col);
                if (getGrid().isValid(loc) && getGrid().get(loc) instanceof Flower)
                    flowers.add(getGrid().get(loc));
            }
        }

        return flowers;

        // Alternative is to return all actors within range here and find flowers in processActors
    }

    public void processActors(ArrayList<Actor> actors)
    {
        int flowersEaten = 0;

        for (Actor a : actors)
        {
            if (flowersEaten < STOMACH_SIZE)
            {
                a.removeSelfFromGrid();
                flowersEaten++;
            }
        }

        if (flowersEaten == STOMACH_SIZE)
            hungrySteps = 0;
        else
            hungrySteps++;
    }

    public Location selectMoveLocation(ArrayList<Location> locs)
    {
        if (hungrySteps >= MAX_HUNGRY_STEPS)
            return null;
        else if (hungrySteps == 0)
            return getLocation();
        else
            return super.selectMoveLocation(locs);
    }
}

Overriding the correct methods is an important part of this problem. As with all creatures that extend Critter, you must not override act.

GiraffeCritter gets a different list of actors to process than Critter, so it must override getActors. Specifically, GiraffeCritter gets flowers within NECK_LENGTH rows and NECK_LENGTH columns. You cannot get the list of actors to process in processActors since you would violate the postcondition when removing an actor that is not in the parameter actors.

GiraffeCritter processes actors differently than Critter, so it must override processActors. Specifically, GiraffeCritter attempts to eat a certain number of flowers and keeps track of how many flowers have been eaten. The postcondition of processActors permits the state of GiraffeCritter to be changed, so you can update the instance field that tracks how many steps the GiraffeCritter has been hungry.

GiraffeCritter moves differently than Critter, so it must override at least one of the methods that control movement. Overriding selectMoveLocation results in code that does not violate the postconditions of any method. Since the postcondition of selectMoveLocation prohibits changing the state of any actor, the private instance field cannot be updated. You cannot call removeSelfFromGrid in selectMoveLocation. Doing so would violate the postcondition that prohibits changing the state of any actor.

It is not possible to achieve the desired behavior without violating any postconditions by overriding only makeMove. The postcondition of makeMove requires that a call to getLocation immediately after a call to makeMove return loc (the parameter to makeMove). You cannot make a decision about whether to move or not in makeMove. You must move to the parameter loc.