/*
* AP(r) Computer Science GridWorld Case Study:
* Copyright(c) 2002-2006 College Entrance Examination Board
* (http://www.collegeboard.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 Alyce Brady
* @author Chris Nevison
* @author APCS Development Committee
* @author Cay Horstmann
*/
package info.gridworld.grid;
/**
* A <code>Location</code> object represents the row and column of a location
* in a two-dimensional grid. <br />
* The API of this class is testable on the AP CS A and AB exams.
*/
public class Location implements Comparable
{
private int row; // row location in grid
private int col; // column location in grid
/**
* The turn angle for turning 90 degrees to the left.
*/
public static final int LEFT = -90;
/**
* The turn angle for turning 90 degrees to the right.
*/
public static final int RIGHT = 90;
/**
* The turn angle for turning 45 degrees to the left.
*/
public static final int HALF_LEFT = -45;
/**
* The turn angle for turning 45 degrees to the right.
*/
public static final int HALF_RIGHT = 45;
/**
* The turn angle for turning a full circle.
*/
public static final int FULL_CIRCLE = 360;
/**
* The turn angle for turning a half circle.
*/
public static final int HALF_CIRCLE = 180;
/**
* The turn angle for making no turn.
*/
public static final int AHEAD = 0;
/**
* The compass direction for north.
*/
public static final int NORTH = 0;
/**
* The compass direction for northeast.
*/
public static final int NORTHEAST = 45;
/**
* The compass direction for east.
*/
public static final int EAST = 90;
/**
* The compass direction for southeast.
*/
public static final int SOUTHEAST = 135;
/**
* The compass direction for south.
*/
public static final int SOUTH = 180;
/**
* The compass direction for southwest.
*/
public static final int SOUTHWEST = 225;
/**
* The compass direction for west.
*/
public static final int WEST = 270;
/**
* The compass direction for northwest.
*/
public static final int NORTHWEST = 315;
/**
* Constructs a location with given row and column coordinates.
* @param r the row
* @param c the column
*/
public Location(int r, int c)
{
row = r;
col = c;
}
/**
* Gets the row coordinate.
* @return the row of this location
*/
public int getRow()
{
return row;
}
/**
* Gets the column coordinate.
* @return the column of this location
*/
public int getCol()
{
return col;
}
/**
* Gets the adjacent location in any one of the eight compass directions.
* @param direction the direction in which to find a neighbor location
* @return the adjacent location in the direction that is closest to
* <tt>direction</tt>
*/
public Location getAdjacentLocation(int direction)
{
// reduce mod 360 and round to closest multiple of 45
int adjustedDirection = (direction + HALF_RIGHT / 2) % FULL_CIRCLE;
if (adjustedDirection < 0)
adjustedDirection += FULL_CIRCLE;
adjustedDirection = (adjustedDirection / HALF_RIGHT) * HALF_RIGHT;
int dc = 0;
int dr = 0;
if (adjustedDirection == EAST)
dc = 1;
else if (adjustedDirection == SOUTHEAST)
{
dc = 1;
dr = 1;
}
else if (adjustedDirection == SOUTH)
dr = 1;
else if (adjustedDirection == SOUTHWEST)
{
dc = -1;
dr = 1;
}
else if (adjustedDirection == WEST)
dc = -1;
else if (adjustedDirection == NORTHWEST)
{
dc = -1;
dr = -1;
}
else if (adjustedDirection == NORTH)
dr = -1;
else if (adjustedDirection == NORTHEAST)
{
dc = 1;
dr = -1;
}
return new Location(getRow() + dr, getCol() + dc);
}
/**
* Returns the direction from this location toward another location. The
* direction is rounded to the nearest compass direction.
* @param target a location that is different from this location
* @return the closest compass direction from this location toward
* <code>target</code>
*/
public int getDirectionToward(Location target)
{
int dx = target.getCol() - getCol();
int dy = target.getRow() - getRow();
// y axis points opposite to mathematical orientation
int angle = (int) Math.toDegrees(Math.atan2(-dy, dx));
// mathematical angle is counterclockwise from x-axis,
// compass angle is clockwise from y-axis
int compassAngle = RIGHT - angle;
// prepare for truncating division by 45 degrees
compassAngle += HALF_RIGHT / 2;
// wrap negative angles
if (compassAngle < 0)
compassAngle += FULL_CIRCLE;
// round to nearest multiple of 45
return (compassAngle / HALF_RIGHT) * HALF_RIGHT;
}
/**
* Indicates whether some other <code>Location</code> object is "equal to"
* this one.
* @param other the other location to test
* @return <code>true</code> if <code>other</code> is a
* <code>Location</code> with the same row and column as this location;
* <code>false</code> otherwise
*/
public boolean equals(Object other)
{
if (!(other instanceof Location))
return false;
Location otherLoc = (Location) other;
return getRow() == otherLoc.getRow() && getCol() == otherLoc.getCol();
}
/**
* Generates a hash code.
* @return a hash code for this location
*/
public int hashCode()
{
return getRow() * 3737 + getCol();
}
/**
* Compares this location to <code>other</code> for ordering. Returns a
* negative integer, zero, or a positive integer as this location is less
* than, equal to, or greater than <code>other</code>. Locations are
* ordered in row-major order. <br />
* (Precondition: <code>other</code> is a <code>Location</code> object.)
* @param other the other location to test
* @return a negative integer if this location is less than
* <code>other</code>, zero if the two locations are equal, or a positive
* integer if this location is greater than <code>other</code>
*/
public int compareTo(Object other)
{
Location otherLoc = (Location) other;
if (getRow() < otherLoc.getRow())
return -1;
if (getRow() > otherLoc.getRow())
return 1;
if (getCol() < otherLoc.getCol())
return -1;
if (getCol() > otherLoc.getCol())
return 1;
return 0;
}
/**
* Creates a string that describes this location.
* @return a string with the row and column of this location, in the format
* (row, col)
*/
public String toString()
{
return "(" + getRow() + ", " + getCol() + ")";
}
}