Skip to content

Commit

Permalink
feat: added astar algorithm.
Browse files Browse the repository at this point in the history
  • Loading branch information
manishdait committed Mar 10, 2024
1 parent 308574e commit e69966c
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 27 deletions.
2 changes: 2 additions & 0 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ <h1>{{ title }}</h1>
<li class="opt" (click)="this.selectedAlgo = 'Breath First Search'; toggleAlgo(); this.isWeight = false">Breath First Search</li>
<li class="opt" (click)="this.selectedAlgo = 'Depth First Search'; toggleAlgo(); this.isWeight = false">Depth First Search</li>
<li class="opt" (click)="this.selectedAlgo = 'Dijktras'; toggleAlgo(); this.isWeight = true">Dijistras</li>
<li class="opt" (click)="this.selectedAlgo = 'Astar'; toggleAlgo(); this.isWeight = true">Astar</li>
<li class="opt" (click)="this.selectedAlgo = 'Bidirectional'; toggleAlgo(); this.isWeight = false">Bidirectional</li>
</ul>
</div>
Expand Down Expand Up @@ -178,6 +179,7 @@ <h1>{{ title }}</h1>
<p *ngSwitchCase="'Breath First Search'" class="banner">Breath-First Search is <strong><em>unweighted</em></strong> and <strong><em>guarantees</em></strong> shortest path.</p>
<p *ngSwitchCase="'Depth First Search'" class="banner">Depth-First Search is <strong><em>unweighted</em></strong> and <strong><em>desn't guarantees</em></strong> shortest path!</p>
<p *ngSwitchCase="'Dijktras'" class="banner">Dijktras is <strong><em>weighted</em></strong> and <strong><em>guarantees</em></strong> shortest path.</p>
<p *ngSwitchCase="'Astar'" class="banner">Astar is <strong><em>weighted</em></strong> and <strong><em>guarantees</em></strong> shortest path.</p>
<p *ngSwitchCase="'Bidirectional'" class="banner">Bidirectional (BFS) use <strong><em>two separate searches</em></strong> from <strong><em>source</em></strong> and <strong><em>target</em></strong>.</p>
</div>

Expand Down
24 changes: 16 additions & 8 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Grid } from 'src/assets/helper/Grid';
import { BFS } from '../assets/algorithms/BFS';
import { DFS } from '../assets/algorithms/DFS';
import { BiDirectional } from 'src/assets/algorithms/BiDirectional';
import { Astar } from 'src/assets/algorithms/Astart';

@Component({
selector: 'app-root',
Expand Down Expand Up @@ -35,9 +36,9 @@ export class AppComponent implements AfterViewInit, OnInit {
row: number = 28;
col: number = 70;

start: string = '[12,12]';
end: string = '[12,58]';
boom: string = '[12,35]';
start!: string;
end!: string;
boom!: string;

boomAdded: boolean = false;

Expand Down Expand Up @@ -74,7 +75,7 @@ export class AppComponent implements AfterViewInit, OnInit {
}
}

graph: any = {};
graph: {[key: string]:string[]} = {};

toggleAlgo(): void {
if(!this.disAble) {
Expand Down Expand Up @@ -118,7 +119,6 @@ export class AppComponent implements AfterViewInit, OnInit {
if(this.disAble){
return;
}
// Dragging
});

node?.appendChild(img);
Expand Down Expand Up @@ -165,7 +165,17 @@ export class AppComponent implements AfterViewInit, OnInit {
await new BiDirectional().search(this.graph,this.start, this.end);

this.disAble=false;

break

case 'Astar':
this.disAble=true
if(this.boomAdded)
await new Astar().search_bomb(this.graph, new Grid().mapHurestic(this.end, this.row, this.col),this.start,this.end,this.boom);
else
await new Astar().search(this.graph, new Grid().mapHurestic(this.end, this.row, this.col),this.start, this.end);

this.disAble=false;
break;
}
}

Expand Down Expand Up @@ -196,7 +206,6 @@ export class AppComponent implements AfterViewInit, OnInit {
if(this.disAble){
return;
}
//On dragging.
});

document.getElementById(this.start)!.setAttribute('weight','0');
Expand All @@ -222,7 +231,6 @@ export class AppComponent implements AfterViewInit, OnInit {
if(this.disAble){
return;
}
//On dragging.
});

