-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathAStarAlgorithm.java
157 lines (141 loc) · 4.46 KB
/
AStarAlgorithm.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
This is an implementation of the popular
A* path finding algorithm. This algorithm takes
as input a grid-shaped graph, a starting point
and a destination. The algorithm would then
find the shortest path between the starting point
and the destination.
(https://en.wikipedia.org/wiki/A*_search_algorithm)
Let w be the width of the grid-shaped graph and
h be the height of the graph.
Time complexity: O(w * h * log2(w * h))
Space complexity: O(w*h)
*/
import java.util.PriorityQueue;
import java.util.Arrays;
public class AStarAlgorithm {
// A class representing every node in the graph
class Node {
int rowIdx, colIdx, value;
int G, H, F;
Node predecessor;
public Node(int rowIdx, int colIdx, int value) {
this.rowIdx = rowIdx;
this.colIdx = colIdx;
this.value = value;
G = Integer.MAX_VALUE;
H = 0;
F = Integer.MAX_VALUE;
predecessor = null;
}
public boolean equals(Object other) {
Node otherNode = (Node) other;
return (rowIdx == otherNode.rowIdx) && (colIdx == otherNode.colIdx);
}
public String toString() {
return "RowIdx: " + rowIdx + ", colIdx: " + colIdx + "\n"
+ "G: " + G + ", H: " + H + ", F: " + F;
}
}
public int[][] aStarAlgorithm(int startRow, int startCol, int endRow, int endCol, int[][] graph) {
int ROWS = graph.length, COLS = graph[0].length;
Node[][] nodesGraph = new Node[ROWS][COLS];
for (int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLS; col++) {
int H = getManhattanDistance(row, col, endRow, endCol);
nodesGraph[row][col] = new Node(row, col, graph[row][col]);
nodesGraph[row][col].H = H;
}
}
PriorityQueue<Node> pq = new PriorityQueue<>((node1, node2) -> {
if (node1.F != node2.F) {
return node1.F - node2.F;
} else {
return node1.G - node2.G;
}
});
Node startNode = nodesGraph[startRow][startCol];
startNode.G = 0;
startNode.F = startNode.H;
pq.add(startNode);
Node currentNode = null, endNode = nodesGraph[endRow][endCol];
while (!pq.isEmpty()) {
currentNode = pq.remove();
// System.out.println("CurrentNode:\n" + currentNode);
if (currentNode.equals(endNode)) {
break;
}
updateNeighbors(currentNode, nodesGraph, pq);
}
if (!currentNode.equals(endNode)) {
return new int[][] {};
} else {
int[][] path = constructPath(endNode);
return path;
}
}
// Get Manhattan distance to destination
private int getManhattanDistance(int startRow, int startCol, int endRow, int endCol) {
return Math.abs(endRow - startRow) + Math.abs(endCol - startCol);
}
// Update weights of neighboring nodes
private void updateNeighbors(Node currentNode, Node[][] nodesGraph, PriorityQueue<Node> pq) {
int[][] directions = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } };
int ROWS = nodesGraph.length;
int COLS = nodesGraph[0].length;
int currentNodeRowIdx = currentNode.rowIdx;
int currentNodeColIdx = currentNode.colIdx;
int nextNodeRowIdx, nextNodeColIdx;
int[] direction;
Node nextNode;
for (int i = 0; i < directions.length; i++) {
direction = directions[i];
nextNodeRowIdx = currentNodeRowIdx + direction[0];
nextNodeColIdx = currentNodeColIdx + direction[1];
if (nextNodeRowIdx < 0 || nextNodeRowIdx >= ROWS || nextNodeColIdx < 0 || nextNodeColIdx >= COLS) {
continue;
}
nextNode = nodesGraph[nextNodeRowIdx][nextNodeColIdx];
if (nextNode.value == 1) {
continue;
}
if (currentNode.G + 1 < nextNode.G) {
nextNode.G = currentNode.G + 1;
nextNode.F = nextNode.G + nextNode.H;
nextNode.predecessor = currentNode;
pq.remove(nextNode);
pq.add(nextNode);
}
}
}
// Construct the shortest path starting from destination
private int[][] constructPath(Node endNode) {
int[][] path = new int[endNode.F + 1][2];
int idx = path.length - 1;
Node tempNode = endNode;
do {
path[idx][0] = tempNode.rowIdx;
path[idx][1] = tempNode.colIdx;
tempNode = tempNode.predecessor;
idx--;
} while (tempNode != null);
return path;
}
public static void main(String[] args) {
AStarAlgorithm application = new AStarAlgorithm();
int startRow = 0, startCol = 1, endRow = 4, endCol = 3;
int[][] graph = {
{ 0, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0 },
{ 0, 0, 0, 0, 0 },
{ 1, 0, 1, 1, 1 },
{ 0, 0, 0, 0, 0 }
};
int[][] path = application.aStarAlgorithm(startRow, startCol, endRow, endCol, graph);
for (int[] node : path) {
System.out.print(Arrays.toString(node) + " ");
}
// Output:
// [0, 1] [0, 0] [1, 0] [2, 0] [2, 1] [3, 1] [4, 1] [4, 2] [4, 3]
}
}