General cleanups to path calculation

This commit is contained in:
Brady 2018-08-02 20:48:21 -07:00
parent 5537954180
commit 77f6e1c6c4
No known key found for this signature in database
GPG Key ID: 73A788379A197567
3 changed files with 49 additions and 34 deletions

View File

@ -12,6 +12,7 @@ import java.util.List;
* @author leijurv
*/
public interface IPath {
/**
* Ordered list of movements to carry out.
* movements.get(i).getSrc() should equal positions.get(i)
@ -44,11 +45,13 @@ public interface IPath {
}
/**
* @param currentPosition
* @return
* Determines whether or not a position is within this path.
*
* @param pos The position to check
* @return Whether or not the specified position is in this class
*/
default boolean isInPath(BlockPos currentPosition) {
return positions().contains(currentPosition);
default boolean isInPath(BlockPos pos) {
return positions().contains(pos);
}
default Tuple<Double, BlockPos> closestPathPos(double x, double y, double z) {

View File

@ -14,65 +14,73 @@ import java.util.stream.Collectors;
* @author leijurv
*/
class Path implements IPath {
public final BlockPos start;
public final BlockPos end;
public final Goal goal;
/**
* The blocks on the path. Guaranteed that path.get(0) equals start and
* path.get(path.size()-1) equals end
*/
public final ArrayList<BlockPos> path;
final ArrayList<Movement> movements;
public final List<BlockPos> path;
final List<Movement> movements;
Path(PathNode start, PathNode end, Goal goal) {
this.start = start.pos;
this.end = end.pos;
this.goal = goal;
this.path = new ArrayList<>();
this.movements = new ArrayList<>();
this.path = new LinkedList<>();
this.movements = new LinkedList<>();
assemblePath(start, end);
sanityCheck();
}
private final void assemblePath(PathNode start, PathNode end) {
private void assemblePath(PathNode start, PathNode end) {
if (!path.isEmpty() || !movements.isEmpty()) {
throw new IllegalStateException();
}
PathNode current = end;
LinkedList<BlockPos> tempPath = new LinkedList<>();//repeatedly inserting to the beginning of an arraylist is O(n^2)
LinkedList<Movement> tempMovements = new LinkedList<>();//instead, do it into a linked list, then convert at the end
LinkedList<BlockPos> tempPath = new LinkedList<>(); // Repeatedly inserting to the beginning of an arraylist is O(n^2)
LinkedList<Movement> tempMovements = new LinkedList<>(); // Instead, do it into a linked list, then convert at the end
while (!current.equals(start)) {
tempPath.addFirst(current.pos);
tempMovements.addFirst(current.previousMovement);
current = current.previous;
}
tempPath.addFirst(start.pos);
//can't directly convert from the PathNode pseudo linked list to an array because we don't know how long it is
//inserting into a LinkedList<E> keeps track of length, then when we addall (which calls .toArray) it's able
//to performantly do that conversion since it knows the length.
// Can't directly convert from the PathNode pseudo linked list to an array because we don't know how long it is
// inserting into a LinkedList<E> keeps track of length, then when we addall (which calls .toArray) it's able
// to performantly do that conversion since it knows the length.
path.addAll(tempPath);
movements.addAll(tempMovements);
}
public void sanityCheck() {
/**
* Performs a series of checks to ensure that the assembly of the path went as expected.
*/
private void sanityCheck() {
if (!start.equals(path.get(0))) {
throw new IllegalStateException();
throw new IllegalStateException("Start node does not equal first path element");
}
if (!end.equals(path.get(path.size() - 1))) {
throw new IllegalStateException();
throw new IllegalStateException("End node does not equal last path element");
}
if (path.size() != movements.size() + 1) {
throw new IllegalStateException();
throw new IllegalStateException("Size of path array is unexpected");
}
for (int i = 0; i < path.size(); i++) {
BlockPos src = path.get(i);
BlockPos dest = path.get(i + 1);
Movement movement = movements.get(i);
if (!src.equals(movement.getSrc())) {
throw new IllegalStateException();
throw new IllegalStateException("Path source is not equal to the movement source");
}
if (!dest.equals(movement.getDest())) {
throw new IllegalStateException();
throw new IllegalStateException("Path destination is not equal to the movement destination");
}
}
}

View File

@ -12,19 +12,25 @@ import java.util.Objects;
* @author leijurv
*/
class PathNode {
final BlockPos pos;
final Goal goal;
final double estimatedCostToGoal;
// These three fields are mutable and are changed by PathFinder
double cost;
PathNode previous;
Movement previousMovement;
/**
* Is this a member of the open set in A*? (only used during pathfinding)
*/
boolean isOpen;
/**
* In the linked list of open nodes, which one is next? (only used during pathfinding)
*/
@ -40,30 +46,28 @@ class PathNode {
this.isOpen = false;
}
// TODO possibly reimplement hashCode and equals. They are necessary for this class to function but they could be done better
/**
* TODO: Possibly reimplement hashCode and equals. They are necessary for this class to function but they could be done better
*
* @return The hash code value for this {@link PathNode}
*/
@Override
public int hashCode() {//this is some OG code right here
public int hashCode() {
int hash = 3241;
hash = 3457689 * hash + this.pos.getX();
hash = 8734625 * hash + this.pos.getY();
hash = 2873465 * hash + this.pos.getZ();
hash = 3241543 * hash + Objects.hashCode(this.goal);//don't call goal.hashcode. this calls objects hashcode to verify that the actual goal objects are == identical, which is important for node caching
// Don't call goal.hashCode(). this calls objects hashcode to verify that the actual goal objects are == identical, which is important for node caching
hash = 3241543 * hash + Objects.hashCode(this.goal);
return hash;
}
@Override
public boolean equals(Object obj) {//autogenerated by netbeans. that's why it looks disgusting.
if (obj == null) {
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof PathNode))
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final PathNode other = (PathNode) obj;
if (!Objects.equals(this.pos, other.pos)) {
return false;
}
return Objects.equals(this.goal, other.goal);
return Objects.equals(this.pos, other.pos) && Objects.equals(this.goal, other.goal);
}
}