├── LICENSE
├── README.md
├── build
├── asset-manifest.json
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
├── precache-manifest.753fd06515cb4bfffa418f4a4b35d820.js
├── robots.txt
├── service-worker.js
└── static
│ ├── css
│ ├── main.3944e690.chunk.css
│ └── main.3944e690.chunk.css.map
│ └── js
│ ├── 2.f0583ba6.chunk.js
│ ├── 2.f0583ba6.chunk.js.map
│ ├── main.d7aa8aac.chunk.js
│ ├── main.d7aa8aac.chunk.js.map
│ ├── runtime-main.0f354abe.js
│ └── runtime-main.0f354abe.js.map
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
└── src
├── App.css
├── App.js
├── App.test.js
├── PathfindingVisualizer
├── Node
│ ├── Node.css
│ └── Node.jsx
├── PathfindingVisualizer.css
└── PathfindingVisualizer.jsx
├── algorithms
├── aStar.js
├── bfs.js
├── dfs.js
└── dijkstra.js
├── index.css
├── index.js
├── logo.svg
└── serviceWorker.js
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Prudhvi Garapati
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PathFinding-Visualizer: - A REACT APPLICATION
2 | [](https://img.shields.io/badge/node-12.14.1-important)
3 | [](https://img.shields.io/badge/npm-6.13.7-blueviolet)
4 | [](https://img.shields.io/badge/npm-6.13.7-blueviolet)
5 | [](https://travis-ci.org/badges/badgerbadgerbadger)
6 |
7 | ---------------
8 | ### check out live demo [HERE](https://prudhvignv.github.io/pathFinderVisualizer/)
9 |
10 | ##### DFS visualization demo:
11 |
12 | 
13 |
14 |
15 |
16 | ## Overview:
17 | This is a fun project on visualizing path finding algorithms i.e BFS, DFS, Dikstra’s , A* algorithm.
18 | This app is entirely built in react and below is the how the interface looks like..
19 | Green box is the starting node and Red box is the end node.
20 | You can see the various algorithms below to visualize.
21 | Here design of grid is done using tables and set first node and second node colors using CSS properties.
22 | 
23 |
24 |
25 | ## Intro ..
26 |
27 | Path finding algorithms plays a vital role in our daily life such as packets in computer networks , google maps uses a path finding algorthm to find the shortest path.
28 | So this project main idea is to visualize this path finding algorthms using react with the help of some css animations.
29 |
30 | You can also follow my [Medium BLOG](https://medium.com/@prudhvi.gnv/path-finding-visualizer-using-react-from-creating-to-building-and-deploying-bd1e2bc64696) for more understanding and details :)
31 | ------
32 |
33 | Let's check out some intuition behind this algorithms for better insights.
34 | ### Breadth First Search
35 | * Breadth First Search explores equally in all directions.
36 | * This is an incredibly useful algorithm, not only for regular traversal, but also for procedural map generation, flow field pathfinding, distance maps, and other types of map analysis.
37 | * This may be the algorithm of choice to identify nearby places of interest in GPS.
38 | * BFS guarantees the shortest path.
39 | Below is the result for Breadth first search:
40 | 
41 |
42 | ### Depth First Search
43 | - Traverses by exploring as far as possible down each path before backtracking.
44 | - As useful as the BFS: DFS can be used to generate a topological ordering, to generate mazes, to traverse trees, to build decision trees, to discover a solution path with hierarchical choices…
45 | - DFS does not guarantee the shortest path.
46 | Below is how the DFS works
47 | 
48 | ### Dijkstra
49 | - Dijkstra's Algorithm lets us prioritize which paths to explore. Instead of exploring all possible paths equally, it favors lower cost paths.
50 | - We can assign lower cost to encourage moving on roads while assigning high cost on highway to avoid them.
51 | - It is the algorithm of choice for finding the shortest path paths with multiple destinations.
52 | Below is the demo
53 | 
54 |
55 | ### A* (A-Star)
56 | - A* is a modification of Dijkstra's Algorithm that is optimized for a single destination.
57 | - Dijkstra's Algorithm can find paths to all locations; A* finds paths to one location. It prioritizes paths that seem to be leading closer to a goal.
58 | - In a game, we could set costs to be attracted or discouraged in going near some objects : how useful it is for an AI.
59 | - It is more or less the golden ticket or industry standard algorithm for all applications finding directions between two locations.
60 | Below is the demo of application:
61 | 
62 |
63 | Now Let's drive into the code ..
64 | ------------------
65 | ## Getting Started ..
66 | First install node.js which comes with a bundle(npm+npx) to run javascript in local system.
67 | type following commands in the shell to create a react app
68 |
69 | ```
70 | npx create-react-app my-app
71 | cd my-app
72 | npm start
73 | ```
74 |
75 | ### npm start
76 | Runs the app in the development mode.
77 | Open http://localhost:3000 to view it in the browser.
78 | The page will reload if you make edits.
79 | You will also see any lint errors in the console.
80 | Below is the App.js component which is the root component for the react applications.
81 |
82 | ```js
83 |
84 | import React from 'react';
85 | import './App.css';
86 | import PathfindingVisualizer from './PathfindingVisualizer/PathfindingVisualizer';
87 |
88 | function App() {
89 | return (
90 |
91 |
92 |
93 | );
94 | }
95 |
96 | export default App;
97 | ```
98 |
99 | The PathfindingVisualizer component is imported and rendered in App.js.
100 |
101 | I write everything related to the project in the pathfindingVisualizer component.
102 | ## pathfindingVisualizer:
103 | Here we jammed everything we need into this component such as GUI logic, animations logic , node objects structure and its properties, Some boolean values (isRunning, isStartNode, isFinishNode, isWallNode ), css properties , walls logic, implementing algorithms, mousehandlers
104 | Then the pathfinding algorithms are written in another folder and is imported into pathfindingVisualizer component.
105 |
106 | ```js
107 | import React, {Component} from 'react';
108 | import Node from './Node/Node';
109 | import {dijkstra} from '../algorithms/dijkstra';
110 | import {AStar} from '../algorithms/aStar';
111 | import {dfs} from '../algorithms/dfs';
112 | import {bfs} from '../algorithms/bfs';
113 |
114 | import './PathfindingVisualizer.css';
115 | ```
116 | Then handle mouse events and some reusable components to make this application more friendly.
117 |
118 | There are functionalities in pathfindingVisualizer component for creating initialgrid(), clearwalls(), CreateNode(), isGridClear(), clearGrid() etc ..
119 |
120 | ***Below is the driver code to implement algorithms in the component!!***
121 |
122 | ```js
123 |
124 | visualize(algo) {
125 | if (!this.state.isRunning) {
126 | this.clearGrid();
127 | this.toggleIsRunning();
128 | const {grid} = this.state;
129 | const startNode =
130 | grid[this.state.START_NODE_ROW][this.state.START_NODE_COL];
131 | const finishNode =
132 | grid[this.state.FINISH_NODE_ROW][this.state.FINISH_NODE_COL];
133 | let visitedNodesInOrder;
134 | switch (algo) {
135 | case 'Dijkstra':
136 | visitedNodesInOrder = dijkstra(grid, startNode, finishNode);
137 | break;
138 | case 'AStar':
139 | visitedNodesInOrder = AStar(grid, startNode, finishNode);
140 | break;
141 | case 'BFS':
142 | visitedNodesInOrder = bfs(grid, startNode, finishNode);
143 | break;
144 | case 'DFS':
145 | visitedNodesInOrder = dfs(grid, startNode, finishNode);
146 | break;
147 | default:
148 | // should never get here
149 | break;
150 | }
151 |
152 | ```
153 |
154 |
155 |
156 |
157 |
158 |
159 | If you want to work off of this base to create your own Pathfinding Visualizer, feel free to fork this project or to just copy-paste code.
160 |
161 | Feel free to check out my other projects by going to [My Portfolio Site](https://prudhvignv.github.io).
162 |
163 | Everything below this line was automatically generated by Create React App.
164 |
165 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
166 |
167 |
168 | ## Deployment
169 |
170 | ### `npm run build`
171 |
172 | Builds the app for production to the `build` folder.
173 | It correctly bundles React in production mode and optimizes the build for the best performance.
174 |
175 | The build is minified and the filenames include the hashes.
176 | Your app is ready to be deployed!
177 |
178 |
179 | I deploy this app in github pages.
180 | You can check out here : [https://prudhvignv.github.io/pathFinderVisualizer/](https://prudhvignv.github.io/pathFinderVisualizer/)
181 |
182 |
183 |
184 | ### LICENSE
185 | [MIT](https://github.com/PrudhviGNV/pathFinderVisualizer/blob/master/LICENSE)
186 |
187 |
188 |
189 |
190 |
191 | -------------------------------
192 |
193 | ----------------------------
194 |
195 |
196 |
197 | ## For more documentation and understanding.. check out following links..
198 |
199 |
200 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
201 |
202 | To learn React, check out the [React documentation](https://reactjs.org/).
203 |
204 | ### Code Splitting
205 |
206 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
207 |
208 | ### Analyzing the Bundle Size
209 |
210 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
211 |
212 | ### Making a Progressive Web App
213 |
214 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
215 |
216 | ### Advanced Configuration
217 |
218 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
219 |
220 | ### Deployment
221 |
222 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
223 |
224 | ### `npm run build` fails to minify
225 |
226 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
227 |
--------------------------------------------------------------------------------
/build/asset-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": {
3 | "main.css": "/pathFinderVisualizer/static/css/main.3944e690.chunk.css",
4 | "main.js": "/pathFinderVisualizer/static/js/main.d7aa8aac.chunk.js",
5 | "main.js.map": "/pathFinderVisualizer/static/js/main.d7aa8aac.chunk.js.map",
6 | "runtime-main.js": "/pathFinderVisualizer/static/js/runtime-main.0f354abe.js",
7 | "runtime-main.js.map": "/pathFinderVisualizer/static/js/runtime-main.0f354abe.js.map",
8 | "static/js/2.f0583ba6.chunk.js": "/pathFinderVisualizer/static/js/2.f0583ba6.chunk.js",
9 | "static/js/2.f0583ba6.chunk.js.map": "/pathFinderVisualizer/static/js/2.f0583ba6.chunk.js.map",
10 | "index.html": "/pathFinderVisualizer/index.html",
11 | "precache-manifest.753fd06515cb4bfffa418f4a4b35d820.js": "/pathFinderVisualizer/precache-manifest.753fd06515cb4bfffa418f4a4b35d820.js",
12 | "service-worker.js": "/pathFinderVisualizer/service-worker.js",
13 | "static/css/main.3944e690.chunk.css.map": "/pathFinderVisualizer/static/css/main.3944e690.chunk.css.map"
14 | }
15 | }
--------------------------------------------------------------------------------
/build/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PrudhviGNV/pathFinderVisualizer/178c7d4660600c2b8684e38d3a3df554f82c222d/build/favicon.ico
--------------------------------------------------------------------------------
/build/index.html:
--------------------------------------------------------------------------------
1 | PathFinder Visualizer - React App
Made with ♥ Prudhvi GNV
--------------------------------------------------------------------------------
/build/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PrudhviGNV/pathFinderVisualizer/178c7d4660600c2b8684e38d3a3df554f82c222d/build/logo192.png
--------------------------------------------------------------------------------
/build/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PrudhviGNV/pathFinderVisualizer/178c7d4660600c2b8684e38d3a3df554f82c222d/build/logo512.png
--------------------------------------------------------------------------------
/build/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/build/precache-manifest.753fd06515cb4bfffa418f4a4b35d820.js:
--------------------------------------------------------------------------------
1 | self.__precacheManifest = (self.__precacheManifest || []).concat([
2 | {
3 | "revision": "cd76c10519a55a2a272b80c96c9d0af2",
4 | "url": "/pathFinderVisualizer/index.html"
5 | },
6 | {
7 | "revision": "7883538111ce8282e9ad",
8 | "url": "/pathFinderVisualizer/static/css/main.3944e690.chunk.css"
9 | },
10 | {
11 | "revision": "3f51ea05862ffd4db38d",
12 | "url": "/pathFinderVisualizer/static/js/2.f0583ba6.chunk.js"
13 | },
14 | {
15 | "revision": "7883538111ce8282e9ad",
16 | "url": "/pathFinderVisualizer/static/js/main.d7aa8aac.chunk.js"
17 | },
18 | {
19 | "revision": "8420aba34769908039a4",
20 | "url": "/pathFinderVisualizer/static/js/runtime-main.0f354abe.js"
21 | }
22 | ]);
--------------------------------------------------------------------------------
/build/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/build/service-worker.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Welcome to your Workbox-powered service worker!
3 | *
4 | * You'll need to register this file in your web app and you should
5 | * disable HTTP caching for this file too.
6 | * See https://goo.gl/nhQhGp
7 | *
8 | * The rest of the code is auto-generated. Please don't update this file
9 | * directly; instead, make changes to your Workbox build configuration
10 | * and re-run your build process.
11 | * See https://goo.gl/2aRDsh
12 | */
13 |
14 | importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
15 |
16 | importScripts(
17 | "/pathFinderVisualizer/precache-manifest.753fd06515cb4bfffa418f4a4b35d820.js"
18 | );
19 |
20 | self.addEventListener('message', (event) => {
21 | if (event.data && event.data.type === 'SKIP_WAITING') {
22 | self.skipWaiting();
23 | }
24 | });
25 |
26 | workbox.core.clientsClaim();
27 |
28 | /**
29 | * The workboxSW.precacheAndRoute() method efficiently caches and responds to
30 | * requests for URLs in the manifest.
31 | * See https://goo.gl/S9QRab
32 | */
33 | self.__precacheManifest = [].concat(self.__precacheManifest || []);
34 | workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
35 |
36 | workbox.routing.registerNavigationRoute(workbox.precaching.getCacheKeyForURL("/pathFinderVisualizer/index.html"), {
37 |
38 | blacklist: [/^\/_/,/\/[^/?]+\.[^/]+$/],
39 | });
40 |
--------------------------------------------------------------------------------
/build/static/css/main.3944e690.chunk.css:
--------------------------------------------------------------------------------
1 | body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.App{text-align:center}.App-logo{height:40vmin}.App-header{background-color:#282c34;min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;font-size:calc(10px + 2vmin);color:#fff}.App-link{color:#09d3ac}.node{width:25px;height:25px;outline:1px solid #afd8f8;display:inline-block}.node-finish{background-color:red}.node-start{background-color:green}.node-visited{-webkit-animation-name:visitedAnimation;animation-name:visitedAnimation;-webkit-animation-duration:1.5s;animation-duration:1.5s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-delay:0;animation-delay:0;-webkit-animation-direction:alternate;animation-direction:alternate;-webkit-animation-iteration-count:1;animation-iteration-count:1;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-play-state:running;animation-play-state:running}@-webkit-keyframes visitedAnimation{0%{-webkit-transform:scale(.3);transform:scale(.3);background-color:rgba(0,0,66,.75);border-radius:100%}50%{background-color:rgba(217,17,187,.75)}75%{-webkit-transform:scale(1.2);transform:scale(1.2);background-color:rgba(34,17,217,.75)}to{-webkit-transform:scale(1);transform:scale(1);background-color:rgba(0,218,69,.75)}}@keyframes visitedAnimation{0%{-webkit-transform:scale(.3);transform:scale(.3);background-color:rgba(0,0,66,.75);border-radius:100%}50%{background-color:rgba(217,17,187,.75)}75%{-webkit-transform:scale(1.2);transform:scale(1.2);background-color:rgba(34,17,217,.75)}to{-webkit-transform:scale(1);transform:scale(1);background-color:rgba(0,218,69,.75)}}.node-wall{background-color:#0c3547}.node-shortest-path{-webkit-animation-name:shortestPath;animation-name:shortestPath;-webkit-animation-duration:1.5s;animation-duration:1.5s;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out;-webkit-animation-delay:0;animation-delay:0;-webkit-animation-direction:alternate;animation-direction:alternate;-webkit-animation-iteration-count:1;animation-iteration-count:1;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-play-state:running;animation-play-state:running}@-webkit-keyframes shortestPath{0%{-webkit-transform:scale(.6);transform:scale(.6);background-color:#fffe6a}50%{-webkit-transform:scale(1.2);transform:scale(1.2);background-color:#fffe6a}to{-webkit-transform:scale(1);transform:scale(1);background-color:#fffe6a}}@keyframes shortestPath{0%{-webkit-transform:scale(.6);transform:scale(.6);background-color:#fffe6a}50%{-webkit-transform:scale(1.2);transform:scale(1.2);background-color:#fffe6a}to{-webkit-transform:scale(1);transform:scale(1);background-color:#fffe6a}}.grid-container{margin:10% auto}.grid{white-space:pre}button{margin:2px}
2 | /*# sourceMappingURL=main.3944e690.chunk.css.map */
--------------------------------------------------------------------------------
/build/static/css/main.3944e690.chunk.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["index.css","App.css","Node.css","PathfindingVisualizer.css"],"names":[],"mappings":"AAAA,KACE,QAAS,CACT,mIAEY,CACZ,kCAAmC,CACnC,iCACF,CAEA,KACE,uEAEF,CCZA,KACE,iBACF,CAEA,UACE,aACF,CAEA,YACE,wBAAyB,CACzB,gBAAiB,CACjB,YAAa,CACb,qBAAsB,CACtB,kBAAmB,CACnB,sBAAuB,CACvB,4BAA6B,CAC7B,UACF,CAEA,UACE,aACF,CCrBA,MACE,UAAW,CACX,WAAY,CACZ,yBAAqC,CACrC,oBACF,CAEA,aACE,oBACF,CAEA,YACE,sBACF,CAEA,cACE,uCAAgC,CAAhC,+BAAgC,CAChC,+BAAwB,CAAxB,uBAAwB,CACxB,6CAAsC,CAAtC,qCAAsC,CACtC,yBAAkB,CAAlB,iBAAkB,CAClB,qCAA8B,CAA9B,6BAA8B,CAC9B,mCAA4B,CAA5B,2BAA4B,CAC5B,oCAA6B,CAA7B,4BAA6B,CAC7B,oCAA6B,CAA7B,4BACF,CAEA,oCACE,GACE,2BAAqB,CAArB,mBAAqB,CACrB,iCAAsC,CACtC,kBACF,CAEA,IACE,qCACF,CAEA,IACE,4BAAqB,CAArB,oBAAqB,CACrB,oCACF,CAEA,GACE,0BAAmB,CAAnB,kBAAmB,CACnB,mCACF,CACF,CApBA,4BACE,GACE,2BAAqB,CAArB,mBAAqB,CACrB,iCAAsC,CACtC,kBACF,CAEA,IACE,qCACF,CAEA,IACE,4BAAqB,CAArB,oBAAqB,CACrB,oCACF,CAEA,GACE,0BAAmB,CAAnB,kBAAmB,CACnB,mCACF,CACF,CAEA,WACE,wBACF,CAEA,oBACE,mCAA4B,CAA5B,2BAA4B,CAC5B,+BAAwB,CAAxB,uBAAwB,CACxB,0CAAmC,CAAnC,kCAAmC,CACnC,yBAAkB,CAAlB,iBAAkB,CAClB,qCAA8B,CAA9B,6BAA8B,CAC9B,mCAA4B,CAA5B,2BAA4B,CAC5B,oCAA6B,CAA7B,4BAA6B,CAC7B,oCAA6B,CAA7B,4BACF,CAEA,gCACE,GACE,2BAAqB,CAArB,mBAAqB,CACrB,wBACF,CAEA,IACE,4BAAqB,CAArB,oBAAqB,CACrB,wBACF,CAEA,GACE,0BAAmB,CAAnB,kBAAmB,CACnB,wBACF,CACF,CAfA,wBACE,GACE,2BAAqB,CAArB,mBAAqB,CACrB,wBACF,CAEA,IACE,4BAAqB,CAArB,oBAAqB,CACrB,wBACF,CAEA,GACE,0BAAmB,CAAnB,kBAAmB,CACnB,wBACF,CACF,CC9EA,gBACE,eACF,CAEA,MACE,eACF,CAEA,OACE,UACF","file":"main.3944e690.chunk.css","sourcesContent":["body {\r\n margin: 0;\r\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\r\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\r\n sans-serif;\r\n -webkit-font-smoothing: antialiased;\r\n -moz-osx-font-smoothing: grayscale;\r\n}\r\n\r\ncode {\r\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\r\n monospace;\r\n}\r\n",".App {\r\n text-align: center;\r\n}\r\n\r\n.App-logo {\r\n height: 40vmin;\r\n}\r\n\r\n.App-header {\r\n background-color: #282c34;\r\n min-height: 100vh;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: calc(10px + 2vmin);\r\n color: white;\r\n}\r\n\r\n.App-link {\r\n color: #09d3ac;\r\n}\r\n",".node {\r\n width: 25px;\r\n height: 25px;\r\n outline: 1px solid rgb(175, 216, 248);\r\n display: inline-block;\r\n}\r\n\r\n.node-finish {\r\n background-color: red;\r\n}\r\n\r\n.node-start {\r\n background-color: green;\r\n}\r\n\r\n.node-visited {\r\n animation-name: visitedAnimation;\r\n animation-duration: 1.5s;\r\n animation-timing-function: ease-in-out;\r\n animation-delay: 0;\r\n animation-direction: alternate;\r\n animation-iteration-count: 1;\r\n animation-fill-mode: forwards;\r\n animation-play-state: running;\r\n}\r\n\r\n@keyframes visitedAnimation {\r\n 0% {\r\n transform: scale(0.3);\r\n background-color: rgba(0, 0, 66, 0.75);\r\n border-radius: 100%;\r\n }\r\n\r\n 50% {\r\n background-color: rgba(217, 17, 187, 0.75);\r\n }\r\n\r\n 75% {\r\n transform: scale(1.2);\r\n background-color: rgba(34, 17, 217, 0.75);\r\n }\r\n\r\n 100% {\r\n transform: scale(1);\r\n background-color: rgba(0, 218, 69, 0.75);\r\n }\r\n}\r\n\r\n.node-wall {\r\n background-color: rgb(12, 53, 71);\r\n}\r\n\r\n.node-shortest-path {\r\n animation-name: shortestPath;\r\n animation-duration: 1.5s;\r\n animation-timing-function: ease-out;\r\n animation-delay: 0;\r\n animation-direction: alternate;\r\n animation-iteration-count: 1;\r\n animation-fill-mode: forwards;\r\n animation-play-state: running;\r\n}\r\n\r\n@keyframes shortestPath {\r\n 0% {\r\n transform: scale(0.6);\r\n background-color: rgb(255, 254, 106);\r\n }\r\n\r\n 50% {\r\n transform: scale(1.2);\r\n background-color: rgb(255, 254, 106);\r\n }\r\n\r\n 100% {\r\n transform: scale(1);\r\n background-color: rgb(255, 254, 106);\r\n }\r\n}\r\n",".grid-container {\r\n margin: 10% auto;\r\n}\r\n\r\n.grid {\r\n white-space: pre;\r\n}\r\n\r\nbutton {\r\n margin: 2px;\r\n}\r\n"]}
--------------------------------------------------------------------------------
/build/static/js/main.d7aa8aac.chunk.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonpmy-app"]=window["webpackJsonpmy-app"]||[]).push([[0],[,,,,,,,,,,function(t,e,n){t.exports=n(19)},,,,,function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){"use strict";n.r(e);var i=n(0),a=n.n(i),s=n(8),r=n.n(s),o=(n(15),n(16),n(9)),l=n(2),c=n(3),u=n(5),d=n(4),h=n(1),f=n(6),v=(n(17),function(t){function e(){return Object(l.a)(this,e),Object(u.a)(this,Object(d.a)(e).apply(this,arguments))}return Object(f.a)(e,t),Object(c.a)(e,[{key:"render",value:function(){var t=this.props,e=t.col,n=t.isFinish,i=t.isStart,s=t.isWall,r=t.onMouseDown,o=t.onMouseEnter,l=t.onMouseUp,c=t.row,u=n?"node-finish":i?"node-start":s?"node-wall":"";return a.a.createElement("td",{id:"node-".concat(c,"-").concat(e),className:"node ".concat(u),onMouseDown:function(){return r(c,e)},onMouseEnter:function(){return o(c,e)},onMouseUp:function(){return l()}})}}]),e}(i.Component));function N(t,e,n){var i=[];e.distance=0;for(var a=function(t){var e=[],n=!0,i=!1,a=void 0;try{for(var s,r=t[Symbol.iterator]();!(n=(s=r.next()).done);n=!0){var o=s.value,l=!0,c=!1,u=void 0;try{for(var d,h=o[Symbol.iterator]();!(l=(d=h.next()).done);l=!0){var f=d.value;e.push(f)}}catch(v){c=!0,u=v}finally{try{l||null==h.return||h.return()}finally{if(c)throw u}}}}catch(v){i=!0,a=v}finally{try{n||null==r.return||r.return()}finally{if(i)throw a}}return e}(t);a.length;){m(a);var s=a.shift();if(!s.isWall){if(s.distance===1/0)return i;if(s.isVisited=!0,i.push(s),s===n)return i;O(s,t)}}}function m(t){t.sort((function(t,e){return t.distance-e.distance}))}function O(t,e){var n=function(t,e){var n=[],i=t.col,a=t.row;a>0&&n.push(e[a-1][i]);a0&&n.push(e[a][i-1]);i0&&n.push(e[a-1][i]);a0&&n.push(e[a][i-1]);i0&&void 0!==arguments[0]?arguments[0]:t.state.ROW_COUNT,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:t.state.COLUMN_COUNT,i=[],a=0;athis.state.MOBILE_ROW_COUNT||this.state.FINISH_NODE_ROW>this.state.MOBILE_ROW_COUNT||this.state.START_NODE_COL>this.state.MOBILE_COLUMN_COUNT||this.state.FINISH_NODE_COL>this.state.MOBILE_COLUMN_COUNT?alert("Start & Finish Nodes Must Be within 10 Rows x 20 Columns"):(t=this.getInitialGrid(this.state.MOBILE_ROW_COUNT,this.state.MOBILE_COLUMN_COUNT),this.setState({isDesktopView:e,grid:t}))}}},{key:"handleMouseDown",value:function(t,e){if(!this.state.isRunning)if(this.isGridClear())if("node node-start"===document.getElementById("node-".concat(t,"-").concat(e)).className)this.setState({mouseIsPressed:!0,isStartNode:!0,currRow:t,currCol:e});else if("node node-finish"===document.getElementById("node-".concat(t,"-").concat(e)).className)this.setState({mouseIsPressed:!0,isFinishNode:!0,currRow:t,currCol:e});else{var n=E(this.state.grid,t,e);this.setState({grid:n,mouseIsPressed:!0,isWallNode:!0,currRow:t,currCol:e})}else this.clearGrid()}},{key:"isGridClear",value:function(){var t=!0,e=!1,n=void 0;try{for(var i,a=this.state.grid[Symbol.iterator]();!(t=(i=a.next()).done);t=!0){var s=i.value,r=!0,o=!1,l=void 0;try{for(var c,u=s[Symbol.iterator]();!(r=(c=u.next()).done);r=!0){var d=c.value,h=document.getElementById("node-".concat(d.row,"-").concat(d.col)).className;if("node node-visited"===h||"node node-shortest-path"===h)return!1}}catch(f){o=!0,l=f}finally{try{r||null==u.return||u.return()}finally{if(o)throw l}}}}catch(f){e=!0,n=f}finally{try{t||null==a.return||a.return()}finally{if(e)throw n}}return!0}},{key:"handleMouseEnter",value:function(t,e){if(!this.state.isRunning&&this.state.mouseIsPressed){var n=document.getElementById("node-".concat(t,"-").concat(e)).className;if(this.state.isStartNode){if("node node-wall"!==n)this.state.grid[this.state.currRow][this.state.currCol].isStart=!1,document.getElementById("node-".concat(this.state.currRow,"-").concat(this.state.currCol)).className="node",this.setState({currRow:t,currCol:e}),this.state.grid[t][e].isStart=!0,document.getElementById("node-".concat(t,"-").concat(e)).className="node node-start";this.setState({START_NODE_ROW:t,START_NODE_COL:e})}else if(this.state.isFinishNode){if("node node-wall"!==n)this.state.grid[this.state.currRow][this.state.currCol].isFinish=!1,document.getElementById("node-".concat(this.state.currRow,"-").concat(this.state.currCol)).className="node",this.setState({currRow:t,currCol:e}),this.state.grid[t][e].isFinish=!0,document.getElementById("node-".concat(t,"-").concat(e)).className="node node-finish";this.setState({FINISH_NODE_ROW:t,FINISH_NODE_COL:e})}else if(this.state.isWallNode){var i=E(this.state.grid,t,e);this.setState({grid:i})}}}},{key:"handleMouseUp",value:function(t,e){if(!this.state.isRunning){if(this.setState({mouseIsPressed:!1}),this.state.isStartNode){var n=!this.state.isStartNode;this.setState({isStartNode:n,START_NODE_ROW:t,START_NODE_COL:e})}else if(this.state.isFinishNode){var i=!this.state.isFinishNode;this.setState({isFinishNode:i,FINISH_NODE_ROW:t,FINISH_NODE_COL:e})}this.getInitialGrid()}}},{key:"handleMouseLeave",value:function(){if(this.state.isStartNode){var t=!this.state.isStartNode;this.setState({isStartNode:t,mouseIsPressed:!1})}else if(this.state.isFinishNode){var e=!this.state.isFinishNode;this.setState({isFinishNode:e,mouseIsPressed:!1})}else if(this.state.isWallNode){var n=!this.state.isWallNode;this.setState({isWallNode:n,mouseIsPressed:!1}),this.getInitialGrid()}}},{key:"clearGrid",value:function(){if(!this.state.isRunning){var t=this.state.grid.slice(),e=!0,n=!1,i=void 0;try{for(var a,s=t[Symbol.iterator]();!(e=(a=s.next()).done);e=!0){var r=a.value,o=!0,l=!1,c=void 0;try{for(var u,d=r[Symbol.iterator]();!(o=(u=d.next()).done);o=!0){var h=u.value,f=document.getElementById("node-".concat(h.row,"-").concat(h.col)).className;"node node-start"!==f&&"node node-finish"!==f&&"node node-wall"!==f&&(document.getElementById("node-".concat(h.row,"-").concat(h.col)).className="node",h.isVisited=!1,h.distance=1/0,h.distanceToFinishNode=Math.abs(this.state.FINISH_NODE_ROW-h.row)+Math.abs(this.state.FINISH_NODE_COL-h.col)),"node node-finish"===f&&(h.isVisited=!1,h.distance=1/0,h.distanceToFinishNode=0),"node node-start"===f&&(h.isVisited=!1,h.distance=1/0,h.distanceToFinishNode=Math.abs(this.state.FINISH_NODE_ROW-h.row)+Math.abs(this.state.FINISH_NODE_COL-h.col),h.isStart=!0,h.isWall=!1,h.previousNode=null,h.isNode=!0)}}catch(v){l=!0,c=v}finally{try{o||null==d.return||d.return()}finally{if(l)throw c}}}}catch(v){n=!0,i=v}finally{try{e||null==s.return||s.return()}finally{if(n)throw i}}}}},{key:"clearWalls",value:function(){if(!this.state.isRunning){var t=this.state.grid.slice(),e=!0,n=!1,i=void 0;try{for(var a,s=t[Symbol.iterator]();!(e=(a=s.next()).done);e=!0){var r=a.value,o=!0,l=!1,c=void 0;try{for(var u,d=r[Symbol.iterator]();!(o=(u=d.next()).done);o=!0){var h=u.value;"node node-wall"===document.getElementById("node-".concat(h.row,"-").concat(h.col)).className&&(document.getElementById("node-".concat(h.row,"-").concat(h.col)).className="node",h.isWall=!1)}}catch(f){l=!0,c=f}finally{try{o||null==d.return||d.return()}finally{if(l)throw c}}}}catch(f){n=!0,i=f}finally{try{e||null==s.return||s.return()}finally{if(n)throw i}}}}},{key:"visualize",value:function(t){if(!this.state.isRunning){this.clearGrid(),this.toggleIsRunning();var e,n=this.state.grid,i=n[this.state.START_NODE_ROW][this.state.START_NODE_COL],a=n[this.state.FINISH_NODE_ROW][this.state.FINISH_NODE_COL];switch(t){case"Dijkstra":e=N(n,i,a);break;case"AStar":e=y(n,i,a);break;case"BFS":e=function(t,e,n){for(var i=[],a=[e];a.length;){var s=a.shift();if(s===n)return i;if(!s.isWall&&(s.isStart||!s.isVisited)){s.isVisited=!0,i.push(s);var r=s.col,o=s.row,l=void 0;o>0&&((l=t[o-1][r]).isVisited||(l.previousNode=s,a.push(l))),o0&&((l=t[o][r-1]).isVisited||(l.previousNode=s,a.push(l))),r0&&((l=t[o-1][r]).isVisited||(l.previousNode=s,a.push(l))),o0&&((l=t[o][r-1]).isVisited||(l.previousNode=s,a.push(l))),r onMouseDown(row, col)}\r\n onMouseEnter={() => onMouseEnter(row, col)}\r\n onMouseUp={() => onMouseUp()}>\r\n );\r\n }\r\n}\r\n","// Returns all nodes in the order in which they were visited.\r\n// Make nodes point back to their previous node so that we can compute the shortest path\r\n// by backtracking from the finish node.\r\n\r\nexport function dijkstra(grid, startNode, finishNode) {\r\n const visitedNodesInOrder = [];\r\n startNode.distance = 0;\r\n const unvisitedNodes = getAllNodes(grid); // Q: different from using grid or slice of grid???\r\n\r\n while (unvisitedNodes.length) {\r\n sortNodesByDistance(unvisitedNodes);\r\n const closestNode = unvisitedNodes.shift();\r\n // If we encounter a wall, we skip it.\r\n if (!closestNode.isWall) {\r\n // If the closest node is at a distance of infinity,\r\n // we must be trapped and should stop.\r\n if (closestNode.distance === Infinity) return visitedNodesInOrder;\r\n closestNode.isVisited = true;\r\n visitedNodesInOrder.push(closestNode);\r\n if (closestNode === finishNode) return visitedNodesInOrder;\r\n updateUnvisitedNeighbors(closestNode, grid);\r\n }\r\n }\r\n}\r\n\r\nfunction getAllNodes(grid) {\r\n const nodes = [];\r\n for (const row of grid) {\r\n for (const node of row) {\r\n nodes.push(node);\r\n }\r\n }\r\n return nodes;\r\n}\r\n\r\nfunction sortNodesByDistance(unvisitedNodes) {\r\n unvisitedNodes.sort((nodeA, nodeB) => nodeA.distance - nodeB.distance);\r\n}\r\n\r\nfunction updateUnvisitedNeighbors(node, grid) {\r\n const unvisitedNeighbors = getUnvisitedNeighbors(node, grid);\r\n for (const neighbor of unvisitedNeighbors) {\r\n neighbor.distance = node.distance + 1;\r\n neighbor.previousNode = node;\r\n }\r\n}\r\n\r\nfunction getUnvisitedNeighbors(node, grid) {\r\n const neighbors = [];\r\n const {col, row} = node;\r\n if (row > 0) neighbors.push(grid[row - 1][col]);\r\n if (row < grid.length - 1) neighbors.push(grid[row + 1][col]);\r\n if (col > 0) neighbors.push(grid[row][col - 1]);\r\n if (col < grid[0].length - 1) neighbors.push(grid[row][col + 1]);\r\n return neighbors.filter(neighbor => !neighbor.isVisited);\r\n}\r\n","// Returns all nodes in the order in which they were visited.\r\n// Make nodes point back to their previous node so that we can compute the shortest path\r\n// by backtracking from the finish node.\r\n\r\nexport function AStar(grid, startNode, finishNode) {\r\n const visitedNodesInOrder = [];\r\n startNode.distance = 0;\r\n const unvisitedNodes = getAllNodes(grid); // Q: different from using grid or slice of grid???\r\n\r\n while (unvisitedNodes.length) {\r\n sortByDistance(unvisitedNodes);\r\n const closestNode = unvisitedNodes.shift();\r\n // If we encounter a wall, we skip it.\r\n if (!closestNode.isWall) {\r\n // If the closest node is at a distance of infinity,\r\n // we must be trapped and should stop.\r\n if (closestNode.distance === Infinity) return visitedNodesInOrder;\r\n closestNode.isVisited = true;\r\n visitedNodesInOrder.push(closestNode);\r\n if (closestNode === finishNode) return visitedNodesInOrder;\r\n updateUnvisitedNeighbors(closestNode, grid);\r\n }\r\n }\r\n}\r\n\r\nfunction getAllNodes(grid) {\r\n const nodes = [];\r\n for (const row of grid) {\r\n for (const node of row) {\r\n nodes.push(node);\r\n }\r\n }\r\n return nodes;\r\n}\r\n\r\nfunction sortByDistance(unvisitedNodes) {\r\n unvisitedNodes.sort((nodeA, nodeB) => nodeA.distance - nodeB.distance);\r\n}\r\n\r\nfunction updateUnvisitedNeighbors(node, grid) {\r\n const unvisitedNeighbors = getUnvisitedNeighbors(node, grid);\r\n for (const neighbor of unvisitedNeighbors) {\r\n neighbor.distance = node.distance + 1 + neighbor.distanceToFinishNode;\r\n neighbor.previousNode = node;\r\n }\r\n}\r\n\r\nfunction getUnvisitedNeighbors(node, grid) {\r\n const neighbors = [];\r\n const {col, row} = node;\r\n if (row > 0) neighbors.push(grid[row - 1][col]);\r\n if (row < grid.length - 1) neighbors.push(grid[row + 1][col]);\r\n if (col > 0) neighbors.push(grid[row][col - 1]);\r\n if (col < grid[0].length - 1) neighbors.push(grid[row][col + 1]);\r\n return neighbors.filter(neighbor => !neighbor.isVisited);\r\n}\r\n","import React, {Component} from 'react';\r\nimport Node from './Node/Node';\r\nimport {dijkstra} from '../algorithms/dijkstra';\r\nimport {AStar} from '../algorithms/aStar';\r\nimport {dfs} from '../algorithms/dfs';\r\nimport {bfs} from '../algorithms/bfs';\r\n\r\nimport './PathfindingVisualizer.css';\r\n\r\nexport default class PathfindingVisualizer extends Component {\r\n constructor() {\r\n super();\r\n this.state = {\r\n grid: [],\r\n START_NODE_ROW: 5,\r\n FINISH_NODE_ROW: 5,\r\n START_NODE_COL: 5,\r\n FINISH_NODE_COL: 15,\r\n mouseIsPressed: false,\r\n ROW_COUNT: 25,\r\n COLUMN_COUNT: 35,\r\n MOBILE_ROW_COUNT: 10,\r\n MOBILE_COLUMN_COUNT: 20,\r\n isRunning: false,\r\n isStartNode: false,\r\n isFinishNode: false,\r\n isWallNode: false, // xxxxxxx\r\n currRow: 0,\r\n currCol: 0,\r\n isDesktopView: true,\r\n };\r\n\r\n this.handleMouseDown = this.handleMouseDown.bind(this);\r\n this.handleMouseLeave = this.handleMouseLeave.bind(this);\r\n this.toggleIsRunning = this.toggleIsRunning.bind(this);\r\n }\r\n\r\n componentDidMount() {\r\n const grid = this.getInitialGrid();\r\n this.setState({grid});\r\n }\r\n\r\n toggleIsRunning() {\r\n this.setState({isRunning: !this.state.isRunning});\r\n }\r\n\r\n toggleView() {\r\n if (!this.state.isRunning) {\r\n this.clearGrid();\r\n this.clearWalls();\r\n const isDesktopView = !this.state.isDesktopView;\r\n let grid;\r\n if (isDesktopView) {\r\n grid = this.getInitialGrid(\r\n this.state.ROW_COUNT,\r\n this.state.COLUMN_COUNT,\r\n );\r\n this.setState({isDesktopView, grid});\r\n } else {\r\n if (\r\n this.state.START_NODE_ROW > this.state.MOBILE_ROW_COUNT ||\r\n this.state.FINISH_NODE_ROW > this.state.MOBILE_ROW_COUNT ||\r\n this.state.START_NODE_COL > this.state.MOBILE_COLUMN_COUNT ||\r\n this.state.FINISH_NODE_COL > this.state.MOBILE_COLUMN_COUNT\r\n ) {\r\n alert('Start & Finish Nodes Must Be within 10 Rows x 20 Columns');\r\n } else {\r\n grid = this.getInitialGrid(\r\n this.state.MOBILE_ROW_COUNT,\r\n this.state.MOBILE_COLUMN_COUNT,\r\n );\r\n this.setState({isDesktopView, grid});\r\n }\r\n }\r\n }\r\n }\r\n\r\n /******************** Set up the initial grid ********************/\r\n getInitialGrid = (\r\n rowCount = this.state.ROW_COUNT,\r\n colCount = this.state.COLUMN_COUNT,\r\n ) => {\r\n const initialGrid = [];\r\n for (let row = 0; row < rowCount; row++) {\r\n const currentRow = [];\r\n for (let col = 0; col < colCount; col++) {\r\n currentRow.push(this.createNode(row, col));\r\n }\r\n initialGrid.push(currentRow);\r\n }\r\n return initialGrid;\r\n };\r\n\r\n createNode = (row, col) => {\r\n return {\r\n row,\r\n col,\r\n isStart:\r\n row === this.state.START_NODE_ROW && col === this.state.START_NODE_COL,\r\n isFinish:\r\n row === this.state.FINISH_NODE_ROW &&\r\n col === this.state.FINISH_NODE_COL,\r\n distance: Infinity,\r\n distanceToFinishNode:\r\n Math.abs(this.state.FINISH_NODE_ROW - row) +\r\n Math.abs(this.state.FINISH_NODE_COL - col),\r\n isVisited: false,\r\n isWall: false,\r\n previousNode: null,\r\n isNode: true,\r\n };\r\n };\r\n\r\n /******************** Control mouse events ********************/\r\n handleMouseDown(row, col) {\r\n if (!this.state.isRunning) {\r\n if (this.isGridClear()) {\r\n if (\r\n document.getElementById(`node-${row}-${col}`).className ===\r\n 'node node-start'\r\n ) {\r\n this.setState({\r\n mouseIsPressed: true,\r\n isStartNode: true,\r\n currRow: row,\r\n currCol: col,\r\n });\r\n } else if (\r\n document.getElementById(`node-${row}-${col}`).className ===\r\n 'node node-finish'\r\n ) {\r\n this.setState({\r\n mouseIsPressed: true,\r\n isFinishNode: true,\r\n currRow: row,\r\n currCol: col,\r\n });\r\n } else {\r\n const newGrid = getNewGridWithWallToggled(this.state.grid, row, col);\r\n this.setState({\r\n grid: newGrid,\r\n mouseIsPressed: true,\r\n isWallNode: true,\r\n currRow: row,\r\n currCol: col,\r\n });\r\n }\r\n } else {\r\n this.clearGrid();\r\n }\r\n }\r\n }\r\n\r\n isGridClear() {\r\n for (const row of this.state.grid) {\r\n for (const node of row) {\r\n const nodeClassName = document.getElementById(\r\n `node-${node.row}-${node.col}`,\r\n ).className;\r\n if (\r\n nodeClassName === 'node node-visited' ||\r\n nodeClassName === 'node node-shortest-path'\r\n ) {\r\n return false;\r\n }\r\n }\r\n }\r\n return true;\r\n }\r\n\r\n handleMouseEnter(row, col) {\r\n if (!this.state.isRunning) {\r\n if (this.state.mouseIsPressed) {\r\n const nodeClassName = document.getElementById(`node-${row}-${col}`)\r\n .className;\r\n if (this.state.isStartNode) {\r\n if (nodeClassName !== 'node node-wall') {\r\n const prevStartNode = this.state.grid[this.state.currRow][\r\n this.state.currCol\r\n ];\r\n prevStartNode.isStart = false;\r\n document.getElementById(\r\n `node-${this.state.currRow}-${this.state.currCol}`,\r\n ).className = 'node';\r\n\r\n this.setState({currRow: row, currCol: col});\r\n const currStartNode = this.state.grid[row][col];\r\n currStartNode.isStart = true;\r\n document.getElementById(`node-${row}-${col}`).className =\r\n 'node node-start';\r\n }\r\n this.setState({START_NODE_ROW: row, START_NODE_COL: col});\r\n } else if (this.state.isFinishNode) {\r\n if (nodeClassName !== 'node node-wall') {\r\n const prevFinishNode = this.state.grid[this.state.currRow][\r\n this.state.currCol\r\n ];\r\n prevFinishNode.isFinish = false;\r\n document.getElementById(\r\n `node-${this.state.currRow}-${this.state.currCol}`,\r\n ).className = 'node';\r\n\r\n this.setState({currRow: row, currCol: col});\r\n const currFinishNode = this.state.grid[row][col];\r\n currFinishNode.isFinish = true;\r\n document.getElementById(`node-${row}-${col}`).className =\r\n 'node node-finish';\r\n }\r\n this.setState({FINISH_NODE_ROW: row, FINISH_NODE_COL: col});\r\n } else if (this.state.isWallNode) {\r\n const newGrid = getNewGridWithWallToggled(this.state.grid, row, col);\r\n this.setState({grid: newGrid});\r\n }\r\n }\r\n }\r\n }\r\n\r\n handleMouseUp(row, col) {\r\n if (!this.state.isRunning) {\r\n this.setState({mouseIsPressed: false});\r\n if (this.state.isStartNode) {\r\n const isStartNode = !this.state.isStartNode;\r\n this.setState({isStartNode, START_NODE_ROW: row, START_NODE_COL: col});\r\n } else if (this.state.isFinishNode) {\r\n const isFinishNode = !this.state.isFinishNode;\r\n this.setState({\r\n isFinishNode,\r\n FINISH_NODE_ROW: row,\r\n FINISH_NODE_COL: col,\r\n });\r\n }\r\n this.getInitialGrid();\r\n }\r\n }\r\n\r\n handleMouseLeave() {\r\n if (this.state.isStartNode) {\r\n const isStartNode = !this.state.isStartNode;\r\n this.setState({isStartNode, mouseIsPressed: false});\r\n } else if (this.state.isFinishNode) {\r\n const isFinishNode = !this.state.isFinishNode;\r\n this.setState({isFinishNode, mouseIsPressed: false});\r\n } else if (this.state.isWallNode) {\r\n const isWallNode = !this.state.isWallNode;\r\n this.setState({isWallNode, mouseIsPressed: false});\r\n this.getInitialGrid();\r\n }\r\n }\r\n\r\n /******************** Clear Board/Walls ********************/\r\n\r\n clearGrid() {\r\n if (!this.state.isRunning) {\r\n const newGrid = this.state.grid.slice();\r\n for (const row of newGrid) {\r\n for (const node of row) {\r\n let nodeClassName = document.getElementById(\r\n `node-${node.row}-${node.col}`,\r\n ).className;\r\n if (\r\n nodeClassName !== 'node node-start' &&\r\n nodeClassName !== 'node node-finish' &&\r\n nodeClassName !== 'node node-wall'\r\n ) {\r\n document.getElementById(`node-${node.row}-${node.col}`).className =\r\n 'node';\r\n node.isVisited = false;\r\n node.distance = Infinity;\r\n node.distanceToFinishNode =\r\n Math.abs(this.state.FINISH_NODE_ROW - node.row) +\r\n Math.abs(this.state.FINISH_NODE_COL - node.col);\r\n }\r\n if (nodeClassName === 'node node-finish') {\r\n node.isVisited = false;\r\n node.distance = Infinity;\r\n node.distanceToFinishNode = 0;\r\n }\r\n if (nodeClassName === 'node node-start') {\r\n node.isVisited = false;\r\n node.distance = Infinity;\r\n node.distanceToFinishNode =\r\n Math.abs(this.state.FINISH_NODE_ROW - node.row) +\r\n Math.abs(this.state.FINISH_NODE_COL - node.col);\r\n node.isStart = true;\r\n node.isWall = false;\r\n node.previousNode = null;\r\n node.isNode = true;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n clearWalls() {\r\n if (!this.state.isRunning) {\r\n const newGrid = this.state.grid.slice();\r\n for (const row of newGrid) {\r\n for (const node of row) {\r\n let nodeClassName = document.getElementById(\r\n `node-${node.row}-${node.col}`,\r\n ).className;\r\n if (nodeClassName === 'node node-wall') {\r\n document.getElementById(`node-${node.row}-${node.col}`).className =\r\n 'node';\r\n node.isWall = false;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n /******************** Create Animations ********************/\r\n visualize(algo) {\r\n if (!this.state.isRunning) {\r\n this.clearGrid();\r\n this.toggleIsRunning();\r\n const {grid} = this.state;\r\n const startNode =\r\n grid[this.state.START_NODE_ROW][this.state.START_NODE_COL];\r\n const finishNode =\r\n grid[this.state.FINISH_NODE_ROW][this.state.FINISH_NODE_COL];\r\n let visitedNodesInOrder;\r\n switch (algo) {\r\n case 'Dijkstra':\r\n visitedNodesInOrder = dijkstra(grid, startNode, finishNode);\r\n break;\r\n case 'AStar':\r\n visitedNodesInOrder = AStar(grid, startNode, finishNode);\r\n break;\r\n case 'BFS':\r\n visitedNodesInOrder = bfs(grid, startNode, finishNode);\r\n break;\r\n case 'DFS':\r\n visitedNodesInOrder = dfs(grid, startNode, finishNode);\r\n break;\r\n default:\r\n // should never get here\r\n break;\r\n }\r\n const nodesInShortestPathOrder = getNodesInShortestPathOrder(finishNode);\r\n nodesInShortestPathOrder.push('end');\r\n this.animate(visitedNodesInOrder, nodesInShortestPathOrder);\r\n }\r\n }\r\n\r\n animate(visitedNodesInOrder, nodesInShortestPathOrder) {\r\n for (let i = 0; i <= visitedNodesInOrder.length; i++) {\r\n if (i === visitedNodesInOrder.length) {\r\n setTimeout(() => {\r\n this.animateShortestPath(nodesInShortestPathOrder);\r\n }, 10 * i);\r\n return;\r\n }\r\n setTimeout(() => {\r\n const node = visitedNodesInOrder[i];\r\n const nodeClassName = document.getElementById(\r\n `node-${node.row}-${node.col}`,\r\n ).className;\r\n if (\r\n nodeClassName !== 'node node-start' &&\r\n nodeClassName !== 'node node-finish'\r\n ) {\r\n document.getElementById(`node-${node.row}-${node.col}`).className =\r\n 'node node-visited';\r\n }\r\n }, 10 * i);\r\n }\r\n }\r\n\r\n /******************** Create path from start to finish ********************/\r\n animateShortestPath(nodesInShortestPathOrder) {\r\n for (let i = 0; i < nodesInShortestPathOrder.length; i++) {\r\n if (nodesInShortestPathOrder[i] === 'end') {\r\n setTimeout(() => {\r\n this.toggleIsRunning();\r\n }, i * 50);\r\n } else {\r\n setTimeout(() => {\r\n const node = nodesInShortestPathOrder[i];\r\n const nodeClassName = document.getElementById(\r\n `node-${node.row}-${node.col}`,\r\n ).className;\r\n if (\r\n nodeClassName !== 'node node-start' &&\r\n nodeClassName !== 'node node-finish'\r\n ) {\r\n document.getElementById(`node-${node.row}-${node.col}`).className =\r\n 'node node-shortest-path';\r\n }\r\n }, i * 40);\r\n }\r\n }\r\n }\r\n\r\n render() {\r\n const {grid, mouseIsPressed} = this.state;\r\n return (\r\n
\r\n );\r\n }\r\n}\r\n\r\n/******************** Create Walls ********************/\r\nconst getNewGridWithWallToggled = (grid, row, col) => {\r\n // mouseDown starts to act strange if I don't make newGrid and work off of grid instead.\r\n const newGrid = grid.slice();\r\n const node = newGrid[row][col];\r\n if (!node.isStart && !node.isFinish && node.isNode) {\r\n const newNode = {\r\n ...node,\r\n isWall: !node.isWall,\r\n };\r\n newGrid[row][col] = newNode;\r\n }\r\n return newGrid;\r\n};\r\n\r\n// Backtracks from the finishNode to find the shortest path.\r\n// Only works when called after the pathfinding methods.\r\nfunction getNodesInShortestPathOrder(finishNode) {\r\n const nodesInShortestPathOrder = [];\r\n let currentNode = finishNode;\r\n while (currentNode !== null) {\r\n nodesInShortestPathOrder.unshift(currentNode);\r\n currentNode = currentNode.previousNode;\r\n }\r\n return nodesInShortestPathOrder;\r\n}\r\n","// Returns all nodes in the order in which they were visited.\r\n// Make nodes point back to their previous node so that we can compute the shortest path\r\n// by backtracking from the finish node.\r\n\r\nexport function bfs(grid, startNode, finishNode) {\r\n const visitedNodesInOrder = [];\r\n let nextNodesStack = [startNode];\r\n while (nextNodesStack.length) {\r\n const currentNode = nextNodesStack.shift();\r\n if (currentNode === finishNode) return visitedNodesInOrder;\r\n\r\n if (\r\n !currentNode.isWall &&\r\n (currentNode.isStart || !currentNode.isVisited)\r\n ) {\r\n currentNode.isVisited = true;\r\n visitedNodesInOrder.push(currentNode);\r\n const {col, row} = currentNode;\r\n let nextNode;\r\n if (row > 0) {\r\n nextNode = grid[row - 1][col];\r\n if (!nextNode.isVisited) {\r\n nextNode.previousNode = currentNode;\r\n nextNodesStack.push(nextNode);\r\n }\r\n }\r\n if (row < grid.length - 1) {\r\n nextNode = grid[row + 1][col];\r\n if (!nextNode.isVisited) {\r\n nextNode.previousNode = currentNode;\r\n nextNodesStack.push(nextNode);\r\n }\r\n }\r\n if (col > 0) {\r\n nextNode = grid[row][col - 1];\r\n if (!nextNode.isVisited) {\r\n nextNode.previousNode = currentNode;\r\n nextNodesStack.push(nextNode);\r\n }\r\n }\r\n if (col < grid[0].length - 1) {\r\n nextNode = grid[row][col + 1];\r\n if (!nextNode.isVisited) {\r\n nextNode.previousNode = currentNode;\r\n nextNodesStack.push(nextNode);\r\n }\r\n }\r\n }\r\n }\r\n // return visitedNodesInOrder;\r\n}\r\n","// Returns all nodes in the order in which they were visited.\r\n// Make nodes point back to their previous node so that we can compute the shortest path\r\n// by backtracking from the finish node.\r\n\r\nexport function dfs(grid, startNode, finishNode) {\r\n const visitedNodesInOrder = [];\r\n const nextNodesStack = [];\r\n nextNodesStack.push(startNode);\r\n while (nextNodesStack.length) {\r\n const currentNode = nextNodesStack.pop();\r\n\r\n if (currentNode === finishNode) {\r\n return visitedNodesInOrder;\r\n }\r\n\r\n if (\r\n !currentNode.isWall &&\r\n (currentNode.isStart || !currentNode.isVisited)\r\n ) {\r\n currentNode.isVisited = true;\r\n visitedNodesInOrder.push(currentNode);\r\n\r\n const {col, row} = currentNode;\r\n let nextNode;\r\n if (row > 0) {\r\n nextNode = grid[row - 1][col];\r\n if (!nextNode.isVisited) {\r\n nextNode.previousNode = currentNode;\r\n nextNodesStack.push(nextNode);\r\n }\r\n }\r\n if (row < grid.length - 1) {\r\n nextNode = grid[row + 1][col];\r\n if (!nextNode.isVisited) {\r\n nextNode.previousNode = currentNode;\r\n nextNodesStack.push(nextNode);\r\n }\r\n }\r\n if (col > 0) {\r\n nextNode = grid[row][col - 1];\r\n if (!nextNode.isVisited) {\r\n nextNode.previousNode = currentNode;\r\n nextNodesStack.push(nextNode);\r\n }\r\n }\r\n if (col < grid[0].length - 1) {\r\n nextNode = grid[row][col + 1];\r\n if (!nextNode.isVisited) {\r\n nextNode.previousNode = currentNode;\r\n nextNodesStack.push(nextNode);\r\n }\r\n }\r\n }\r\n }\r\n}\r\n","import React from 'react';\r\nimport './App.css';\r\nimport PathfindingVisualizer from './PathfindingVisualizer/PathfindingVisualizer';\r\n\r\nfunction App() {\r\n return (\r\n
\r\n \r\n
\r\n );\r\n}\r\n\r\nexport default App;\r\n","// This optional code is used to register a service worker.\r\n// register() is not called by default.\r\n\r\n// This lets the app load faster on subsequent visits in production, and gives\r\n// it offline capabilities. However, it also means that developers (and users)\r\n// will only see deployed updates on subsequent visits to a page, after all the\r\n// existing tabs open on the page have been closed, since previously cached\r\n// resources are updated in the background.\r\n\r\n// To learn more about the benefits of this model and instructions on how to\r\n// opt-in, read https://bit.ly/CRA-PWA\r\n\r\nconst isLocalhost = Boolean(\r\n window.location.hostname === 'localhost' ||\r\n // [::1] is the IPv6 localhost address.\r\n window.location.hostname === '[::1]' ||\r\n // 127.0.0.1/8 is considered localhost for IPv4.\r\n window.location.hostname.match(\r\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\r\n )\r\n);\r\n\r\nexport function register(config) {\r\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\r\n // The URL constructor is available in all browsers that support SW.\r\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);\r\n if (publicUrl.origin !== window.location.origin) {\r\n // Our service worker won't work if PUBLIC_URL is on a different origin\r\n // from what our page is served on. This might happen if a CDN is used to\r\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\r\n return;\r\n }\r\n\r\n window.addEventListener('load', () => {\r\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\r\n\r\n if (isLocalhost) {\r\n // This is running on localhost. Let's check if a service worker still exists or not.\r\n checkValidServiceWorker(swUrl, config);\r\n\r\n // Add some additional logging to localhost, pointing developers to the\r\n // service worker/PWA documentation.\r\n navigator.serviceWorker.ready.then(() => {\r\n console.log(\r\n 'This web app is being served cache-first by a service ' +\r\n 'worker. To learn more, visit https://bit.ly/CRA-PWA'\r\n );\r\n });\r\n } else {\r\n // Is not localhost. Just register service worker\r\n registerValidSW(swUrl, config);\r\n }\r\n });\r\n }\r\n}\r\n\r\nfunction registerValidSW(swUrl, config) {\r\n navigator.serviceWorker\r\n .register(swUrl)\r\n .then(registration => {\r\n registration.onupdatefound = () => {\r\n const installingWorker = registration.installing;\r\n if (installingWorker == null) {\r\n return;\r\n }\r\n installingWorker.onstatechange = () => {\r\n if (installingWorker.state === 'installed') {\r\n if (navigator.serviceWorker.controller) {\r\n // At this point, the updated precached content has been fetched,\r\n // but the previous service worker will still serve the older\r\n // content until all client tabs are closed.\r\n console.log(\r\n 'New content is available and will be used when all ' +\r\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\r\n );\r\n\r\n // Execute callback\r\n if (config && config.onUpdate) {\r\n config.onUpdate(registration);\r\n }\r\n } else {\r\n // At this point, everything has been precached.\r\n // It's the perfect time to display a\r\n // \"Content is cached for offline use.\" message.\r\n console.log('Content is cached for offline use.');\r\n\r\n // Execute callback\r\n if (config && config.onSuccess) {\r\n config.onSuccess(registration);\r\n }\r\n }\r\n }\r\n };\r\n };\r\n })\r\n .catch(error => {\r\n console.error('Error during service worker registration:', error);\r\n });\r\n}\r\n\r\nfunction checkValidServiceWorker(swUrl, config) {\r\n // Check if the service worker can be found. If it can't reload the page.\r\n fetch(swUrl)\r\n .then(response => {\r\n // Ensure service worker exists, and that we really are getting a JS file.\r\n const contentType = response.headers.get('content-type');\r\n if (\r\n response.status === 404 ||\r\n (contentType != null && contentType.indexOf('javascript') === -1)\r\n ) {\r\n // No service worker found. Probably a different app. Reload the page.\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister().then(() => {\r\n window.location.reload();\r\n });\r\n });\r\n } else {\r\n // Service worker found. Proceed as normal.\r\n registerValidSW(swUrl, config);\r\n }\r\n })\r\n .catch(() => {\r\n console.log(\r\n 'No internet connection found. App is running in offline mode.'\r\n );\r\n });\r\n}\r\n\r\nexport function unregister() {\r\n if ('serviceWorker' in navigator) {\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister();\r\n });\r\n }\r\n}\r\n","import React from 'react';\r\nimport ReactDOM from 'react-dom';\r\nimport './index.css';\r\nimport App from './App';\r\nimport * as serviceWorker from './serviceWorker';\r\n\r\nReactDOM.render(, document.getElementById('root'));\r\n\r\n// If you want your app to work offline and load faster, you can change\r\n// unregister() to register() below. Note this comes with some pitfalls.\r\n// Learn more about service workers: https://bit.ly/CRA-PWA\r\nserviceWorker.unregister();\r\n"],"sourceRoot":""}
--------------------------------------------------------------------------------
/build/static/js/runtime-main.0f354abe.js:
--------------------------------------------------------------------------------
1 | !function(e){function r(r){for(var n,p,a=r[0],i=r[1],l=r[2],c=0,s=[];c0.2%",
25 | "not dead",
26 | "not op_mini all"
27 | ],
28 | "development": [
29 | "last 1 chrome version",
30 | "last 1 firefox version",
31 | "last 1 safari version"
32 | ]
33 | },
34 | "devDependencies": {
35 | "gh-pages": "^3.1.0"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PrudhviGNV/pathFinderVisualizer/178c7d4660600c2b8684e38d3a3df554f82c222d/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 |
15 |
16 |
20 |
21 |
30 | PathFinder Visualizer - React App
31 |
32 |
38 |
39 |
40 |
100 |
101 |
102 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |