Skip to content

Commit 8c6bb8d

Browse files
committed
added files
2 parents 3ea9acc + 1cea674 commit 8c6bb8d

File tree

12 files changed

+28227
-0
lines changed

12 files changed

+28227
-0
lines changed

package-lock.json

Lines changed: 27598 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"name": "algorithm-visualiser",
3+
"version": "0.1.0",
4+
"homepage": "https://gaelgil.github.io/algorithm-visualizer/",
5+
"private": true,
6+
"dependencies": {
7+
"@testing-library/jest-dom": "^5.16.4",
8+
"@testing-library/react": "^13.1.1",
9+
"@testing-library/user-event": "^13.5.0",
10+
"http-parser": "^1.0.3",
11+
"jquery": "^3.6.0",
12+
"mocha": "^10.0.0",
13+
"react": "^18.0.0",
14+
"react-dom": "^18.0.0",
15+
"react-scripts": "^2.1.3",
16+
"web-vitals": "^2.1.4"
17+
},
18+
"scripts": {
19+
"predeploy": "npm run build",
20+
"deploy": "gh-pages -d build",
21+
"start": "export SET NODE_OPTIONS=--openssl-legacy-provider && react-scripts start",
22+
"build": "react-scripts build",
23+
"eject": "react-scripts eject"
24+
},
25+
"eslintConfig": {
26+
"extends": [
27+
"react-app",
28+
"react-app/jest"
29+
]
30+
},
31+
"browserslist": {
32+
"production": [
33+
">0.2%",
34+
"not dead",
35+
"not op_mini all"
36+
],
37+
"development": [
38+
"last 1 chrome version",
39+
"last 1 firefox version",
40+
"last 1 safari version"
41+
]
42+
},
43+
"devDependencies": {
44+
"gh-pages": "^6.3.0"
45+
}
46+
}

public/index.html

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
<meta name="theme-color" content="#000000" />
8+
<meta
9+
name="description"
10+
content="Web site created using create-react-app"
11+
/>
12+
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> -->
13+
<!--
14+
manifest.json provides metadata used when your web app is installed on a
15+
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
16+
-->
17+
<!-- <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> -->
18+
<!--
19+
Notice the use of %PUBLIC_URL% in the tags above.
20+
It will be replaced with the URL of the `public` folder during the build.
21+
Only files inside the `public` folder can be referenced from the HTML.
22+
23+
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
24+
work correctly both with client-side routing and a non-root public URL.
25+
Learn how to configure a non-root public URL by running `npm run build`.
26+
-->
27+
<title>Algorithm Vizualiser</title>
28+
</head>
29+
<body>
30+
<!-- <noscript>You need to enable JavaScript to run this app.</noscript> -->
31+
<div id="root"></div>
32+
<!--
33+
This HTML file is a template.
34+
If you open it directly in the browser, you will see an empty page.
35+
36+
You can add webfonts, meta tags, or analytics to this file.
37+
The build step will place the bundled scripts into the <body> tag.
38+
39+
To begin the development, run `npm start` or `yarn start`.
40+
To create a production bundle, use `npm run build` or `yarn build`.
41+
-->
42+
</body>
43+
</html>

src/App.css

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
body {
2+
margin: 0;
3+
padding: 0;
4+
background-color: #282c34;
5+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
6+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
7+
sans-serif;
8+
-webkit-font-smoothing: antialiased;
9+
-moz-osx-font-smoothing: grayscale;
10+
}
11+
12+
13+
14+
code {
15+
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
16+
monospace;
17+
}