img.id = 'goal';
Expand Down
209 changes: 209 additions & 0 deletions src/assets/algorithms/Astart.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import { wait } from "../helper/Timmer";

type Node = {
id: string,
prevNode: string|null,
gn: number,
hn: number,
fn: number
}

export class Astar {
path:any = [];
path_b:any = [];
track: {[key: string]: any} = {};
visited:string[] = [];

public async search(graph:any, hurestic:any, start: any, goal: any) {
let queue: Node[] = [];

queue.push({
id: start,
prevNode: null,
gn: 0,
hn: this.calculate_hn(goal, start),
fn: this.calculate_hn(goal, start) + 0
});

while (queue.length > 0) {
var node = queue.shift();

document.getElementById(node!.id)!.firstElementChild!.classList.remove('boom-visited');
document.getElementById(node!.id)!.firstElementChild!.classList.add('marker');
await wait(15);
document.getElementById(node!.id)!.firstElementChild!.classList.remove('marker');
document.getElementById(node!.id)!.firstElementChild!.classList.add('visited');

if (node!.id === goal) {
console.log(hurestic);
console.log(this.visited);
console.log(this.track)
console.log(node);

this.solve(node!, false)
this.drawPath()
break;
}

for (var neighbour of graph[node!.id]) {
if (!this.visited.includes(node!.id) && !this.visited.includes(neighbour) && !document.getElementById(neighbour)!.firstElementChild!.classList.contains('wall')){
let new_gn = node!.gn + this.getWeight(neighbour);

let existingNode = this.hasNode(queue, neighbour);

console.log(existingNode);
if(existingNode!=null) {
existingNode.prevNode = node!.id,
existingNode.gn = new_gn,
existingNode.hn = this.calculate_hn(goal, neighbour)
} else {
queue.push({
id: neighbour,
prevNode: node!.id,
gn: new_gn,
hn: this.calculate_hn(goal, neighbour),
fn: this.calculate_hn(goal, neighbour) + new_gn
});
}

this.track[node!.id] = node!.prevNode;
}
}
this.visited.push(node!.id);

queue.sort((a,b) => a.fn - b.fn)
}
}


public async search_bomb(graph:any, hurestic:any, start: any, goal: any, bomb:any) {
let queue: Node[] = [];

queue.push({
id: start,
prevNode: null,
gn: 0,
hn: this.calculate_hn(bomb, start),
fn: this.calculate_hn(bomb, start) + 0
});

while (queue.length > 0) {
var node = queue.shift();

document.getElementById(node!.id)!.firstElementChild!.classList.add('marker');
await wait(15)
document.getElementById(node!.id)!.firstElementChild!.classList.remove('marker');
document.getElementById(node!.id)!.firstElementChild!.classList.add('boom-visited');

if (node!.id === bomb) {
console.log(hurestic);
console.log(this.visited);
console.log(this.track)
console.log(node);

this.solve(node!, true)
this.visited = []
this.track = {}

this.search(graph,hurestic, bomb, goal);
break;
}

for (var neighbour of graph[node!.id]) {
if (!this.visited.includes(node!.id) && !this.visited.includes(neighbour) && !document.getElementById(neighbour)!.firstElementChild!.classList.contains('wall')){
let new_gn = node!.gn + this.getWeight(neighbour);

let existingNode = this.hasNode(queue, neighbour);

console.log(existingNode);
if(existingNode!=null) {
existingNode.prevNode = node!.id,
existingNode.gn = new_gn,
existingNode.hn = this.calculate_hn(bomb, neighbour)
} else {
queue.push({
id: neighbour,
prevNode: node!.id,
gn: new_gn,
hn: this.calculate_hn(bomb, neighbour),
fn: this.calculate_hn(bomb, neighbour) + new_gn
});
}

this.track[node!.id] = node!.prevNode;
}
}
this.visited.push(node!.id);

queue.sort((a,b) => a.fn - b.fn)
}
}

getWeight(id:any){
return parseInt(document.getElementById(id)!.getAttribute('weight')!)
}

public async drawPath(){
for(var item of this.path_b){
document.getElementById(item)!.firstElementChild!.classList.remove('visited');
document.getElementById(item)!.firstElementChild!.classList.remove('boom-visited');
document.getElementById(item)!.firstElementChild!.classList.remove('path');
document.getElementById(item)!.firstElementChild!.classList.add('path-marker');
await wait(15);
document.getElementById(item)!.firstElementChild!.classList.remove('path-marker');
document.getElementById(item)!.firstElementChild!.classList.add('path');
await wait(15);
}
await wait(15);
for(var item of this.path){
document.getElementById(item)!.firstElementChild!.classList.remove('visited');
document.getElementById(item)!.firstElementChild!.classList.remove('boom-visited');
document.getElementById(item)!.firstElementChild!.classList.remove('path');
document.getElementById(item)!.firstElementChild!.classList.add('path-marker');
await wait(15);
document.getElementById(item)!.firstElementChild!.classList.remove('path-marker');
document.getElementById(item)!.firstElementChild!.classList.add('path');
await wait(15);
}
}

solve(goal:Node, isBomb:boolean) {
let arr = [];
arr.push(goal.id);

let ele = goal.prevNode;
arr.push(ele)
while (this.track[ele!] != null) {
console.log(arr);

arr.push(this.track[ele!]);
ele = this.track[ele!];
}

if(!isBomb) {
this.path = arr.reverse()
console.log(this.path);
} else {
this.path_b = arr.reverse();
console.log(this.path_b);
}
}

hasNode(queue: Node[], node: string) {
for(let n of queue) {
if (n.id == node) {
return n;
}
}
return null;
}

calculate_hn(id1: string, id2: string) {
var a = id1.replace('[', '').replace(']', '').split(',');
var b = id2.replace('[', '').replace(']', '').split(',');
return (Math.abs(parseInt(b[0]) - parseInt(a[0]))) + Math.abs(parseInt(b[1]) - parseInt(a[1]));
}
}



