<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">// Class: GridFish
//
// Author: Alyce Brady
//
// This class is based on the College Board's Fish class,
// as allowed by the GNU General Public License.  Fish is a
// component of the AP(r) CS Marine Biology Simulation
// case study (see
// http://www.collegeboard.com/student/testing/ap/compsci_a/case.html).
//
// License Information:
//   This class 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 class 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.

package edu.kzoo.mbsInAGrid;

import java.awt.Color;
import java.util.ArrayList;
import java.util.Random;

import edu.kzoo.util.Debug;
import edu.kzoo.util.NamedColor;
import edu.kzoo.util.RandNumGenerator;

import edu.kzoo.grid.Direction;
import edu.kzoo.grid.Grid;
import edu.kzoo.grid.GridObject;
import edu.kzoo.grid.Location;

/**
 *  Grid Container Package Examples:&lt;br&gt;
 * 
 *  A &lt;code&gt;GridFish&lt;/code&gt; object represents a fish similar to an
 *  instance of the &lt;code&gt;Fish&lt;/code&gt; class in the College Board's
 *  Marine Biology Simulation, but implemented as a subclass of the
 *  &lt;code&gt;GridObject&lt;/code&gt; class.
 *
 *  &lt;p&gt;
 *  The &lt;code&gt;GridFish&lt;/code&gt; class is based on the College Board's
 *  &lt;code&gt;Fish&lt;/code&gt; class, as allowed by the GNU General
 *  Public License.
 *
 *  @author Alyce Brady
 *  @version 10 March 2004
 *  @see Grid
 *  @see Direction
 *  @see Location
 **/

public class GridFish extends GridObject
{
  // class variable: shared among ALL fish
    private static int nextAvailableID = 1;   // next avail unique identifier

  // instance variables: encapsulated data for EACH fish
    private int myId;                  // unique ID for this fish
    private Direction myDir;           // fish's direction
    private Color myColor;             // fish's color


  // constructors

    /** Constructs a fish at the specified location in a given grid.
     *  The GridFish is assigned a random direction and random color.
     *  (Precondition: parameters are non-null; &lt;code&gt;loc&lt;/code&gt; is valid
     *  for &lt;code&gt;grid&lt;/code&gt;.)
     *  @param grid   grid in which fish will live
     *  @param loc    location of the new fish in &lt;code&gt;grid&lt;/code&gt;
     **/
    public GridFish(Grid grid, Location loc)
    {
        this(grid, loc, grid.randomDirection(), NamedColor.getRandomColor());
    }

    /** Constructs a fish at the specified location and direction in a
     *  given Grid.  The GridFish is assigned a random color.
     *  (Precondition: parameters are non-null; &lt;code&gt;loc&lt;/code&gt; is valid
     *  for &lt;code&gt;grid&lt;/code&gt;.)
     *  @param grid   grid in which fish will live
     *  @param loc    location of the new fish in &lt;code&gt;grid&lt;/code&gt;
     *  @param dir    direction the new fish is facing
     **/
    public GridFish(Grid grid, Location loc, Direction dir)
    {
        this(grid, loc, dir, NamedColor.getRandomColor());
    }

    /** Constructs a fish of the specified color at the specified location
     *  and direction.
     *  (Precondition: parameters are non-null; &lt;code&gt;loc&lt;/code&gt; is valid
     *  for &lt;code&gt;grid&lt;/code&gt;.)
     *  @param grid   grid in which fish will live
     *  @param loc    location of the new fish in &lt;code&gt;grid&lt;/code&gt;
     *  @param dir    direction the new fish is facing
     *  @param col    color of the new fish
     **/
    public GridFish(Grid grid, Location loc, Direction dir, Color col)
    {
        super(grid, loc);
        myId = nextAvailableID;
        nextAvailableID++;
        myDir = dir;
        myColor = col;
    }


  // accessor methods

    /** Returns this fish's ID.
     *  @return        the unique ID for this fish
     **/
    public int id()
    {
        return myId;
    }

    /** Returns this fish's color.
     *  @return        the color of this fish
     **/
    public Color color()
    {
        return myColor;
    }

    /** Returns this fish's direction.
     *  @return        the direction in which this fish is facing
     **/
    public Direction direction()
    {
        return myDir;
    }

    /** Returns a string representing key information about this fish.
     *  @return  a string indicating the fish's ID, location, and direction
     **/
    public String toString()
    {
        return id() + location().toString() + direction().toString();
    }


  // modifier method

    /** Acts for one step in the simulation.
     **/
    public void act()
    {
        // Make sure fish is alive and well in the grid -- fish
        // that have been removed from a grid shouldn't act.
        if ( isInAGrid() ) 
            move();
    }


  // internal helper methods

    /** Moves this fish in its grid.
     **/
    protected void move()
    {
        // Find a location to move to.
        Debug.print("GridFish " + toString() + " attempting to move.  ");
        Location nextLoc = nextLocation();

        // If the next location is different, move there.
        if ( ! nextLoc.equals(location()) )
        {
            // Move to new location.
            Location oldLoc = location();
            changeLocation(nextLoc);
                 // Note: changeLocation is inherited from GridObject

            // Update direction in case fish had to turn to move.
            Direction newDir = grid().getDirection(oldLoc, nextLoc);
            changeDirection(newDir);
            Debug.println("  Moves to " + location() + direction());
        }
        else
            Debug.println("  Does not move.");
    }

    /** Finds this fish's next location.
     *  A fish may move to any empty adjacent locations except the one
     *  behind it (fish do not move backwards).  If this fish cannot
     *  move, &lt;code&gt;nextLocation&lt;/code&gt; returns its current location.
     *  @return    the next location for this fish
     **/
    protected Location nextLocation()
    {
        // Get list of neighboring empty locations.
        ArrayList emptyNbrs = emptyNeighbors();

        // Remove the location behind, since fish do not move backwards.
        Direction oppositeDir = direction().reverse();
        Location locationBehind = grid().getNeighbor(location(),
                                                            oppositeDir);
        emptyNbrs.remove(locationBehind);
        Debug.print("Possible new locations are: " + emptyNbrs.toString());

        // If there are no valid empty neighboring locations, then we're done.
        if ( emptyNbrs.size() == 0 )
            return location();

        // Return a randomly chosen neighboring empty location.
        Random randNumGen = RandNumGenerator.getInstance();
        int randNum = randNumGen.nextInt(emptyNbrs.size());
	    return (Location) emptyNbrs.get(randNum);
    }

    /** Finds empty locations adjacent to this fish.
     *  @return    an ArrayList containing neighboring empty locations
     **/
    protected ArrayList emptyNeighbors()
    {
        // Get all the neighbors of this fish, empty or not.
        ArrayList nbrs = grid().neighborsOf(location());

        // Figure out which neighbors are empty and add those to a new list.
        ArrayList emptyNbrs = new ArrayList();
        for ( int index = 0; index &lt; nbrs.size(); index++ )
        {
            Location loc = (Location) nbrs.get(index);
            if ( grid().isEmpty(loc) )
                emptyNbrs.add(loc);
        }

        return emptyNbrs;
    }

    /** Modifies this fish's direction.
     *  @param  newDir    new direction value
     **/
    protected void changeDirection(Direction newDir)
    {
        // Change direction.
        myDir = newDir;
    }

}
</pre></body></html>