Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
The only steps left is giving better definitions to the cost function…
…s of the Nodes and the finishing the A-Star implmentation to work with our graph data structure.
  • Loading branch information
rjm11010 committed May 3, 2018
1 parent e41e67a commit 18ea654
Show file tree
Hide file tree
Showing 10 changed files with 651 additions and 135 deletions.
349 changes: 349 additions & 0 deletions AbstractNode.java
@@ -0,0 +1,349 @@
/*
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;
}

}
11 changes: 4 additions & 7 deletions pathfinding/Node.java → Node.java
@@ -1,9 +1,6 @@
/**
Our Implementation of an AbstractNode
*/

package pathfinding;

import java.util.ArrayList;

/**
Expand Down Expand Up @@ -56,19 +53,19 @@ public class Node extends AbstractNode {
// Getting
// --------------------------------------------------------

public Node getLeft(Node aNode) {
public Node getLeft() {
return neighbors.get(LEFT);
}

public Node getStraight(Node aNode) {
public Node getStraight() {
return neighbors.get(STRAIGHT);
}

public Node getRight(Node aNode) {
public Node getRight() {
return neighbors.get(RIGHT);
}

public ArrayList<Node> get_neighbors() {
public ArrayList<Node> getNeighbors() {
return neighbors;
}

Expand Down

0 comments on commit 18ea654

Please sign in to comment.