1 change: 0 additions & 1 deletion src/assets/algorithms/Dijktars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ export class Dijktars{
visited.push(graph[ele][i]);
pq[graph[ele][i]] = [(pq[ele][0]+this.getWeight(graph[ele][i])),ele];
queue.push(`${graph[ele][i]} ${(pq[ele][0]+this.getWeight(graph[ele][i]))}`);

const getVal = (str: any) => str.split(' ')[1];
queue.sort((a, b) => getVal(a) - getVal(b));
}
Expand Down
50 changes: 32 additions & 18 deletions src/assets/helper/Grid.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,52 @@
export class Grid{
mapGrid(row:number, col:number){
let graph:any = {};
mapGrid(row:number, col:number): {[key: string]:string[]} {
let graph:{[key: string]:string[]} = {};
let i =0;
while(i < row){
for(var j = 0; j<col; j++){
var node = `[${i},${j}]`;
var neighbor = [];
var topEle = document.getElementById(`[${i-1},${j}]`);
var rightEle = document.getElementById(`[${i},${j+1}]`);
var leftEle = document.getElementById(`[${i},${j-1}]`);
var bottomEle = document.getElementById(`[${i+1},${j}]`);
var neighbour = [];
var topElement = document.getElementById(`[${i-1},${j}]`);
var rightElement = document.getElementById(`[${i},${j+1}]`);
var leftElement = document.getElementById(`[${i},${j-1}]`);
var bottomElement = document.getElementById(`[${i+1},${j}]`);

if(topEle != null){
neighbor.push(`[${i-1},${j}]`);
if(topElement != null){
neighbour.push(`[${i-1},${j}]`);
}

if(rightEle != null){
neighbor.push(`[${i},${j+1}]`);
if(rightElement != null){
neighbour.push(`[${i},${j+1}]`);
}

if(bottomEle != null){
neighbor.push(`[${i+1},${j}]`);
if(bottomElement != null){
neighbour.push(`[${i+1},${j}]`);
}


if(leftEle != null){
neighbor.push(`[${i},${j-1}]`);
if(leftElement != null){
neighbour.push(`[${i},${j-1}]`);
}

graph[node] = neighbor
graph[node] = neighbour
}
i++;
}
return graph;
}

}

mapHurestic(goal: string, row: number, col: number) {
let hurestic: {[key: string]: number} = {};
let cordinate = goal.replace('[', '').replace(']', '').split(',');
let goal_row:number = parseInt(cordinate[0]);
let goal_col = parseInt(cordinate[1]);

for (let i = 0; i < row; i++) {
for (let j = 0; j < col; j++) {
hurestic[`[${i},${j}]`] = Math.abs(goal_row - i) + Math.abs(goal_col - j);
}
}

return hurestic;
}
}

0 comments on commit e69966c

Please sign in to comment.