Separated node class from DFS class.

This commit is contained in:
Harrison Deng 2020-04-23 23:07:49 -05:00
parent de3b3a614a
commit be19db1f9b
3 changed files with 120 additions and 92 deletions

View File

@ -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;
}
}

View File

@ -1,21 +1,19 @@
package ca.recrown.islandsurvivalcraft.pathfinding;
import java.util.HashSet;
import java.util.Objects;
import java.util.PriorityQueue;
import java.util.Queue;
import org.apache.commons.lang.NullArgumentException;
public class DepthFirstSearch {
private Queue<Node> queue;
private Queue<DFSNode> queue;
private CoordinateValidatable coordValidatable;
private Node startNode;
private Node endNode;
private HashSet<Node> checkedNodes;
private DFSNode startNode;
private DFSNode endNode;
private HashSet<DFSNode> checkedNodes;
private int maxNodesSearched = -1;
private int foundX;
private int foundY;
private DFSNode foundNode;
public DepthFirstSearch() {
checkedNodes = new HashSet<>();
@ -39,22 +37,18 @@ public class DepthFirstSearch {
public void setValidatable(CoordinateValidatable validatable) {
this.coordValidatable = validatable;
}
}
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) {
endNode = new Node(null, x, y);
endNode = new DFSNode(null, x, y, endNode);
}
public int getEndX() {
return foundX;
}
public int getEndY() {
return foundY;
public DFSNode getFoundNode() {
return foundNode;
}
public void deleteTree() {
@ -63,50 +57,55 @@ public class DepthFirstSearch {
}
public boolean buildPathToEndNode() {
if (coordValidatable == null) throw new IllegalStateException("Need to set a validator.");
if (startNode == null) throw new IllegalStateException("Need to set the starting position.");
if (coordValidatable == null)
throw new IllegalStateException("Need to set a validator.");
if (startNode == null)
throw new IllegalStateException("Need to set the starting position.");
return findTarget(new CoordinateTargetValidatable() {
@Override
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.
* If an end node is set, it will try going in that direction first.
* Will not set end node if one wasn't found,
* therefore, previous end node data is kept.
* Finds the end node. If an end node is set, it will try going in that
* direction first. Will not set end node if one wasn't found, therefore,
* previous end node data is kept.
*
* @param targetValidator
* @return
*/
public boolean findTarget(CoordinateTargetValidatable targetValidator) {
if (coordValidatable == null) throw new IllegalStateException("Need to set a validator.");
if (targetValidator == null) throw new NullArgumentException("targetValidator");
if (startNode == null) throw new IllegalStateException("Need to set the starting position.");
if (coordValidatable == null)
throw new IllegalStateException("Need to set a validator.");
if (targetValidator == null)
throw new NullArgumentException("targetValidator");
if (startNode == null)
throw new IllegalStateException("Need to set the starting position.");
queue.clear();
checkedNodes.clear();
Node begin = startNode;
DFSNode begin = startNode;
queue.add(begin);
while (!queue.isEmpty()) {
Node n = queue.poll();
if (maxNodesSearched != -1 && checkedNodes.size() > maxNodesSearched) return false;
if (checkedNodes.add(n) && coordValidatable.validate(n.x, n.y)) {
n.child[0] = new Node(n, n.x + 1, n.y);
n.child[1] = new Node(n, n.x - 1, n.y);
n.child[2] = new Node(n, n.x, n.y + 1);
n.child[3] = new Node(n, n.x, n.y - 1);
if (targetValidator.isCoordinateTarget(n.x, n.y)) {
foundX = n.x;
foundY = n.y;
DFSNode n = queue.poll();
if (maxNodesSearched != -1 && checkedNodes.size() > maxNodesSearched)
return false;
if (checkedNodes.add(n) && coordValidatable.validate(n.getX(), n.getY())) {
n.child[0] = new DFSNode(n, n.getX() + 1, n.getY(), endNode);
n.child[1] = new DFSNode(n, n.getX() - 1, n.getY(), endNode);
n.child[2] = new DFSNode(n, n.getX(), n.getY() + 1, endNode);
n.child[3] = new DFSNode(n, n.getX(), n.getY() - 1, endNode);
if (targetValidator.isCoordinateTarget(n.getX(), n.getY())) {
foundNode = new DFSNode(n.getParent(), n.getX(), n.getY(), null);
return true;
}
for (int i = 0; i < n.child.length; i++) {
Node child = n.child[i];
DFSNode child = n.child[i];
queue.add(child);
}
}
@ -117,47 +116,4 @@ public class DepthFirstSearch {
public int getSearchedCount() {
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);
}
}
}

View File

@ -146,8 +146,8 @@ public class DepthFirstSearchTest {
dfs.setStartPosition(3, 0);
assertTrue(dfs.findTarget(validator));
assertEquals(1, dfs.getEndX());
assertEquals(2, dfs.getEndY());
assertEquals(1, dfs.getFoundNode().getX());
assertEquals(2, dfs.getFoundNode().getY());
}
@Test
@ -158,8 +158,8 @@ public class DepthFirstSearchTest {
dfs.setStartPosition(0, 0);
assertTrue(dfs.findTarget(validator));
assertEquals(0, dfs.getEndX());
assertEquals(3, dfs.getEndY());
assertEquals(0, dfs.getFoundNode().getX());
assertEquals(3, dfs.getFoundNode().getY());
}
@Test
@ -169,8 +169,8 @@ public class DepthFirstSearchTest {
dfs.setStartPosition(3, 0);
assertTrue(dfs.findTarget(validator));
assertEquals(95, dfs.getEndX());
assertEquals(49, dfs.getEndY());
assertEquals(95, dfs.getFoundNode().getX());
assertEquals(49, dfs.getFoundNode().getY());
}
@Test
@ -199,8 +199,8 @@ public class DepthFirstSearchTest {
dfs.setStartPosition(0, 0);
assertTrue(dfs.findTarget(validator));
assertEquals(26, dfs.getEndX());
assertEquals(32, dfs.getEndY());
assertEquals(26, dfs.getFoundNode().getX());
assertEquals(32, dfs.getFoundNode().getY());
}
@Test
@ -220,7 +220,7 @@ public class DepthFirstSearchTest {
dfs.setDirectionPosition(42, 84);
assertTrue(dfs.findTarget(validator));
assertEquals(95, dfs.getEndX());
assertEquals(49, dfs.getEndY());
assertEquals(95, dfs.getFoundNode().getX());
assertEquals(49, dfs.getFoundNode().getY());
}
}