Separated node class from DFS class.
This commit is contained in:
parent
de3b3a614a
commit
be19db1f9b
@ -0,0 +1,72 @@
|
|||||||
|
package ca.recrown.islandsurvivalcraft.pathfinding;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class DFSNode implements Comparable<DFSNode> {
|
||||||
|
private DFSNode goal;
|
||||||
|
public DFSNode[] child;
|
||||||
|
private DFSNode parent;
|
||||||
|
private int x;
|
||||||
|
private int y;
|
||||||
|
|
||||||
|
public DFSNode(DFSNode parent, int x, int y, DFSNode goal) {
|
||||||
|
child = new DFSNode[4];
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.parent = parent;
|
||||||
|
this.goal = goal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DFSNode getGoal() {
|
||||||
|
return goal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(DFSNode o) {
|
||||||
|
if (goal == null) return 0;
|
||||||
|
return Math.round(distanceToGoal(goal) - o.distanceToGoal(goal));
|
||||||
|
}
|
||||||
|
|
||||||
|
public DFSNode getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float distanceToGoal(DFSNode goal) {
|
||||||
|
float distanceX = goal.x - this.x;
|
||||||
|
float distanceY = goal.y - this.y;
|
||||||
|
float distance = (float) Math.sqrt(distanceX * distanceX + distanceY * distanceY);
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj instanceof DFSNode) {
|
||||||
|
DFSNode comp = (DFSNode) obj;
|
||||||
|
if (comp.x == this.x && comp.y == this.y) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyTo(DFSNode node) {
|
||||||
|
node.child = child;
|
||||||
|
node.parent = parent;
|
||||||
|
node.x = x;
|
||||||
|
node.y = y;
|
||||||
|
node.goal = goal;
|
||||||
|
}
|
||||||
|
}
|
@ -1,21 +1,19 @@
|
|||||||
package ca.recrown.islandsurvivalcraft.pathfinding;
|
package ca.recrown.islandsurvivalcraft.pathfinding;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.PriorityQueue;
|
import java.util.PriorityQueue;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
|
||||||
import org.apache.commons.lang.NullArgumentException;
|
import org.apache.commons.lang.NullArgumentException;
|
||||||
|
|
||||||
public class DepthFirstSearch {
|
public class DepthFirstSearch {
|
||||||
private Queue<Node> queue;
|
private Queue<DFSNode> queue;
|
||||||
private CoordinateValidatable coordValidatable;
|
private CoordinateValidatable coordValidatable;
|
||||||
private Node startNode;
|
private DFSNode startNode;
|
||||||
private Node endNode;
|
private DFSNode endNode;
|
||||||
private HashSet<Node> checkedNodes;
|
private HashSet<DFSNode> checkedNodes;
|
||||||
private int maxNodesSearched = -1;
|
private int maxNodesSearched = -1;
|
||||||
private int foundX;
|
private DFSNode foundNode;
|
||||||
private int foundY;
|
|
||||||
|
|
||||||
public DepthFirstSearch() {
|
public DepthFirstSearch() {
|
||||||
checkedNodes = new HashSet<>();
|
checkedNodes = new HashSet<>();
|
||||||
@ -42,19 +40,15 @@ public class DepthFirstSearch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setStartPosition(int x, int y) {
|
public void setStartPosition(int x, int y) {
|
||||||
startNode = new Node(null, x, y);
|
startNode = new DFSNode(null, x, y, endNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDirectionPosition(int x, int y) {
|
public void setDirectionPosition(int x, int y) {
|
||||||
endNode = new Node(null, x, y);
|
endNode = new DFSNode(null, x, y, endNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getEndX() {
|
public DFSNode getFoundNode() {
|
||||||
return foundX;
|
return foundNode;
|
||||||
}
|
|
||||||
|
|
||||||
public int getEndY() {
|
|
||||||
return foundY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteTree() {
|
public void deleteTree() {
|
||||||
@ -63,50 +57,55 @@ public class DepthFirstSearch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean buildPathToEndNode() {
|
public boolean buildPathToEndNode() {
|
||||||
if (coordValidatable == null) throw new IllegalStateException("Need to set a validator.");
|
if (coordValidatable == null)
|
||||||
if (startNode == null) throw new IllegalStateException("Need to set the starting position.");
|
throw new IllegalStateException("Need to set a validator.");
|
||||||
|
if (startNode == null)
|
||||||
|
throw new IllegalStateException("Need to set the starting position.");
|
||||||
|
|
||||||
return findTarget(new CoordinateTargetValidatable() {
|
return findTarget(new CoordinateTargetValidatable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCoordinateTarget(int x, int y) {
|
public boolean isCoordinateTarget(int x, int y) {
|
||||||
return endNode.x == x && endNode.y == y;
|
return endNode.getX() == x && endNode.getY() == y;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the end node.
|
* Finds the end node. If an end node is set, it will try going in that
|
||||||
* If an end node is set, it will try going in that direction first.
|
* direction first. Will not set end node if one wasn't found, therefore,
|
||||||
* Will not set end node if one wasn't found,
|
* previous end node data is kept.
|
||||||
* therefore, previous end node data is kept.
|
*
|
||||||
* @param targetValidator
|
* @param targetValidator
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean findTarget(CoordinateTargetValidatable targetValidator) {
|
public boolean findTarget(CoordinateTargetValidatable targetValidator) {
|
||||||
if (coordValidatable == null) throw new IllegalStateException("Need to set a validator.");
|
if (coordValidatable == null)
|
||||||
if (targetValidator == null) throw new NullArgumentException("targetValidator");
|
throw new IllegalStateException("Need to set a validator.");
|
||||||
if (startNode == null) throw new IllegalStateException("Need to set the starting position.");
|
if (targetValidator == null)
|
||||||
|
throw new NullArgumentException("targetValidator");
|
||||||
|
if (startNode == null)
|
||||||
|
throw new IllegalStateException("Need to set the starting position.");
|
||||||
|
|
||||||
queue.clear();
|
queue.clear();
|
||||||
checkedNodes.clear();
|
checkedNodes.clear();
|
||||||
Node begin = startNode;
|
DFSNode begin = startNode;
|
||||||
queue.add(begin);
|
queue.add(begin);
|
||||||
while (!queue.isEmpty()) {
|
while (!queue.isEmpty()) {
|
||||||
Node n = queue.poll();
|
DFSNode n = queue.poll();
|
||||||
if (maxNodesSearched != -1 && checkedNodes.size() > maxNodesSearched) return false;
|
if (maxNodesSearched != -1 && checkedNodes.size() > maxNodesSearched)
|
||||||
if (checkedNodes.add(n) && coordValidatable.validate(n.x, n.y)) {
|
return false;
|
||||||
n.child[0] = new Node(n, n.x + 1, n.y);
|
if (checkedNodes.add(n) && coordValidatable.validate(n.getX(), n.getY())) {
|
||||||
n.child[1] = new Node(n, n.x - 1, n.y);
|
n.child[0] = new DFSNode(n, n.getX() + 1, n.getY(), endNode);
|
||||||
n.child[2] = new Node(n, n.x, n.y + 1);
|
n.child[1] = new DFSNode(n, n.getX() - 1, n.getY(), endNode);
|
||||||
n.child[3] = new Node(n, n.x, n.y - 1);
|
n.child[2] = new DFSNode(n, n.getX(), n.getY() + 1, endNode);
|
||||||
if (targetValidator.isCoordinateTarget(n.x, n.y)) {
|
n.child[3] = new DFSNode(n, n.getX(), n.getY() - 1, endNode);
|
||||||
foundX = n.x;
|
if (targetValidator.isCoordinateTarget(n.getX(), n.getY())) {
|
||||||
foundY = n.y;
|
foundNode = new DFSNode(n.getParent(), n.getX(), n.getY(), null);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < n.child.length; i++) {
|
for (int i = 0; i < n.child.length; i++) {
|
||||||
Node child = n.child[i];
|
DFSNode child = n.child[i];
|
||||||
queue.add(child);
|
queue.add(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,47 +116,4 @@ public class DepthFirstSearch {
|
|||||||
public int getSearchedCount() {
|
public int getSearchedCount() {
|
||||||
return checkedNodes.size();
|
return checkedNodes.size();
|
||||||
}
|
}
|
||||||
private class Node implements Comparable<Node> {
|
|
||||||
public Node[] child;
|
|
||||||
public Node parent;
|
|
||||||
public int x;
|
|
||||||
public int y;
|
|
||||||
|
|
||||||
public Node(Node parent, int x, int y) {
|
|
||||||
this.parent = parent;
|
|
||||||
child = new Node[4];
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(Node o) {
|
|
||||||
if (endNode == null) return 0;
|
|
||||||
return Math.round(distanceToGoal(endNode) - o.distanceToGoal(endNode));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public float distanceToGoal(Node goal) {
|
|
||||||
float distanceX = goal.x - this.x;
|
|
||||||
float distanceY = goal.y - this.y;
|
|
||||||
float distance = (float) Math.sqrt(distanceX * distanceX + distanceY * distanceY);
|
|
||||||
return distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (obj instanceof Node) {
|
|
||||||
Node comp = (Node) obj;
|
|
||||||
if (comp.x == this.x && comp.y == this.y) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -146,8 +146,8 @@ public class DepthFirstSearchTest {
|
|||||||
dfs.setStartPosition(3, 0);
|
dfs.setStartPosition(3, 0);
|
||||||
|
|
||||||
assertTrue(dfs.findTarget(validator));
|
assertTrue(dfs.findTarget(validator));
|
||||||
assertEquals(1, dfs.getEndX());
|
assertEquals(1, dfs.getFoundNode().getX());
|
||||||
assertEquals(2, dfs.getEndY());
|
assertEquals(2, dfs.getFoundNode().getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -158,8 +158,8 @@ public class DepthFirstSearchTest {
|
|||||||
dfs.setStartPosition(0, 0);
|
dfs.setStartPosition(0, 0);
|
||||||
|
|
||||||
assertTrue(dfs.findTarget(validator));
|
assertTrue(dfs.findTarget(validator));
|
||||||
assertEquals(0, dfs.getEndX());
|
assertEquals(0, dfs.getFoundNode().getX());
|
||||||
assertEquals(3, dfs.getEndY());
|
assertEquals(3, dfs.getFoundNode().getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -169,8 +169,8 @@ public class DepthFirstSearchTest {
|
|||||||
dfs.setStartPosition(3, 0);
|
dfs.setStartPosition(3, 0);
|
||||||
|
|
||||||
assertTrue(dfs.findTarget(validator));
|
assertTrue(dfs.findTarget(validator));
|
||||||
assertEquals(95, dfs.getEndX());
|
assertEquals(95, dfs.getFoundNode().getX());
|
||||||
assertEquals(49, dfs.getEndY());
|
assertEquals(49, dfs.getFoundNode().getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -199,8 +199,8 @@ public class DepthFirstSearchTest {
|
|||||||
dfs.setStartPosition(0, 0);
|
dfs.setStartPosition(0, 0);
|
||||||
|
|
||||||
assertTrue(dfs.findTarget(validator));
|
assertTrue(dfs.findTarget(validator));
|
||||||
assertEquals(26, dfs.getEndX());
|
assertEquals(26, dfs.getFoundNode().getX());
|
||||||
assertEquals(32, dfs.getEndY());
|
assertEquals(32, dfs.getFoundNode().getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -220,7 +220,7 @@ public class DepthFirstSearchTest {
|
|||||||
dfs.setDirectionPosition(42, 84);
|
dfs.setDirectionPosition(42, 84);
|
||||||
|
|
||||||
assertTrue(dfs.findTarget(validator));
|
assertTrue(dfs.findTarget(validator));
|
||||||
assertEquals(95, dfs.getEndX());
|
assertEquals(95, dfs.getFoundNode().getX());
|
||||||
assertEquals(49, dfs.getEndY());
|
assertEquals(49, dfs.getFoundNode().getY());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user