Skip to content

Commit f40251c

Browse files
Add files via upload
0 parents  commit f40251c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+50832
-0
lines changed

README.md

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Pathfinding Visualizer
2+
3+
Welcome to Pathfinding Visualizer! I built this application because I was fascinated by pathfinding algorithms, and I wanted to visualize them in action. I hope that you enjoy playing around with this visualization tool just as much as I enjoyed building it. You can access it here (use Google Chrome!): https://clementmihailescu.github.io/Pathfinding-Visualizer/
4+
5+
## Meet the Algorithms
6+
7+
This application supports the following algorithms:
8+
9+
**Dijkstra's Algorithm** (weighted): the father of pathfinding algorithms; guarantees the shortest path
10+
11+
**A* Search** (weighted): arguably the best pathfinding algorithm; uses heuristics to guarantee the shortest path much faster than Dijkstra's Algorithm
12+
13+
**Greedy Best-first Search** (weighted): a faster, more heuristic-heavy version of A*; does not guarantee the shortest path
14+
15+
**Swarm Algorithm** (weighted): a mixture of Dijkstra's Algorithm and A*; does not guarantee the shortest-path
16+
17+
**Convergent Swarm Algorithm** (weighted): the faster, more heuristic-heavy version of Swarm; does not guarantee the shortest path
18+
19+
**Bidirectional Swarm Algorithm** (weighted): Swarm from both sides; does not guarantee the shortest path
20+
21+
**Breath-first Search** (unweighted): a great algorithm; guarantees the shortest path
22+
23+
**Depth-first Search** (unweighted): a very bad algorithm for pathfinding; does not guarantee the shortest path
24+
25+
On top of the pathfinding algorithms listed above, I implemented a **Recursive Division** Maze Generation algorithm.
26+
27+
## More about the Swarm Algorithm
28+
29+
The Swarm Algorithm is an algorithm that I - at least presumably so (I was unable to find anything close to it online) - co-developed with a good friend and colleague, Hussein Farah. The algorithm is essentially a mixture of Dijkstra's Algorithm and A* Search; more precisely, while it converges to the target node like A* , it still explores quite a few neighboring nodes surrounding the start node like Dijkstra's. The algorithm differentiates itself from A* through its use of heuristics: it continually updates nodes' distance from the start node while taking into account their estimated distance from the target node. This effectively "balances" the difference in total distance between nodes closer to the start node and nodes closer to the target node, which results in the triangle-like shape of the Swarm Algorithm. We named the algorithm "Swarm" because one of its potential applications could be seen in a video-game where a character must keep track of a boss with high priority (the target node), all the while keeping tracking of neighboring enemies that might be swarming nearby.

