Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Found an [implementation of A-Star](https://software-talk.org/blog/20…
…12/01/a-star-java/), and will be using this a framework to cast on our track.
  • Loading branch information
rjm11010 committed Apr 30, 2018
1 parent 2abd3d2 commit 5a7f0e0
Show file tree
Hide file tree
Showing 9 changed files with 1,571 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
*.class
351 changes: 351 additions & 0 deletions pathfinding/AbstractNode.java
@@ -0,0 +1,351 @@
/*
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/>.
*/

package pathfinding;

/**
* 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 int BASICMOVEMENTCOST = 10;
/** costs to move diagonally from one square to another. */
protected static final int DIAGONALMOVEMENTCOST = 14;

private int xPosition;
private int yPosition;
private boolean walkable;

// for pathfinding:

/** the previous AbstractNode of this one on the currently calculated path. */
private AbstractNode previous;

/** weather or not the move from previous to this AbstractNode is diagonally. */
private boolean diagonally;

/** optional extra penalty. */
private int movementPanelty;

//private int fCosts; // g + h costs

/** calculated costs from start AbstractNode to this AbstractNode. */
private int gCosts;

/** estimated costs to get from this AbstractNode to end AbstractNode. */
private int hCosts;

/**
* constructs a walkable AbstractNode with given coordinates.
*
* @param xPosition
* @param yPosition
*/
public AbstractNode(int xPosition, int 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(int x, int y) {
this.xPosition = x;
this.yPosition = y;
}

/**
* @return the xPosition
*/
public int getxPosition() {
return xPosition;
}

/**
* @return the yPosition
*/
public int 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(int movementPanelty) {
this.movementPanelty = movementPanelty;
}

/**
* returns <code>gCosts</code> + <code>hCosts</code>.
* <p>
*
*
* @return the fCosts
*/
public int getfCosts() {
return gCosts + hCosts;
}

/**
* returns the calculated costs from start AbstractNode to this AbstractNode.
*
* @return the gCosts
*/
public int 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(int 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, int 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 int 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 int calculategCosts(AbstractNode previousAbstractNode, int movementCost) {
return (previousAbstractNode.getgCosts() + movementCost + movementPanelty);
}

/**
* returns estimated costs to get from this AbstractNode to end AbstractNode.
*
* @return the hCosts
*/
public int gethCosts() {
return hCosts;
}

/**
* sets hCosts.
*
* @param hCosts the hCosts to set
*/
protected void sethCosts(int 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 int 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 + this.xPosition;
hash = 17 * hash + this.yPosition;
return hash;
}

}
30 changes: 30 additions & 0 deletions pathfinding/ExampleFactory.java
@@ -0,0 +1,30 @@
/*
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/>.
*/

package pathfinding;

/**
* A simple Factory for example nodes.
*/
public class ExampleFactory implements NodeFactory {

@Override
public AbstractNode createNode(int x, int y) {
return new ExampleNode(x, y);
}

}

0 comments on commit 5a7f0e0

Please sign in to comment.