// Class: AquaFish // // Author: Alyce Brady // // Created on July 10, 2002 // Modifications: // Date Name Reason // ---- ---- ------ // ? YourName ? import java.awt.Color; /** Aquarium Lab Series: * The AquaFish class defines a fish in an aquarium. * * @author Alyce Brady * @version 10 July 2002 * @see Aquarium * @see AquaPoint **/ public class AquaFish { // Named constants that specify how far a fish may move in one timestep private static final int MIN_DISTANCE = 10; private static final int MAX_DISTANCE = 70; // Class Variables: Shared among ALL fish private static int nextAvailableID = 1; // next avail unique identifier private static RandNumGenerator generator = RandNumGenerator.getInstance(); // random number generator // Instance Variables: Encapsulated data for EACH fish private Aquarium theAquarium; // aquarium in which this fish is swimming private int myID; // unique identifier for this fish private Color myColor; // fish's color private AquaPoint myPos; // fish's position in the Aquarium private Direction myDir; // fish's direction private int myLength, myHeight; // define size of fish private int halfLength, halfHeight; // useful for knowing perimeter of // fish (myPos is center position) /** * The AquaFish constructor sets properties of the AquaFish. * Precondition: the aquarium must be big enough to accommodate * the biggest fish (currently 75 pixels long and 30 pixels high) * plus 10 pixels of padding in all four directions. * @param aqua the Aquarium in which to place the fish **/ public AquaFish(Aquarium aqua) { // Place fish in aquarium and initialize ID and color. this (aqua, Color.white); /* NOTE: for randomly colored fish, use the statement below instead of the statement above. this (aqua, new Color (generator.nextInt(256), // amount of red generator.nextInt(256), // amount of green generator.nextInt(256))); // amount of blue */ } /** * The AquaFish constructor sets properties of the AquaFish. * This version of the constructor allows the user to select the * Color to be associated with the fish. * Precondition: the aquarium must be big enough to accomodate * the biggest fish (currently 75 pixels long and 30 pixels high) * plus 10 pixels of padding in all four directions. * @param aqua the Aquarium in which to place the fish * @param color the Color to associate with the fish **/ public AquaFish(Aquarium aqua, Color color) { // Place fish in aquarium and initialize ID and color. theAquarium = aqua; myID = nextAvailableID++; myColor = color; // Initialize size, position, and direction). initSize(); initPos(); } /** * Get the unique identifier for this fish. * @return the ID of the fish **/ public int id() { return myID; } /** Get fish's color. * @return the color of this fish **/ public Color color() { return myColor; } /** * Get the fish's position in the aquarium. * @return the position (point in the aquarium) of the fish **/ public AquaPoint position() { return myPos; } /** Get the length of the fish. * @return fish length **/ public int length() { return myLength; } /** Get the height of the fish. * @return fish height **/ public int height() { return myHeight; } /** * Determine whether the fish is facing right. * @return true if fish is facing right; * false otherwise **/ public boolean facingRight() { return myDir.equals(Direction.EAST); } /** * Determine whether the fish is facing left. * @return true if fish is facing left; * false otherwise **/ public boolean facingLeft() { return ! facingRight(); } /** * Compute how far the fish is from the wall in front of it. * @return distance from front of fish to facing wall **/ public int distanceToWall() { int leftEdgeOfFish = myPos.xCoord() - (halfLength + 1); int rightEdgeOfFish = myPos.xCoord() + (halfLength + 1); if ( facingRight() ) return (theAquarium.width() - rightEdgeOfFish); else return leftEdgeOfFish; // since left edge of aquarium is 0 } /** * Determine whether the fish is at a wall. * A fish is considered at a wall if it cannot move forward; in other * words, if the distance from the fish to the wall it faces is less * than the minimum distance that a fish can move forward. * @return true if fish is at a wall; * false otherwise **/ public boolean atWall() { return (distanceToWall() <= MIN_DISTANCE); } /** * Determine whether the fish is at the surface. * A fish is considered at the surface if it cannot ascend; in other * words, if the distance from the fish to the surface is less * than the fish's height. * @return true if fish is at the surface; * false otherwise **/ public boolean atSurface() { int topOfFish = myPos.yCoord() - (halfHeight + 1); return (topOfFish <= myHeight); } /** * Determine whether the fish is at the bottom. * A fish is considered at the bottom if it cannot descend; in other * words, if the distance from the fish to the bottom is less * than the fish's height. * @return true if fish is at the bottom; * false otherwise **/ public boolean atBottom() { int bottomOfFish = myPos.yCoord() + (halfHeight + 1); return (bottomOfFish >= (theAquarium.height() - myHeight)); } /** * This function is provided primarily for debugging purposes. * @return a string representation of a fish **/ public String toString() { String s = new String(); String dir = "R"; if ( facingLeft() ) dir = "L"; s = s + myID + myPos + dir + " "; return s; } /** * Move forward horizontally by random increments, staying * within the aquarium. **/ public void moveForward() { // First get random number in range [0, MAX_DISTANCE-MIN_DISTANCE], // then shift to [MIN_DISTANCE, MAX_DISTANCE]. If moving that // far would mean swimming out of the aquarium, only move to edge // of aquarium. Ajust fish's x coordinate by a positive or // negative amount, depending on whether fish is facing right or left. int moveAmt = generator.nextInt(MAX_DISTANCE - MIN_DISTANCE + 1); moveAmt += MIN_DISTANCE; if ( moveAmt >= distanceToWall() ) moveAmt = distanceToWall(); if ( facingRight() ) myPos.moveRight(moveAmt); else myPos.moveLeft(moveAmt); } /** * Reverse direction. **/ public void changeDir() { myDir = myDir.reverse(); } /** * Initialize fish size: * This helper function determines the height and length of the fish. * Fish are evenly distributed among 4 different sizes based on their * ID numbers. **/ private void initSize() { myLength = 30 + (myID % 4) * 15; myHeight = (int)Math.round(0.4*myLength); halfLength = (int)Math.round(myLength/2.0); halfHeight = (int)Math.round(myHeight/2.0); } /** * Initialize fish position and direction. * This helper function assigns coordinates to a fish such that the * fish is placed within the bounds of the Aquarium. * Precondition: the aquarium must be big enough to accomodate * the biggest fish (currently 75 pixels long and 30 pixels high) * plus 10 pixels of padding in all four directions. **/ private void initPos() { // Find random position within the bounds of the aquarium. int padding = 20; int myX = generator.nextInt(theAquarium.width() - myLength - padding) + padding/2; int myY = generator.nextInt(theAquarium.height() - myHeight - padding) + padding/2; // Since myX and myY indicate CENTER of fish, shift over half // the length and half the width. myX += halfLength; myY += halfHeight; // Initialize my position and direction. myPos = new AquaPoint(myX, myY); myDir = Direction.EAST; } }