Skip to content
Permalink
18ea6546a4
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
349 lines (309 sloc) 9.58 KB
/*
Copyright (C) 2012 http://software-talk.org/ (developer@software-talk.org)
This program 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, either version 3 of the License, or
(at your option) any later version.
This program 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.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* This class represents an AbstractNode. It has all the appropriate fields as well
* as getter and setter to be used by the A* algorithm.
* <p>
* <p>
* An <code>AbstractNode</code> has x- and y-coordinates and can be walkable or not.
* A previous AbstractNode may be set, as well as the
* <code>fCosts</code>, <code>gCosts</code> and <code>hCosts</code>.
* <p>
* <p>
* <code>fCosts</code>: <code>gCosts</code> + <code>hCosts</code>
* <p>
* <code>gCosts</code>: calculated costs from start AbstractNode to this AbstractNode
* <p>
* <code>hCosts</code>: estimated costs to get from this AbstractNode to end AbstractNode
* <p>
* <p>
* A subclass has to override the heuristic function
* <p>
* <code>sethCosts(AbstractNode endAbstractNode)</code>
* <p>
* @see ExampleNode#sethCosts(AbstractNode endNode) example Implementation using manhatten method
* <p>
*
* @version 1.0
*/
public abstract class AbstractNode {
/** costs to move sideways from one square to another. */
protected static final float BASICMOVEMENTCOST = 10;
/** costs to move diagonally from one square to another. */
protected static final float DIAGONALMOVEMENTCOST = 14;
protected float xPosition;
protected float yPosition;
protected boolean walkable;
// for pathfinding:
/** the previous AbstractNode of this one on the currently calculated path. */
protected AbstractNode previous;
/** weather or not the move from previous to this AbstractNode is diagonally. */
protected boolean diagonally;
/** optional extra penalty. */
protected float movementPanelty;
//private float fCosts; // g + h costs
/** calculated costs from start AbstractNode to this AbstractNode. */
protected float gCosts;
/** estimated costs to get from this AbstractNode to end AbstractNode. */
protected float hCosts;
/**
* constructs a walkable AbstractNode with given coordinates.
*
* @param xPosition
* @param yPosition
*/
public AbstractNode(float xPosition, float yPosition) {
this.xPosition = xPosition;
this.yPosition = yPosition;
this.walkable = true;
this.movementPanelty = 0;
}
/**
* returns weather or not the move from the <code>previousAbstractNode</code> was
* diagonally. If it is not diagonal, it is sideways.
*
* @return
*/
public boolean isDiagonaly() {
return diagonally;
}
/**
* sets weather or not the move from the <code>previousAbstractNode</code> was
* diagonally. If it is not diagonal, it is sideways.
*
* @param isDiagonaly
*/
public void setIsDiagonaly(boolean isDiagonaly) {
this.diagonally = isDiagonaly;
}
/**
* sets x and y coordinates.
*
* @param x
* @param y
*/
public void setCoordinates(float x, float y) {
this.xPosition = x;
this.yPosition = y;
}
/**
* @return the xPosition
*/
public float getxPosition() {
return xPosition;
}
/**
* @return the yPosition
*/
public float getyPosition() {
return yPosition;
}
/**
* @return the walkable
*/
public boolean isWalkable() {
return walkable;
}
/**
* @param walkable the walkable to set
*/
public void setWalkable(boolean walkable) {
this.walkable = walkable;
}
/**
* returns the node set as previous node on the current path.
*
* @return the previous
*/
public AbstractNode getPrevious() {
return previous;
}
/**
* @param previous the previous to set
*/
public void setPrevious(AbstractNode previous) {
this.previous = previous;
}
/**
* sets a general penalty for the movement on this node.
*
* @param movementPanelty the movementPanelty to set
*/
public void setMovementPanelty(float movementPanelty) {
this.movementPanelty = movementPanelty;
}
/**
* returns <code>gCosts</code> + <code>hCosts</code>.
* <p>
*
*
* @return the fCosts
*/
public float getfCosts() {
return gCosts + hCosts;
}
/**
* returns the calculated costs from start AbstractNode to this AbstractNode.
*
* @return the gCosts
*/
public float getgCosts() {
return gCosts;
}
/**
* sets gCosts to <code>gCosts</code> plus <code>movementPanelty</code>
* for this AbstractNode.
*
* @param gCosts the gCosts to set
*/
private void setgCosts(float gCosts) {
this.gCosts = gCosts + movementPanelty;
}
/**
* sets gCosts to <code>gCosts</code> plus <code>movementPanelty</code>
* for this AbstractNode given the previous AbstractNode as well as the basic cost
* from it to this AbstractNode.
*
* @param previousAbstractNode
* @param basicCost
*/
public void setgCosts(AbstractNode previousAbstractNode, float basicCost) {
setgCosts(previousAbstractNode.getgCosts() + basicCost);
}
/**
* sets gCosts to <code>gCosts</code> plus <code>movementPanelty</code>
* for this AbstractNode given the previous AbstractNode.
* <p>
* It will assume <code>BASICMOVEMENTCOST</code> as the cost from
* <code>previousAbstractNode</code> to itself if the movement is not diagonally,
* otherwise it will assume <code>DIAGONALMOVEMENTCOST</code>.
* Weather or not it is diagonally is set in the Map class method which
* finds the adjacent AbstractNodes.
*
* @param previousAbstractNode
*/
public void setgCosts(AbstractNode previousAbstractNode) {
if (diagonally) {
setgCosts(previousAbstractNode, DIAGONALMOVEMENTCOST);
} else {
setgCosts(previousAbstractNode, BASICMOVEMENTCOST);
}
}
/**
* calculates - but does not set - g costs.
* <p>
* It will assume <code>BASICMOVEMENTCOST</code> as the cost from
* <code>previousAbstractNode</code> to itself if the movement is not diagonally,
* otherwise it will assume <code>DIAGONALMOVEMENTCOST</code>.
* Weather or not it is diagonally is set in the Map class method which
* finds the adjacent AbstractNodes.
*
* @param previousAbstractNode
* @return gCosts
*/
public float calculategCosts(AbstractNode previousAbstractNode) {
if (diagonally) {
return (previousAbstractNode.getgCosts()
+ DIAGONALMOVEMENTCOST + movementPanelty);
} else {
return (previousAbstractNode.getgCosts()
+ BASICMOVEMENTCOST + movementPanelty);
}
}
/**
* calculates - but does not set - g costs, adding a movementPanelty.
*
* @param previousAbstractNode
* @param movementCost costs from previous AbstractNode to this AbstractNode.
* @return gCosts
*/
public float calculategCosts(AbstractNode previousAbstractNode, float movementCost) {
return (previousAbstractNode.getgCosts() + movementCost + movementPanelty);
}
/**
* returns estimated costs to get from this AbstractNode to end AbstractNode.
*
* @return the hCosts
*/
public float gethCosts() {
return hCosts;
}
/**
* sets hCosts.
*
* @param hCosts the hCosts to set
*/
protected void sethCosts(float hCosts) {
this.hCosts = hCosts;
}
/**
* calculates hCosts for this AbstractNode to a given end AbstractNode.
* Uses Manhatten method.
*
* @param endAbstractNode
*/
public abstract void sethCosts(AbstractNode endAbstractNode);
/*
* @return the movementPanelty
*/
private float getMovementPanelty() {
return movementPanelty;
}
/**
* returns a String containing the coordinates, as well as h, f and g
* costs.
*
* @return
*/
@Override
public String toString() {
return "(" + getxPosition() + ", " + getyPosition() + "): h: "
+ gethCosts() + " g: " + getgCosts() + " f: " + getfCosts();
}
/**
* returns weather the coordinates of AbstractNodes are equal.
*
* @param obj
* @return
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final AbstractNode other = (AbstractNode) obj;
if (this.xPosition != other.xPosition) {
return false;
}
if (this.yPosition != other.yPosition) {
return false;
}
return true;
}
/**
* returns hash code calculated with coordinates.
*
* @return
*/
@Override
public int hashCode() {
int hash = 3;
hash = 17 * hash + (int)this.xPosition;
hash = 17 * hash + (int)this.yPosition;
return hash;
}
}