src/App.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React, { useState } from 'react';
2+
import './App.css';
3+
import SortingVisualiser from './components/SortingVisualiser/SortingVisualiser';
4+
import GraphTraversalVisualiser from './components/GraphTraversalVisualiser/GraphTraversalVisualiser';
5+
import NavBar from './components/NavBar/navbar'
6+
7+
function App() {
8+
const [currentView, setCurrentView] = useState('sorting'); // Default to sorting visualization
9+
10+
const handleViewChange = (view) => {
11+
setCurrentView(view);
12+
};
13+
14+
return (
15+
<div className="App">
16+
<NavBar onNavigate={handleViewChange} />
17+
{currentView === 'sorting' ? <SortingVisualiser /> : null}
18+
{currentView === 'traversal' ? <GraphTraversalVisualiser /> : null}
19+
</div>
20+
);
21+
}
22+
23+
export default App;
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import React, { useState, useEffect } from 'react';
2+
import "./GraphTraversalVisualiser.css"
3+
import { UCS } from './graphAlgorithms/ucs';
4+
import { BFS } from './graphAlgorithms/bfs';
5+
import { DFS } from './graphAlgorithms/dfs';
6+
import { conflict } from './graphAlgorithms/helper';
7+
8+
const MatrixVisualization = () => {
9+
const [matrix, setMatrix] = useState([]);
10+
const [start, setStart] = useState({ row: 0, col: 0 });
11+
const [objectives, setObjectives] = useState([]);
12+
// const [weights, setWeights] = useState([]);
13+
const [obstacles, setObstacles] = useState([]);
14+
const [algorithm, setAlgorithm] = useState('Reset');
15+
const [button, setButton] = useState(false);
16+
17+
18+
useEffect(() => {
19+
generateMatrix();
20+
}, []);
21+
22+
23+
24+
25+
// generate a new matrix
26+
const generateMatrix = () => {
27+
const n = 30
28+
const newMatrix = Array.from({ length: n }, () => Array(n).fill(" ")); // generate array
29+
const objectivesArray = []; // array to hold bojectives
30+
const obstaclesArray = []; // array to hold obstacles
31+
const indices = {}; // dictionary to hold indicies to avoid overlap
32+
const numObjectives = 2; // number of objectives
33+
const numObstacles = 100; // number of obstacles
34+
let x = Math.floor(Math.random() * (newMatrix.length)); // a random x cord
35+
let y = Math.floor(Math.random() * (newMatrix[0].length)); // a randon y cord
36+
setStart({ row: x, col: y }); // set the starting point
37+
indices[`${x},${y}`] = 0; // add starting point to indices
38+
39+
// generate the map
40+
while (Object.keys(indices).length < numObjectives + numObstacles) {
41+
x = Math.floor(Math.random() * (newMatrix.length)); // new x cord
42+
y = Math.floor(Math.random() * (newMatrix[0].length)); // new y cord
43+
44+
if (indices.hasOwnProperty(`${x},${y}`)) { // if its an index we have been do ignore it
45+
continue;
46+
} else {
47+
if (Object.keys(indices).length > numObjectives - 1) {
48+
if (conflict(x, y, newMatrix)) { // if there is a conflic ignore the index
49+
continue;
50+
} else {
51+
obstaclesArray.push({ row: x, col: y }); // add to obstacles
52+
indices[`${x},${y}`] = 0;
53+
newMatrix[x][y] = "w";
54+
}
55+
} else {
56+
objectivesArray.push({ row: x, col: y }); // add to objectives
57+
indices[`${x},${y}`] = 0;
58+
}
59+
}
60+
}
61+
// set the approriate obstacles, objectives and new matrix/grid
62+
setObjectives(objectivesArray);
63+
setObstacles(obstaclesArray);
64+
// setWeights(weightsArray);
65+
setMatrix(newMatrix);
66+
};
67+
68+
// reset the matrix
69+
const resetMatrix = () => {
70+
clearPath(); // remove the previously drawn path
71+
generateMatrix(); // generate a new matrix
72+
};
73+
74+
const colorNodes = (path, expanded) => {
75+
path.forEach(node => {
76+
const [row, col] = node;
77+
const nodeElement = document.querySelector(`.matrix-row-${row} .col-index-${col}`);
78+
if (nodeElement) {
79+
if (!(nodeElement.classList.contains('objective')) && !(nodeElement.classList.contains('start'))){
80+
nodeElement.classList.add('path');
81+
}
82+
}});
83+
84+
if (expanded){
85+
expanded.forEach(node => {
86+
const [row, col] = node;
87+
const nodeElement = document.querySelector(`.matrix-row-${row} .col-index-${col}`);
88+
if (nodeElement) {
89+
if (!(nodeElement.classList.contains('path')) && !(nodeElement.classList.contains('objective')) && !(nodeElement.classList.contains('start'))){
90+
nodeElement.classList.add('expanded');
91+
}
92+
}});
93+
}
94+
}
95+
96+
// clear the old path
97+
const clearPath = () => {
98+
const pathNodes = document.querySelectorAll('.path');
99+
pathNodes.forEach((node) => {
100+
node.classList.remove('path');
101+
});
102+
const expandedNodes = document.querySelectorAll('.expanded');
103+
expandedNodes.forEach((node) => {
104+
node.classList.remove('expanded');
105+
});
106+
};
107+
108+
const handleSubmit = (event) => {
109+
let method = algorithm;
110+
if (method === 'astar') {
111+
//
112+
} else if (method === 'BFS') {
113+
// console.log(objectives)
114+
const result = BFS(matrix, [start.row, start.col], [objectives[0].row, objectives[0].col]);
115+
colorNodes(result.path, result.expanded);
116+
} else if (method === 'Reset') {
117+
resetMatrix();
118+
} else if (method === 'DFS') {
119+
const result = DFS(matrix,[start.row, start.col], [objectives[0].row, objectives[0].col]);
120+
colorNodes(result.path, result.expanded);
121+
} else if (method === 'UCS') {
122+
const result = UCS(matrix, [start.row, start.col], [objectives[0].row, objectives[0].col]);
123+
console.log(result.expanded);
124+
colorNodes(result.path, result.expanded);
125+
}
126+
127+
event.preventDefault();
128+
};
129+
130+
const handleChange = (event) => {
131+
setAlgorithm(event.target.value);
132+
};
133+
134+
135+
return (
136+
<div className='GraphTraversalVisualiser'>
137+
<div className="matrix-container">
138+
{matrix.map((row, rowIndex) => (
139+
<div key={rowIndex} className={"matrix-row matrix-row-"+rowIndex }>
140+
{row.map((cell, colIndex) => (
141+
<div
142+
key={colIndex}
143+
className={`matrix-cell ${start.row === rowIndex && start.col === colIndex ? 'start' : ''}
144+
${objectives.some(obj => obj.row === rowIndex && obj.col === colIndex) ? 'objective' : ''}
145+
${obstacles.some(obs => obs.row === rowIndex && obs.col === colIndex) ? 'obstacle' : ''} col-index-${colIndex}`}>
146+
{cell}
147+
</div>
148+
))}
149+
</div>
150+
))}
151+
</div>
152+
<div className='legend'>
153+
<ul>
154+
<li className='start'>Start</li>
155+
<li className='objective'>Objective</li>
156+
<li className='path'>Path</li>
157+
<li className='obstacle white-text'>Obstacle</li>
158+
<li className='expanded'>Expanded Nodes</li>
159+
<li className='weight'>Weighted (ignored for bfs and dfs)</li>
160+
</ul>
161+
</div>
162+
<form onSubmit={handleSubmit}>
163+
<label htmlFor='algorithm' className='label'>
164+
Algorithms:
165+
<select
166+
className='menu'
167+
id='menu'
168+
value={algorithm}
169+
onChange={handleChange}>
170+
<option value='Reset'>Reset Array</option>
171+
<option value='BFS'>BFS</option>
172+
<option value='DFS'>DFS</option>
173+
<option value='UCS'>UCS</option>
174+
<option value='Astar'>Astar</option>
175+
</select>
176+
</label>
177+
<input
178+
style={{ color: 'black' }}
179+
className="btn"
180+
type="submit"
181+
value="Submit"
182+
disabled={button}
183+
/>
184+
</form>
185+
186+
</div>
187+
);
188+
};
189+
190+
export default MatrixVisualization;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { PriorityQueue } from './datastructures/priorityQueue';
2+
import { getNeighbors } from './helper';
3+
4+
5+
6+
7+
export function Astar(grid, start, destination) {
8+
let priorityQueue = new PriorityQueue();
9+
priorityQueue.enqueue({ node: start, path: [start], cost: 0 });
10+
11+
let visited = {};
12+
let expanded = [];
13+
14+
while (!priorityQueue.isEmpty()) {
15+
let { node, path, cost } = priorityQueue.dequeue(); // get the node, its path, and cost from the front of the priority queue
16+
let nodeKey = node.toString(); // to string for comparison
17+
18+
if (nodeKey === destination.toString()) { // check if we have arrived at the solution
19+
return { status: "found", path, cost , expanded};
20+
} else {
21+
if (!(visited.hasOwnProperty(nodeKey))) { // if we have not been to this node, add it
22+
visited[nodeKey] = true; // mark as visited
23+
let neighbors = getNeighbors(grid, node); // get neighbors of the current node
24+
for (let i = 0; i < neighbors.length; i++) {
25+
let neighbor = neighbors[i];
26+
let neighborKey = neighbor.toString();
27+
let neighborCost = cost
28+
if (grid[neighbor[0]][neighbor[1]] === "e"){
29+
neighborCost += 5;
30+
}else {
31+
neighborCost +=1;
32+
};
33+
34+
if (!(visited.hasOwnProperty(neighborKey))) { // if the neighbor has not been visited, add to the priority queue
35+
if (!(grid[neighbor[0]][neighbor[1]] === "w")) { // if there is no wall, then we add
36+
priorityQueue.enqueue({ node: neighbor, path: path.concat([neighbor]), cost: neighborCost }, neighborCost);
37+
expanded.push(neighbor); // add the expanded node to the list
38+
}
39+
}
40+
}
41+
}
42+
}
43+
}
44+
45+
return { status: "not found", path: [], cost: 0 };
46+
}

0 commit comments

Comments
 (0)