A* pathfinding with Multiple Agents - java

I've currently been learning and programming pathfinding(in Java) using the A* algorithm. A problem I've run into is when multiple entities are trying to pathfind, they both alter the previousNode(the Node that the Node being calculated on came from), messing up the algorithm, and eventually Node A will point to Node B and Node B will point to Node A.
How can I change the algorithm to either
Not use this previousNode system that is littered throughout all of the A * algorithms(that I have seen, that is)
Alter this system to be used concurrently
I am trying to avoid having one entity finish pathfinding, then telling the next entity to pathfinding, and so on. Like doing a wait() - notify() pair in Java.
public Path findPath(int startX, int startY, int goalX, int goalY) {
//Path is basically just a class that contains an ArrayList,
//containing Nodes, which contains the steps to reach a goal.
if(map.getNode(goalX, goalY).isObstacle()) {
return null;
}
map.getNode(startX, startY).setDistanceFromStart(0);
closedList.clear();
openList.clear(); //A List with added getFirst() - gets the first Node in the list
openList.add(map.getNode(startX, startY));
while(openList.size() != 0) {
//Node contains a List that has all of the Nodes around this node, a
//F, G, and H value, and its row(y) and column(x)
Node current = openList.getFirst();
if(current.getX() == goalX && current.getY() == goalY) {
return backtrackPath(current);
}
openList.remove(current);
closedList.add(current);
for(Node neighbor : current.getNeighborList()) {
boolean neighborIsBetter;
//If I've already searched this neighbor/node, don't check it
if(closedList.contains(neighbor)) {
continue;
}
if(!neighbor.isObstacle()) {
float neighborDistanceFromStart = (current.getDistanceFromStart() + map.getDistanceBetween(current, neighbor));
if(!openList.contains(neighbor)) {
openList.add(neighbor);
neighborIsBetter = true;
} else if(neighborDistanceFromStart < current.getDistanceFromStart()) {
neighborIsBetter = true;
} else {
neighborIsBetter = false;
}
if(neighborIsBetter) {
neighbor.setPreviousNode(current);
neighbor.setDistanceFromStart(neighborDistanceFromStart);
neighbor.setHeuristic(getManhattanDistance(neighbor.getX(), neighbor.getY(), goalX, goalY));
}
}
}
}
return null;
}
public Path backtrackPath(Node fromNode) {
Path path = new Path();
while(fromNode.getPreviousNode() != null) {
path.prependWaypoint(fromNode);
fromNode = fromNode.getPreviousNode();
}
return path;
}
I am specifically talking about(within findPath())
if(neighborIsBetter) {
neighbor.setPreviousNode(current); //previousNode is a value in the Node class that points to the Node that it came from
neighbor.setDistanceFromStart(neighborDistanceFromStart);
neighbor.setHeuristic(getManhattanDistance(neighbor.getX(), neighbor.getY(), goalX, goalY));
}

