General cleanups to path calculation
This commit is contained in:
parent
5537954180
commit
77f6e1c6c4
@ -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) {
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user