Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

A star #40

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions Greedy/A-Star Shortest Path/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# A\* Shortest Path Algorithm

The A\* (A Star) algorithm is a popular and efficient search algorithm used to find the shortest path between nodes in a graph. It is widely used in various applications, such as pathfinding in video games, robotics, and network routing

![](https://www.101computing.net/wp/wp-content/uploads/A-Star-Search-Algorithm-Step-1.png)

## Overview
A\* combines features of Dijkstra's Algorithm and Greedy Best-First Search. It uses a heuristic to prioritize paths that appear to lead most directly to the goal, which often allows it to find the shortest path more efficiently than Dijkstra's algorithm alone. The algorithm calculates the cost of reaching a node based on the actual cost from the start node and an estimated cost to the goal.

## Key Concepts
G-Score: The cost of the path from the start node to the current node.
H-Score (Heuristic): An estimate of the cost from the current node to the goal.
F-Score: The sum of G-Score and H-Score. A\* selects the node with the lowest F-Score to explore next.

## How It Works
Initialization: Start with the initial node. The G-Score is 0, and the F-Score is equal to the heuristic value for reaching the goal.

Exploration: For each node, calculate the G-Score and H-Score. Update the F-Score for each adjacent node.

Path Selection: Select the node with the lowest F-Score for exploration. If the goal is reached, the algorithm terminates.

Repeat: Continue exploring nodes, updating scores, and selecting the next node until the goal is found or all possible paths are exhausted.

## References
trekhleb/javascript-algorithms - A* Implementation
Wikipedia - A* Search Algorithm
YouTube - A* Pathfinding by Amit Patel
YouTube - A* Algorithm by Sebastian Lague
140 changes: 140 additions & 0 deletions Greedy/A-Star Shortest Path/code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// import visualization libraries {
const {
Tracer,
Array1DTracer,
GraphTracer,
Randomize,
Layout,
VerticalLayout,
} = require("algorithm-visualizer");
// }

const G = Randomize.Graph({
N: 5,
ratio: 0.6,
directed: false,
weighted: true,
});
const MAX_VALUE = Infinity;
const S = []; // S[end] returns the distance from start node to end node
for (let i = 0; i < G.length; i++) S[i] = MAX_VALUE;

// Heuristic function based on actual distances between nodes
function heuristic(node, goal) {
if (G[node][goal] !== 0) {
return G[node][goal]; // Use the direct edge weight if available
} else {
// Use an alternative if no direct edge exists (optional)
let minEdge = MAX_VALUE;
for (let i = 0; i < G.length; i++) {
if (G[node][i] !== 0 && G[node][i] < minEdge) {
minEdge = G[node][i];
}
}
return minEdge !== MAX_VALUE ? minEdge : 1; // Use the smallest edge connected to the node as a fallback heuristic
}
}

// define tracer variables {
const tracer = new GraphTracer().directed(false).weighted();
const tracerS = new Array1DTracer();
Layout.setRoot(new VerticalLayout([tracer, tracerS]));
tracer.set(G);
tracerS.set(S);
Tracer.delay();
// }

function AStar(start, end) {
let minIndex;
let minDistance;
const D = []; // D[i] indicates whether the i-th node is discovered or not
const openSet = []; // Nodes to be evaluated
const previous = []; // Array to store the previous node for path reconstruction
for (let i = 0; i < G.length; i++) {
D.push(false);
previous.push(null);
}
S[start] = 0; // Starting node is at distance 0 from itself
openSet.push({ node: start, fCost: heuristic(start, end) });

// visualize {
tracerS.patch(start, S[start]);
Tracer.delay();
tracerS.depatch(start);
tracerS.select(start);
// }

while (openSet.length > 0) {
// Find the node in the open set with the lowest fCost (gCost + hCost)
minIndex = openSet.reduce((prev, curr, idx, arr) => {
return arr[prev].fCost < curr.fCost ? prev : idx;
}, 0);

const current = openSet[minIndex].node;

if (current === end) {
break; // If we reached the goal, stop
}

openSet.splice(minIndex, 1);
D[current] = true;

// visualize {
tracerS.select(current);
tracer.visit(current);
Tracer.delay();
// }

// For every unvisited neighbor of the current node
for (let i = 0; i < G.length; i++) {
if (G[current][i] && !D[i]) {
const tentative_gCost = S[current] + G[current][i];
if (tentative_gCost < S[i]) {
S[i] = tentative_gCost;
previous[i] = current; // Store the previous node
const fCost = tentative_gCost + heuristic(i, end);
openSet.push({ node: i, fCost });

// visualize {
tracerS.patch(i, S[i]);
tracer.visit(i, current, S[i]);
Tracer.delay();
tracerS.depatch(i);
tracer.leave(i, current);
Tracer.delay();
// }
}
}
}
// visualize {
tracer.leave(current);
Tracer.delay();
// }
}

// If end is reached, reconstruct the path
if (S[end] !== MAX_VALUE) {
let path = [];
for (let at = end; at !== null; at = previous[at]) {
path.push(at);
}
path.reverse();

// visualize the final path
for (let i = 0; i < path.length; i++) {
tracer.select(path[i]);
if (i > 0) {
tracer.visit(path[i], path[i - 1]);
}
Tracer.delay();
}
}
}

const s = Randomize.Integer({ min: 0, max: G.length - 1 }); // s = start node
let e; // e = end node
do {
e = Randomize.Integer({ min: 0, max: G.length - 1 });
} while (s === e);
Tracer.delay();
AStar(s, e);