I don't think you can do A* (or any pathfinding algorithm, for that matter) without somehow storing a backpointer for a given path. So that leaves you with two options
Require each agent (Thread, I assume) to create their own copy of the graph to work on. That way each A* call going on won't interfere with one another, as they are working with the fields of the same node on different graphs.
Change your A* code to be able to handle multiple concurrent calls.
Option 1 is fairly self-explanatory and probably the better option. If this is just for you, you should probably just go with that one (instead of trying to make A* fully concurrent on a single graph). This would entail adding map as an input parameter (and requiring that concurrent calls should use a different map instance, either throwing an exception or having unspecified behavior if that doesn't occur). Additionally, you should instantiate closedList and openList as new data structures in each call, rather than share a list.
If that's not to your liking - you really want to fully encapsulate the mutli-call usage into the method itself, I think the simplest way you could do this is require an additional parameter of an id - some unique string that is guaranteed not to be the same as the id of another concurrent call. So the header of A* now looks like:
public Path findPath(final String ID, int startX, int startY, int goalX, int goalY) {
From there, change all of the implementations of each of the settable pathfinding fields in Node to a HashMap with the id as the key. From your code, I'm going to guess that your Node class looks something like this:
public class Node{
//Fields used by the A* call - no problem here
private boolean obstacle;
//Fields *edited* by the A* call
private float distanceFromStart;
private Node previous;
private int heuristic;
//other fields and stuff
public boolean isObstacle(){
return obstacle;
}
public float getDistanceFromStart(){
return distanceFromStart;
}
public void setDistanceFromStart(float f){
distanceFromStart = f;
}
public Node getPrevious(){
return previous;
}
public void setPrevious(Node p){
previous = p;
}
public int getHeuristic(){
return heuristic;
}
public void setHeuristic(int h){
heuristic = h;
}
}
We can edit the edited fields to be able to store many values, by id, as such:
public class Node{
//Fields used by the A* call - no problem here
private boolean obstacle;
//Fields *edited* by the A* call
private HashMap<String,Float> distanceFromStart;
private HashMap<String,Node> previous;
private HashMap<String,Integer> heuristic;
//other fields and stuff
public boolean isObstacle(){
return obstacle;
}
public float getDistanceFromStart(String id){
return distanceFromStart.get(id);
}
public void setDistanceFromStart(String id, float f){
distanceFromStart.put(id, f);
}
public Node getPrevious(String id){
return previous.get(id);
}
public void setPrevious(String id, Node p){
previous.put(id,p);
}
public int getHeuristic(String id){
return heuristic.get(id);
}
public void setHeuristic(String id,int h){
heuristic.put(id,h);
}
}
From there, simply edit your A* method to give the id from the method call to the getters and setters when called for. So long as two concurrent method calls don't have the same id value, they won't interfere with each other. Three things to keep in mind for this to work correctly:
Make sure that every editable field gets this treatment. It won't work if you forget about one. Non-editable fields (fields that don't get altered as a byproduct of running A*) can stay singular.
If you use the the above, you should probably add to the cleanup stage a step of removing all the information for the given ID from the graph, or the nodes' hashmaps will grow larger with each call.
Either way, you still should make openList and closedList new local instances, no matter what concurrent approach you pick. There's nothing to gain from making openList and closedList shared instances, and only bugs can come of it.
List<Node> closedList = new LinkedList<Node>();
List<Node> openList = new LinkedList<Node>();
//Don't have to clear them anymore - they're new lists
openList.add(map.getNode(startX, startY));

Related

Compilation error while implementing the Depth first search Recursively

I am new to using recursion for my methods. I tend to steer away from them for quite a few reasons. However, for a project, it seems to easier to have a recursive method instead of a looping one since I am trying to do Depth First Traversal for a Graph.
Since I am not too well versed in recursion, I don't understand why I am getting the following error.
This method must return a result of type LinkedList.Node
The code I have currently is:
public Node DFSTime(Node node){
if(node == null){
System.out.println("No path found");
return null;
}
else if(node.element.equals(destinationAirport)){
return node;
}
else{
stack.push(node);
DFSTime(node.nextNode);
}
}
It is unfinished code since I still need to implement some logic, however, I don't understand how to eliminate the error. Is there something very basic that I am missing?
The reason of the compilation error is pretty trivial. The compiler clearly tells that didn't provide the result to return for all possible cases.
The more important is that your current approach is not correct.
it seems to easier to have a recursive method instead of a looping one since I am trying to do Depth First Traversal for a Graph
There are crucial things to consider:
Field nextNode is very suspicious. If each Node holds a reference pointing to a single node only, in fact the data structure you've created by definition isn't a Graph, but a Singly linked list. And doesn't make sense to implement DFS for a list. Every node should point to a collection of nodes, no to a single node.
You have to distinguish somehow between unvisited nodes and nodes that are already visited. Or else you might and up with infinite recursion. For that, you can define a boolean field isVisited inside the Node, or place every visited node into a HashSet.
Since you've chosen to create a recursive implementation of DFS, you don't need to create a stack. It's required only for iterative implementation.
Don't overuse global variables. I guess you might want to be able to check whether it is possible to reach different airports of destination without reinstantiating the graph.
Use getters and setters instead of accessing fields directly. It's a preferred practice in Java.
Your method might look like this (it's not necessary that element should be of type String it's just an illustration of the overall idea):
public Node DFSTime(Node node, String destinationAirport){
if(node == null || node.isVisited()) {
return null;
}
if (node.getElement().equals(destinationAirport)) {
System.out.println("The destination airport was found");
return node;
}
node.setVisited(true);
for (Node neighbour: node.getNeighbours()) {
Node result = DFSTime(neighbour, destinationAirport);
if (result != null) return result;
}
return null;
}
And the node might look like this:
public class Node {
private String element;
private List<Node> neighbours;
private boolean isVisited;
public Node(String element, List<Node> neighbours) {
this.element = element;
this.neighbours = neighbours;
}
public void setVisited(boolean visited) {
isVisited = visited;
}
public boolean isVisited() {
return isVisited;
}
public void addNeighbours(Node neighbour) {
neighbours.add(neighbour);
}
public String getElement() {
return element;
}
public List<Node> getNeighbours() {
return neighbours;
}
}
You should have a default return statement at the end of the function after the closing of the else.
In methods conditional blocks (if-else), you need to make sure you are returning appropriate Type from all conditional statements, so that there is no compile-time error. In your case, else block is recursively calling DFSTime(..) without returning anything.
You might want to return reference which gets called via recursive call, something like below:
public Node DFSTime(Node node){
if(node == null){
System.out.println("No path found");
return null;
}
else if(node.element.equals(destinationAirport)){
return node;
}
else{
stack.push(node);
Node node = DFSTime(node.nextNode);
return node;
}
}

Recursive method using a graph changes it's state on all levels

I try to solve a graph problem with a recursive method returning one correct solution but I wonder if it is possible to do so, because changing the state of a graph in one recursion level will change it on other levels since they refer to the same object. Is there any way to solve it?
Here are my code samples:
1) Nodes - here you can see that Nodes are binded creating edges
public class Node{
private int visited;
private int label;
private int order;
private int degree;
private ArrayList <Node> neighbours;
...
}
2) Graph
public class Graph {
private ArrayList <Square> graph;
private int graphSize;
private int numOfVertices;
...
}
3) And the sketch of a method:
public boolean backTracking(int label, int moves, Graph graph){
// something here
if(current.getVisited() != 1){
// current is a next neighbor of a vertex
if(backTracking(current.getLabel(),completedMoves, graph))
return true;
}
return false;
I'm not sure what your "graph problem" is, but if you need to track additional information per level then use a stack (push when going down a level, pop when going up).
If you need to store additional information per node then you can either place it inside Node class, or hold it in a Map. You can also clean entries in the map while backtracking.

Doubly Linked List - InsertAfter - Java

First of all, let me say that this is an assignment for a class where we have been tasked with writing our own doubly linked list class and cannot use anything from Java SE (e.g. the LinkedList class). We have to make our code work with a provided driver class. I am not asking for anyone to do the homework for me, I am simply asking for some kind of clarification as to how exactly to implement these methods, since I have struggled with this on and off over the past few days.
We have been provided with an Interface, textEditor.java that provides methods which will be utilized by the driver class, driver.java. These methods include the typical insert, et. al. but my concern is the insertAfter(int lineNum, E line) method and its counterpart, insertBefore. I have not been able to get these to work because comparing int to E, despite my best efforts and reading through several Java texts for guidance.
Below is the code in the DoublyLinkedList.java file, as provided at onset. I would like to know how I can implement some kind of indexing and checking in order to be able to make an insertion following or preceding the line entered by the user/driver class.
public class DoublyLinkedList<E> implements TextEditor<E>
{
Node<E> head, tail;
public DoublyLinkedList()
{
head = null;
tail = null;
}
public boolean isEmpty()
{
return (head == null);
}
public void insert(E line)
{
}
public void insertAfter(int lineNum, E line)
{
}
public void insertBefore(int lineNum, E line) throws IndexOutOfBoundsException
{
}
public void deleteByPosition(int position)
{
}
public void printNode(int position)
{
}
public void printAllNodes()
{
}
}
I have not been able to do this, and having tried several things over several hours, I have given up hope of being able to do it. If I don't find help here or still can't get these methods to work, I will be speaking with my instructor. It may simply be that I am overthinking the problem, and I hope that that is the case.
I'm assuming that your Node class looks like this :
class Node<E> {
private Node next;
private E value;
[...]
}
You can add an attribute in your DoublyLinkedList class, in which you keep the number of Node that your list contains.
Then, if you want the Nth element of your list, you can do this :
private Node getNthElement(int n) {
Node node = head;
for (int i=0; i<n; i++) {
node = node.next;
}
return node;
}
These methods should also check if there are enough elements in the list, etc. But this is the main idea.

Java: OOP Encapsulation vs No encapsulation?

Hello I did a Binary Tree program for my Java Class and I got lots of points off for "No OOP Encapsulation" .. well I thought encapsulation was just using classes? What should I done different to enforce OOP Encapsulation? Below was my working code . Thanks for any input or advice
public class BinTree {
private Node root;
private static class Node{
Node left;
Node right;
int value;
Node(int newValue){
left = null;
right = null;
value = newValue;
}
}
BinTree(){
root = null;
}
public void insertNode(int value){
root = insertNode(root, value);
}
private Node insertNode(Node node, int value){
if (node==null){
node = new Node(value);
}
else{
if (value <= node.value){
node.left = insertNode(node.left, value);
}
else {
node.right = insertNode(node.right, value);
}
}
return(node);
}
public void treeWalk(){
treeWalk(root);
}
private void treeWalk(Node node){
if(node != null){
treeWalk(node.left);
System.out.println(node.value);
treeWalk(node.right);
}
}
}
#Marco13 is probably correct, though the only way to be sure what the marker meant is to actually ask him or her.
For what it is worth, I think your marker is incorrect here. Clearly, the outer class is properly encapsulated, and the nested class is private which means it is not visible outside of the outer class encapsulation boundary.
It is accepted Java practice that private inner classes do not necessarily need getters and setters for their fields.
Encapsulation is not a religion. It is used in Java for a purpose; i.e. to prevent implementation details from leaking. And declaring getters and setters also facilitates subclassing. But when the supposed purposes are moot (as they are here) use of encapsulation is not necessary.
If you want an apposite example, take a look at the Java source code for the standard LinkedList class:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/LinkedList.java#LinkedList.Entry
Note that the Entry class does not have getters or setters ... and its fields are not declared as final either.
When this was an assignment, the term "No OOP Encapsulation" probably refers to the fact that you did not use setters and getters for the fields of the Node class. So you should make left, right and value private, and offer methods for reading/writing the values of these fields accordingly.
(Note that "encapsulation" in this case also means that you do not have to create a method for modifying the value: This is only set in the constructor, and may not be changed later. So in fact, the value may (and should) even be private final.)
Wikipedia writes:
Under this definition, encapsulation means that the internal representation of an object is generally hidden from view outside of the object's definition. Typically, only the object's own methods can directly inspect or manipulate its fields.
In your case, the fields of the Node class are accessed from methods of class BinTree. Therefore, the Node is not encapsulated from the BinTree.
Your teacher might have wanted you to move the methods the access the node's state into the node class:
class BinTree {
private Node root;
private static class Node {
Node left;
Node right;
int value;
Node(int newValue) {
left = null;
right = null;
value = newValue;
}
void insert(int newValue) {
if (newValue <= value) {
if (left == null) {
left = new Node(newValue);
} else {
left.insert(newValue);
}
} else {
if (right == null) {
right = new Node(newValue);
} else {
right.insert(newValue);
}
}
}
void walk() {
if (left != null) {
left.walk();
}
System.out.println(value);
if (right != null) {
right.walk();
}
}
}
BinTree() {
root = null;
}
public void insertNode(int value) {
if (root == null) {
root = new Node(value);
} else {
root.insert(value);
}
}
public void treeWalk() {
if (root != null) {
root.walk();
}
}
}
Now, whether this is better design is somewhat questionable. Sure, the object oriented purist rejoices at the shorter parameter lists, and that all methods only access the fields of this, but a pragmatic programmer will find the duplicated null checks just as bad, or possibly worse than, the lack of strict encapsulation in your approach.
Personally, I consider encapsulation (or more generally information hiding) an indispensable technique for writing all but the most trivial of programs. But I disagree that the proper size of a capsule need always be a single object. In your original code, the capsule surrounds the entire tree, and that's good enough for me.
The idea of OOP is to make code more reusable and more object like, when you are creating an object you want to be able to use all the functions of that object, this also includes accessing data. The problem comes down to creating more than 1 type of object and accidentally overriding the value of data. This is why you encapsulate.
here is an example of encapsulation
private int health;
public void getHealth(){
return health;
}
public int setHealth(int h){
this.health = h;
}
you ask why bother having 2 methods for this property? when you instantiate the class, you don't want to directly access its property but do it indirectly to avoid overriding its default value. You set the property to private so that no class can call it directly.

Edge of undirected graph in Java

Suppose I am writing a Java class to represent an edge of undirected graph. This class Edge contains two vertices to and from.
class Edge<Vertex> {
private final Vertex to, from
public Edge(Vertex to, Vertex from) {
this.to = to;
this.from = from;
}
... // getters, equals, hashCode ...
}
Obviously e1 = new Edge(v1, v2) and e2 = new Edge(v2, v1) are actually the same in an undirected graph. Does it make sense? How would you implement class Edge to meet that requirement?
Perform a sort on the vertices in the constructor based on some unique identifier. This way they are stored consistently regardless of order.
I find this preferable to noMAD's solution because all code interacting with these objects will treat them identically, not just your implementation of equals.
Also, calling your class members to and from is confusing because it sounds like a directed graph. I would rename these to something more generic like vertex1 and vertex2.
public Edge(Vertex x, Vertex y) {
if (vertex2.getId() > vertex1.getId()) {
this.vertex1 = x;
this.vertex2 = y;
} else {
this.vertex1 = y;
this.vertex2 = x;
}
}
I actually wouldn't have this logic in my Edge class but rather some sort of over-seeing class such as a Graph class. The reason for this is because an Edge is just an object with 2 vertices. It doesn't know anything about the rest of the edges in the graph.
So, to expand on #noMad's answer, I would actually put his checkIfSameEdge method in my Graph class:
public class Graph {
private List<Edge> edges;
....
public void addEdge(Edge e) {
for (Edge edge : edges) {
if (isSameEdge(edge, e) {
return; // Edge already in Graph, nothing to do
}
edges.add(e);
}
private boolean isSameEdge(Edge edge1, Edge edge2) {
return ((edge1.to.equals(edge2.to) && edge1.from.equals(edge2.from))
|| (edge1.to.equals(edge2.from) && edge1.from.equals(edge2.to)))
}
}
BTW: I would rename to and from to vertex1 and vertex2 because it is an undirected graph and to and from indicate direction, but that's just my opion.
Well, of the top of my head, the naivest method would be:
protected boolean checkIfSameEdge(Vertex to, Vertex from) {
if(to.equals(this.from) && from.equals(this.to) || to.equals(this.to) && from.equals(this.from)) {
return true;
return false;
}
Obviously you would have to override equals and hashcode
Presumably the nodes contain some sort of scalar values - sort the parameters based on these values (using the compareTo method) and use a factory to create a new instance or return an existing instance.

Categories

Resources