index.html

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<html>
2+
<head>
3+
<title>Pathfinding Visualizer</title>
4+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
5+
<link id="cssTheme" rel="stylesheet" href="public/styling/cssBasic.css"/>
6+
<link rel="shortcut icon" type="image/png" href="public/styling/c_icon.png"/>
7+
</head>
8+
<body>
9+
<div id='navbarDiv'>
10+
<nav class="navbar navbar-inverse">
11+
<div class="container-fluid">
12+
<div class="navbar-header">
13+
<a id="refreshButton" class="navbar-brand" href="#">Pathfinding Visualizer</a>
14+
</div>
15+
<ul class="nav navbar-nav">
16+
<li class="dropdown">
17+
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Algorithms
18+
<span class="caret"></span></a>
19+
<ul class="dropdown-menu">
20+
<li id='startButtonDijkstra'><a href="#">Dijkstra's Algorithm</a></li>
21+
<li id='startButtonAStar2'><a href="#">A* Search</a></li>
22+
<li id='startButtonGreedy'><a href="#">Greedy Best-first Search</a></li>
23+
<li id='startButtonAStar'><a href="#">Swarm Algorithm</a></li>
24+
<li id='startButtonAStar3'><a href="#">Convergent Swarm Algorithm</a></li>
25+
<li id='startButtonBidirectional'><a href="#">Bidirectional Swarm Algorithm</a></li>
26+
<li id='startButtonBFS'><a href="#">Breadth-first Search</a></li>
27+
<li id='startButtonDFS'><a href="#">Depth-first Search</a></li>
28+
</ul>
29+
</li>
30+
<li class="dropdown">
31+
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Mazes &amp; Patterns
32+
<span class="caret"></span></a>
33+
<ul class="dropdown-menu">
34+
<li id='startButtonCreateMazeTwo'><a href="#">Recursive Division</a></li>
35+
<li id='startButtonCreateMazeThree'><a href="#">Recursive Division (vertical skew)</a></li>
36+
<li id='startButtonCreateMazeFour'><a href="#">Recursive Division (horizontal skew)</a></li>
37+
<li id='startButtonCreateMazeOne'><a href="#">Basic Random Maze</a></li>
38+
<li id='startButtonCreateMazeWeights'><a href="#">Basic Weight Maze</a></li>
39+
<li id='startStairDemonstration'><a href="#">Simple Stair Pattern</a></li>
40+
</ul>
41+
</li>
42+
<li id='startButtonAddObject'><a href="#">Add Bomb</a></li>
43+
<li id='startButtonStart'><button id="actualStartButton" class="btn btn-default navbar-btn" type="button">Visualize!</button></li>
44+
<li id='startButtonClearBoard'><a href="#">Clear Board</a></li>
45+
<li id='startButtonClearWalls'><a href="#">Clear Walls &amp; Weights</a></li>
46+
<li id='startButtonClearPath'><a href="#">Clear Path</a></li>
47+
<li class="dropdown">
48+
<a id="adjustSpeed" class="dropdown-toggle" data-toggle="dropdown" href="#">Speed: Fast
49+
<span class="caret"></span></a>
50+
<ul class="dropdown-menu">
51+
<li id='adjustFast'><a href="#">Fast</a></li>
52+
<li id='adjustAverage'><a href="#">Average</a></li>
53+
<li id='adjustSlow'><a href="#">Slow</a></li>
54+
</ul>
55+
</li>
56+
</ul>
57+
</div>
58+
</nav>
59+
</div>
60+
<div id="tutorial">
61+
<h3>Welcome to Pathfinding Visualizer!</h3>
62+
<h6>This short tutorial will walk you through all of the features of this application.</h6>
63+
<p>If you want to dive right in, feel free to press the "Skip Tutorial" button below. Otherwise, press "Next"!</p>
64+
<div id="tutorialCounter">1/9</div>
65+
<img id="mainTutorialImage" src="public/styling/c_icon.png">
66+
<button id="nextButton" class="btn btn-default navbar-btn" type="button">Next</button>
67+
<button id="previousButton" class="btn btn-default navbar-btn" type="button">Previous</button>
68+
<button id="skipButton" class="btn btn-default navbar-btn" type="button">Skip Tutorial</button>
69+
</div>
70+
<div id='mainGrid'>
71+
<div id='mainText'>
72+
<ul>
73+
<li>
74+
<div class="start"></div>Start Node</li>
75+
<li>
76+
<div class="target"></div>Target Node</li>
77+
<li id="bombLegend">
78+
<div class="object"></div>Bomb Node</li>
79+
<li id="weightLegend">
80+
<div class="borderlessWeight"></div>Weight Node</li>
81+
<li>
82+
<div class="unvisited"></div>Unvisited Node</li>
83+
<li>
84+
<div class="visited"></div><div class="visitedobject"></div>Visited Nodes</li>
85+
<li>
86+
<div class="shortest-path"></div>Shortest-path Node</li>
87+
<li>
88+
<div class="wall"></div>Wall Node</li>
89+
</ul>
90+
</div>
91+
<div id="algorithmDescriptor">Pick an algorithm and visualize it!</div>
92+
<table id='board'/>
93+
</div>
94+
</body>
95+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
96+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
97+
<script src='public/browser/bundle.js'></script>
98+
</html>

package.json

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "pathfinding_algorithms",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"start": "nodemon server.js",
8+
"test": "echo \"Error: no test specified\" && exit 1",
9+
"watch": "watchify /home/clement/Documents/Fullstack_Academy/Projects/Pathfinding_Algorithms/public/browser/board.js -o /home/clement/Documents/Fullstack_Academy/Projects/Pathfinding_Algorithms/public/browser/bundle.js"
10+
},
11+
"author": "",
12+
"license": "ISC",
13+
"dependencies": {
14+
"express": "^4.14.0"
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
const weightedSearchAlgorithm = require("../pathfindingAlgorithms/weightedSearchAlgorithm");
2+
const unweightedSearchAlgorithm = require("../pathfindingAlgorithms/unweightedSearchAlgorithm");
3+
4+
function launchAnimations(board, success, type, object, algorithm, heuristic) {
5+
let nodes = object ? board.objectNodesToAnimate.slice(0) : board.nodesToAnimate.slice(0);
6+
let speed = board.speed === "fast" ?
7+
0 : board.speed === "average" ?
8+
100 : 500;
9+
let shortestNodes;
10+
function timeout(index) {
11+
setTimeout(function () {
12+
if (index === nodes.length) {
13+
if (object) {
14+
board.objectNodesToAnimate = [];
15+
if (success) {
16+
board.addShortestPath(board.object, board.start, "object");
17+
board.clearNodeStatuses();
18+
let newSuccess;
19+
if (board.currentAlgorithm === "bidirectional") {
20+
21+
} else {
22+
if (type === "weighted") {
23+
newSuccess = weightedSearchAlgorithm(board.nodes, board.object, board.target, board.nodesToAnimate, board.boardArray, algorithm, heuristic);
24+
} else {
25+
newSuccess = unweightedSearchAlgorithm(board.nodes, board.object, board.target, board.nodesToAnimate, board.boardArray, algorithm);
26+
}
27+
}
28+
document.getElementById(board.object).className = "visitedObjectNode";
29+
launchAnimations(board, newSuccess, type);
30+
return;
31+
} else {
32+
console.log("Failure.");
33+
board.reset();
34+
board.toggleButtons();
35+
return;
36+
}
37+
} else {
38+
board.nodesToAnimate = [];
39+
if (success) {
40+
if (document.getElementById(board.target).className !== "visitedTargetNodeBlue") {
41+
document.getElementById(board.target).className = "visitedTargetNodeBlue";
42+
}
43+
if (board.isObject) {
44+
board.addShortestPath(board.target, board.object);
45+
board.drawShortestPathTimeout(board.target, board.object, type, "object");
46+
board.objectShortestPathNodesToAnimate = [];
47+
board.shortestPathNodesToAnimate = [];
48+
board.reset("objectNotTransparent");
49+
} else {
50+
board.drawShortestPathTimeout(board.target, board.start, type);
51+
board.objectShortestPathNodesToAnimate = [];
52+
board.shortestPathNodesToAnimate = [];
53+
board.reset();
54+
}
55+
shortestNodes = board.objectShortestPathNodesToAnimate.concat(board.shortestPathNodesToAnimate);
56+
return;
57+
} else {
58+
console.log("Failure.");
59+
board.reset();
60+
board.toggleButtons();
61+
return;
62+
}
63+
}
64+
} else if (index === 0) {
65+
if (object) {
66+
document.getElementById(board.start).className = "visitedStartNodePurple";
67+
} else {
68+
if (document.getElementById(board.start).className !== "visitedStartNodePurple") {
69+
document.getElementById(board.start).className = "visitedStartNodeBlue";
70+
}
71+
}
72+
if (board.currentAlgorithm === "bidirectional") {
73+
document.getElementById(board.target).className = "visitedTargetNodeBlue";
74+
}
75+
change(nodes[index])
76+
} else if (index === nodes.length - 1 && board.currentAlgorithm === "bidirectional") {
77+
change(nodes[index], nodes[index - 1], "bidirectional");
78+
} else {
79+
change(nodes[index], nodes[index - 1]);
80+
}
81+
timeout(index + 1);
82+
}, speed);
83+
}
84+
85+
function change(currentNode, previousNode, bidirectional) {
86+
let currentHTMLNode = document.getElementById(currentNode.id);
87+
let relevantClassNames = ["start", "target", "object", "visitedStartNodeBlue", "visitedStartNodePurple", "visitedObjectNode", "visitedTargetNodePurple", "visitedTargetNodeBlue"];
88+
if (!relevantClassNames.includes(currentHTMLNode.className)) {
89+
currentHTMLNode.className = !bidirectional ?
90+
"current" : currentNode.weight === 15 ?
91+
"visited weight" : "visited";
92+
}
93+
if (currentHTMLNode.className === "visitedStartNodePurple" && !object) {
94+
currentHTMLNode.className = "visitedStartNodeBlue";
95+
}
96+
if (currentHTMLNode.className === "target" && object) {
97+
currentHTMLNode.className = "visitedTargetNodePurple";
98+
}
99+
if (previousNode) {
100+
let previousHTMLNode = document.getElementById(previousNode.id);
101+
if (!relevantClassNames.includes(previousHTMLNode.className)) {
102+
if (object) {
103+
previousHTMLNode.className = previousNode.weight === 15 ? "visitedobject weight" : "visitedobject";
104+
} else {
105+
previousHTMLNode.className = previousNode.weight === 15 ? "visited weight" : "visited";
106+
}
107+
}
108+
}
109+
}
110+
111+
function shortestPathTimeout(index) {
112+
setTimeout(function () {
113+
if (index === shortestNodes.length){
114+
board.reset();
115+
if (object) {
116+
shortestPathChange(board.nodes[board.target], shortestNodes[index - 1]);
117+
board.objectShortestPathNodesToAnimate = [];
118+
board.shortestPathNodesToAnimate = [];
119+
board.clearNodeStatuses();
120+
let newSuccess;
121+
if (type === "weighted") {
122+
newSuccess = weightedSearchAlgorithm(board.nodes, board.object, board.target, board.nodesToAnimate, board.boardArray, algorithm);
123+
} else {
124+
newSuccess = unweightedSearchAlgorithm(board.nodes, board.object, board.target, board.nodesToAnimate, board.boardArray, algorithm);
125+
}
126+
launchAnimations(board, newSuccess, type);
127+
return;
128+
} else {
129+
shortestPathChange(board.nodes[board.target], shortestNodes[index - 1]);
130+
board.objectShortestPathNodesToAnimate = [];
131+
board.shortestPathNodesToAnimate = [];
132+
return;
133+
}
134+
} else if (index === 0) {
135+
shortestPathChange(shortestNodes[index])
136+
} else {
137+
shortestPathChange(shortestNodes[index], shortestNodes[index - 1]);
138+
}
139+
shortestPathTimeout(index + 1);
140+
}, 40);
141+
}
142+
143+
function shortestPathChange(currentNode, previousNode) {
144+
let currentHTMLNode = document.getElementById(currentNode.id);
145+
if (type === "unweighted") {
146+
currentHTMLNode.className = "shortest-path-unweighted";
147+
} else {
148+
if (currentNode.direction === "up") {
149+
currentHTMLNode.className = "shortest-path-up";
150+
} else if (currentNode.direction === "down") {
151+
currentHTMLNode.className = "shortest-path-down";
152+
} else if (currentNode.direction === "right") {
153+
currentHTMLNode.className = "shortest-path-right";
154+
} else if (currentNode.direction === "left") {
155+
currentHTMLNode.className = "shortest-path-left";
156+
} else if (currentNode.direction = "down-right") {
157+
currentHTMLNode.className = "wall"
158+
}
159+
}
160+
if (previousNode) {
161+
let previousHTMLNode = document.getElementById(previousNode.id);
162+
previousHTMLNode.className = "shortest-path";
163+
} else {
164+
let element = document.getElementById(board.start);
165+
element.className = "shortest-path";
166+
element.removeAttribute("style");
167+
}
168+
}
169+
170+
timeout(0);
171+
172+
};
173+
174+
module.exports = launchAnimations;

0 commit comments

Comments
 (0)