Skip to content

Commit a7dec2e

Browse files
authored
Merge pull request knaxus#101 from TheSTL/master
--update : path change of A* algo
2 parents 5fc4d9d + d0aaeac commit a7dec2e

File tree

2 files changed

+217
-3
lines changed

2 files changed

+217
-3
lines changed

README.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,9 @@ Collection of interview questions with Unit Tests. Problems includes Data Struct
8484
### Algorithms
8585

8686
- [LRU Cache](src/_Algorithms_/lru-cache)
87+
- Path Finders
88+
- [A*](src/_Algorithms_/path-finder/a-star)
8789

88-
### Path Finder
89-
90-
- [A\*](src/PathFinder/AStart)
9190

9291
### Classics
9392

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
/**
2+
* h is calculate by Euclidean Distance.
3+
* Complexity can be imporved by using Min-heap.
4+
* Worse case time complexity is O(E), where E is the number of edges in the graph.
5+
* Read more: [http://theory.stanford.edu/~amitp/GameProgramming/AStarComparison.html]
6+
*/
7+
function AStar(s, e, row, col, inputGrid) {
8+
const Row = row;
9+
const Col = col;
10+
const start = s;
11+
const end = e;
12+
13+
function cell() {
14+
this.cellValue = null;
15+
this.parent_i = -1;
16+
this.parent_j = -1;
17+
this.h = Number.MAX_SAFE_INTEGER;
18+
this.g = Number.MAX_SAFE_INTEGER;
19+
this.f = Number.MAX_SAFE_INTEGER;
20+
}
21+
22+
function pair(i, j, f) {
23+
this.i = i;
24+
this.j = j;
25+
this.f = f;
26+
}
27+
28+
const grid = [];
29+
30+
for (let i = 0; i < Row; i += 1) {
31+
grid[i] = [];
32+
for (let j = 0; j < Col; j += 1) {
33+
grid[i][j] = new cell();
34+
grid[i][j].cellValue = inputGrid[i][j];
35+
}
36+
}
37+
38+
39+
const isValid = (i, j) => i >= 0 && j >= 0 && i < Row && j < Col;
40+
41+
const isDestination = (i, j) => end.i === i && end.j === j;
42+
43+
const isBlocked = (i, j) => grid[i][j].cellValue === 0;
44+
45+
const euclideanDistance = (i, j) => Math.abs(i - end.i) * Math.abs(i - end.i)
46+
+ Math.abs(j - end.j) * Math.abs(j - end.j);
47+
48+
const trace = () => {
49+
const endRow = end.i;
50+
const endCol = end.j;
51+
const startRow = start.i;
52+
const startCol = start.j;
53+
54+
let i = endRow;
55+
let j = endCol;
56+
const path = [];
57+
58+
while (!(i === startRow && j === startCol)) {
59+
path.push([i, j]);
60+
61+
const nextI = grid[i][j].parent_i;
62+
const nextJ = grid[i][j].parent_j;
63+
i = nextI;
64+
j = nextJ;
65+
}
66+
path.push([i, j]);
67+
68+
for (let i = 0; i < path.length; i += 1) {
69+
console.log(path[i]);
70+
}
71+
};
72+
73+
const neighbourExplorer = (i, j, parentI, parentJ, openList, openListMap,
74+
closedListMap, distanceFromParent) => {
75+
if (!isValid(i, j)) {
76+
return false;
77+
}
78+
79+
if (isBlocked(i, j)) {
80+
return false;
81+
}
82+
83+
if (isDestination(i, j)) {
84+
grid[i][j].parent_i = parentI;
85+
grid[i][j].parent_j = parentJ;
86+
trace();
87+
return true;
88+
}
89+
90+
91+
const g = grid[parentI][parentJ].g + distanceFromParent;
92+
const h = euclideanDistance(i, j);
93+
const f = g + h;
94+
95+
if ((openListMap[[i, j]] && openListMap[[i, j]] > f)
96+
|| (closedListMap[[i, j]] && closedListMap[[i, j]] > f)
97+
|| (!closedListMap[[i, j]] && !openListMap[[i, j]])) {
98+
openListMap[[i, j]] = f;
99+
grid[i][j].parent_i = parentI;
100+
grid[i][j].parent_j = parentJ;
101+
grid[i][j].g = g;
102+
grid[i][j].h = h;
103+
grid[i][j].f = g + h;
104+
105+
const item = new pair(i, j, f);
106+
// can be improved by using Min-Heap DataStructure
107+
if (!openList.length) {
108+
openList.push(item);
109+
}
110+
let k = 0;
111+
let temp = item;
112+
for (; k < openList.length; k += 1) {
113+
if (openList[k].f > item.f) {
114+
[temp, openList[k]] = [openList[k], temp];
115+
}
116+
}
117+
openList[k] = temp;
118+
}
119+
return false;
120+
};
121+
122+
const search = () => {
123+
if (!isValid(start.i, start.j) || !isValid(end.i, end.j)) {
124+
return false;
125+
}
126+
127+
let i = start.i;
128+
let j = start.j;
129+
const openList = [];
130+
const openListMap = new Map();
131+
const closedListMap = new Map();
132+
let foundDest = false;
133+
134+
// Initialize start point
135+
grid[i][j].h = 0;
136+
grid[i][j].g = 0;
137+
grid[i][j].f = 0;
138+
139+
openList.push(new pair(i, j, 0.0));
140+
141+
openListMap[[i, j]] = 0;
142+
143+
while (openList.length > 0) {
144+
const currentCell = openList.shift();
145+
i = currentCell.i;
146+
j = currentCell.j;
147+
const currentF = currentCell.f;
148+
closedListMap[[i, j]] = currentF;
149+
const parentI = i;
150+
const parentJ = j;
151+
152+
foundDest = neighbourExplorer(i - 1, j, parentI, parentJ, openList, openListMap, closedListMap, 1); // for North
153+
if (foundDest) { break; }
154+
foundDest = neighbourExplorer(i, j - 1, parentI, parentJ, openList, openListMap, closedListMap, 1); // for West
155+
if (foundDest) { break; }
156+
foundDest = neighbourExplorer(i + 1, j, parentI, parentJ, openList, openListMap, closedListMap, 1); // for South
157+
if (foundDest) { break; }
158+
foundDest = neighbourExplorer(i, j + 1, parentI, parentJ, openList, openListMap, closedListMap, 1); // for East
159+
if (foundDest) { break; }
160+
foundDest = neighbourExplorer(i - 1, j - 1, parentI, parentJ, openList, openListMap, closedListMap, 1); // for N.W
161+
if (foundDest) { break; }
162+
foundDest = neighbourExplorer(i - 1, j + 1, parentI, parentJ, openList, openListMap, closedListMap, 1);// for S.W
163+
if (foundDest) { break; }
164+
foundDest = neighbourExplorer(i + 1, j + 1, parentI, parentJ, openList, openListMap, closedListMap, 1);// for S.E
165+
if (foundDest) { break; }
166+
foundDest = neighbourExplorer(i + 1, j - 1, parentI, parentJ, openList, openListMap, closedListMap, 1);// for N.E
167+
if (foundDest) { break; }
168+
}
169+
170+
171+
if (!foundDest) {
172+
return false;
173+
}
174+
return true;
175+
};
176+
search();
177+
}
178+
179+
180+
// const inputGrid = [
181+
// [1, 0, 1, 1, 1, 1, 0, 1, 1, 1],
182+
// [1, 1, 1, 0, 1, 1, 1, 0, 1, 1],
183+
// [1, 1, 1, 0, 1, 1, 0, 1, 0, 1],
184+
// [0, 0, 1, 0, 1, 0, 0, 0, 0, 1],
185+
// [1, 1, 1, 0, 1, 1, 1, 0, 1, 0],
186+
// [1, 0, 1, 1, 1, 1, 0, 1, 0, 0],
187+
// [1, 0, 0, 0, 0, 1, 0, 0, 0, 1],
188+
// [1, 0, 1, 1, 1, 1, 0, 1, 1, 1],
189+
// [1, 1, 1, 0, 0, 0, 1, 0, 0, 1],
190+
// ];
191+
192+
const inputGrid = [
193+
[1, 0, 0, 0, 0, 0],
194+
[1, 1, 1, 1, 1, 1],
195+
[1, 0, 0, 0, 0, 0],
196+
[1, 1, 1, 1, 1, 1],
197+
];
198+
199+
const ROW = inputGrid.length;
200+
const COL = inputGrid[0].length;
201+
const start = {
202+
i: 0,
203+
j: 0,
204+
};
205+
const end = {
206+
i: 3,
207+
j: 5,
208+
};
209+
210+
AStar(start, end, ROW, COL, inputGrid);
211+
212+
213+
module.exports = {
214+
AStar,
215+
};

0 commit comments

Comments
 (0)