Skip to content

Commit acc8a8c

Browse files
committed
Added Maze generation and Graphs Tab
1 parent afdc193 commit acc8a8c

File tree

8 files changed

+271
-24
lines changed

8 files changed

+271
-24
lines changed

src/App.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import Navbar from "./components/navbar.component";
1010
import React from ".";
1111
import "bootstrap/dist/css/bootstrap.min.css";
12+
import GraphsVisualiser from "./components/GraphsVisualiser";
1213

1314
function App() {
1415
return (
@@ -19,6 +20,7 @@ function App() {
1920

2021
<Route path="/" exact element={<SortingVisualiser/>}/>
2122
<Route path="/path" exact element={<PathFindingVisualiser/>}/>
23+
<Route path="/graphs" exact element={<GraphsVisualiser/>}/>
2224

2325

2426
</Routes>

src/components/GraphNode.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React, {Component} from "react";
2+
3+
export default class GraphNode extends Component {
4+
5+
constructor(props) {
6+
super(props);
7+
this.state = {};
8+
}
9+
10+
render() {
11+
12+
const {
13+
col,
14+
isFinish,
15+
isStart,
16+
isWall,
17+
onMouseDown,
18+
onMouseEnter,
19+
onMouseUp,
20+
row,
21+
} = this.props;
22+
const extraClassName = isFinish ? 'node-finish' : isStart ? 'node-start' : isWall ? 'node-wall' : '';
23+
return (
24+
<div
25+
id={`node-${row}-${col}`}
26+
className={`node ${extraClassName}`}
27+
onMouseDown={() => onMouseDown(row, col)}
28+
onMouseEnter={() => onMouseEnter(row, col)}
29+
onMouseUp={() => onMouseUp()}></div>
30+
);
31+
32+
}
33+
}

src/components/GraphsVisualiser.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import React from "react";
2+
3+
4+
export default class GraphsVisualiser extends React.Component {
5+
6+
constructor(props) {
7+
super(props);
8+
9+
this.state = {nodes: [], mouseIsPressed: false, mouseX: 0, mouseY: 0};
10+
11+
this.nodesRef = React.createRef();
12+
}
13+
14+
componentDidMount() {
15+
this.drawNodes();
16+
}
17+
18+
drawNodes() {
19+
const canvas = this.nodesRef.current;
20+
21+
const ctx = canvas.getContext("2d");
22+
23+
ctx.clearRect(0, 0, canvas.width, canvas.height);
24+
25+
ctx.fillStyle = 'lightgrey';
26+
ctx.strokeStyle = 'black';
27+
28+
for (let i = 0; i < this.state.nodes.length; i++) {
29+
ctx.beginPath();
30+
ctx.arc(this.state.nodes[i].x, this.state.nodes[i].y, 20, 0, 2 * Math.PI);
31+
ctx.fill();
32+
ctx.lineWidth = 2;
33+
ctx.stroke();
34+
ctx.closePath();
35+
}
36+
ctx.closePath();
37+
}
38+
39+
addNode = (event) => {
40+
let newX = event.clientX - event.target.offsetLeft;
41+
let newY = event.clientY - event.target.offsetTop;
42+
43+
const nodes2 = this.state.nodes
44+
nodes2.push({x: newX, y: newY});
45+
46+
this.setState({nodes: nodes2});
47+
48+
this.drawNodes();
49+
};
50+
51+
52+
clearNodes = () => {
53+
const canvas = this.nodesRef.current;
54+
55+
const ctx = canvas.getContext("2d");
56+
57+
ctx.clearRect(0, 0, canvas.width, canvas.height);
58+
59+
this.setState({nodes: []});
60+
}
61+
62+
render() {
63+
64+
return (
65+
<div className="graphDiv">
66+
<canvas className="graphCanv" style={{backgroundColor: "whitesmoke"}}
67+
ref={this.nodesRef} width={window.innerWidth} height={window.innerHeight - 200}
68+
onClick={this.addNode}/>
69+
70+
<button onClick={this.clearNodes}>Clear Nodes</button>
71+
</div>);
72+
73+
74+
}
75+
}

src/components/Node.css

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,19 @@
4747
}
4848

4949
.node-wall {
50-
background-color: rgb(12, 53, 71);
50+
animation-name: turnWall;
51+
animation-duration: 1.5s;
52+
animation-timing-function: ease-out;
53+
animation-delay: 0s;
54+
animation-direction: alternate;
55+
animation-iteration-count: 1;
56+
animation-fill-mode: forwards;
57+
animation-play-state: running;
5158
}
5259

5360
.node-shortest-path {
5461
animation-name: shortestPath;
55-
animation-duration: 1.5s;
62+
animation-duration: 0.25s;
5663
animation-timing-function: ease-out;
5764
animation-delay: 0s;
5865
animation-direction: alternate;
@@ -61,6 +68,24 @@
6168
animation-play-state: running;
6269
}
6370

71+
@keyframes turnWall {
72+
0% {
73+
transform: scale(0.6);
74+
background-color: rgb(12, 53, 71);
75+
}
76+
77+
50% {
78+
transform: scale(1.2);
79+
background-color: rgb(12, 53, 71);
80+
}
81+
82+
100% {
83+
transform: scale(1);
84+
background-color: rgb(12, 53, 71);
85+
}
86+
}
87+
88+
6489
@keyframes shortestPath {
6590
0% {
6691
transform: scale(0.6);

src/components/PathFinding.js

Lines changed: 128 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ import "./PathFinding.css";
33
import Node from "./Node";
44
import {dijkstra, getNodesInShortestPathOrder} from '../pathfindingAlgos'
55

6+
const start_row = 3;
7+
const start_col = 5;
8+
9+
const finish_row = 10;
10+
const finish_col = 45;
11+
612
export default class PathFindingVisualiser extends React.Component {
713
constructor(props) {
814
super(props);
@@ -21,8 +27,17 @@ export default class PathFindingVisualiser extends React.Component {
2127
for (let col = 0; col < 50; col++) {
2228

2329

24-
const currNode = {col, row, isStart: row === 11 && col === 5, isFinish: row === 10 && col === 45, distance: Infinity,
25-
isVisited: false, isWall: false, previousNode: null};
30+
const currNode = {
31+
col,
32+
row,
33+
isStart: row === start_row && col === start_col,
34+
isFinish: row === finish_row && col === finish_col,
35+
distance: Infinity,
36+
isVisited: false,
37+
isWall: false,
38+
previousNode: null,
39+
visitedDuringMaze: false
40+
};
2641

2742
currRow.push(currNode);
2843

@@ -56,7 +71,6 @@ export default class PathFindingVisualiser extends React.Component {
5671

5772
}
5873

59-
6074
animateShortestPath(shortestOrder) {
6175
for (let i = 0; i < shortestOrder.length; i++) {
6276
setTimeout(() => {
@@ -67,10 +81,11 @@ export default class PathFindingVisualiser extends React.Component {
6781
}
6882

6983
visualiseDijkstra() {
84+
7085
const grid = this.state.nodes;
7186

72-
const startNode = grid[10][5];
73-
const destNode = grid[10][45];
87+
const startNode = grid[start_row][start_col];
88+
const destNode = grid[finish_row][finish_col];
7489

7590
const visitedNodes = dijkstra(grid, startNode, destNode);
7691

@@ -80,27 +95,113 @@ export default class PathFindingVisualiser extends React.Component {
8095

8196
}
8297

83-
handleMouseDown(row, col){
84-
console.log("down");
85-
const newGrid = getNewGridWithWallToggled(this.state.nodes, row, col);
98+
handleMouseDown(row, col, wallStatus) {
99+
const newGrid = getNewGridWithWallToggled(this.state.nodes, row, col, wallStatus);
86100
this.setState({nodes: newGrid, mouseIsPressed: true});
87101

88102
}
89103

90-
handleMouseEnter(row, col) {
91-
console.log("enter");
92-
if (!this.state.mouseIsPressed){
104+
handleMouseEnter(row, col, wallStatus) {
105+
if (!this.state.mouseIsPressed) {
93106
return;
94107
}
95-
const newGrid = getNewGridWithWallToggled(this.state.grid, row, col);
96-
this.setState({grid: newGrid});
108+
const newGrid = getNewGridWithWallToggled(this.state.grid, row, col, wallStatus);
109+
this.setState({nodes: newGrid});
97110
}
98111

99112
handleMouseUp() {
100-
console.log("up");
101113
this.setState({mouseIsPressed: false});
102114
}
103115

116+
resetWalls() {
117+
const newGrid = this.state.nodes.slice();
118+
for (let i = 0; i < 15; i++) {
119+
for (let j = 0; j < 50; j++) {
120+
121+
const currNode = newGrid[i][j]
122+
newGrid[i][j] = {
123+
...currNode,
124+
isWall: false,
125+
visitedDuringMaze: false,
126+
previousNode: null
127+
};
128+
}
129+
}
130+
131+
this.setState({nodes: newGrid});
132+
}
133+
134+
135+
generateMaze() {
136+
137+
this.resetWalls();
138+
139+
const grid = this.state.nodes.slice();
140+
141+
const startNode = grid[start_row][start_col];
142+
const destNode = grid[finish_row][finish_col];
143+
144+
dijkstra(grid, startNode, destNode);
145+
146+
const nodesToAnimate = getNodesInShortestPathOrder(destNode);
147+
148+
for (let i = 0; i < nodesToAnimate.length; i++) {
149+
150+
let r = getRndInteger(0, 1);
151+
152+
if (r === 1) {
153+
let d = getRndInteger(0, 3);
154+
let row = nodesToAnimate[i].row;
155+
let col = nodesToAnimate[i].col;
156+
157+
let r2;
158+
let c2;
159+
160+
if (d === 0) {
161+
r2 = getRndInteger(0, row);
162+
c2 = getRndInteger(col, 49);
163+
} else if (d === 1) {
164+
r2 = getRndInteger(0, row);
165+
c2 = getRndInteger(0, col);
166+
} else if (d === 2) {
167+
r2 = getRndInteger(row, 14);
168+
c2 = getRndInteger(col, 49);
169+
} else {
170+
r2 = getRndInteger(row, 14);
171+
c2 = getRndInteger(0, col);
172+
}
173+
174+
console.log([r2, c2]);
175+
176+
dijkstra(grid, grid[row][col], grid[r2][c2]);
177+
178+
const visitedNodes2 = getNodesInShortestPathOrder(grid[r2][c2]);
179+
180+
for (let j = 0; j < visitedNodes2.length; j++) {
181+
grid[visitedNodes2[j].row][visitedNodes2[j].col].isWall = true;
182+
}
183+
184+
}
185+
186+
grid[nodesToAnimate[i].row][nodesToAnimate[i].col].isWall = true;
187+
}
188+
189+
190+
191+
for (let i = 0; i < 15; i++) {
192+
for (let j = 0; j < 50; j++) {
193+
194+
const currNode = grid[i][j]
195+
grid[i][j] = {
196+
...currNode,
197+
isWall: !currNode.isWall,
198+
previousNode: null
199+
};
200+
}
201+
}
202+
this.setState({nodes: grid});
203+
}
204+
104205
render() {
105206

106207
const nodes2 = this.state.nodes;
@@ -120,9 +221,9 @@ export default class PathFindingVisualiser extends React.Component {
120221
isStart={node.isStart}
121222
isFinish={node.isFinish}
122223
isWall={node.isWall}
123-
mouseIsPressed = {mClicked}
124-
onMouseDown={(row, col) => this.handleMouseDown(row, col)}
125-
onMouseEnter={(row, col) => this.handleMouseEnter(row, col)}
224+
mouseIsPressed={mClicked}
225+
onMouseDown={(row, col) => this.handleMouseDown(row, col, !node.isWall)}
226+
onMouseEnter={(row, col) => this.handleMouseEnter(row, col, !node.isWall)}
126227
onMouseUp={() => this.handleMouseUp()}
127228

128229
></Node>)}
@@ -132,19 +233,26 @@ export default class PathFindingVisualiser extends React.Component {
132233
})
133234
}
134235
<button onClick={() => this.visualiseDijkstra()}>Visualise Dijkstra's</button>
236+
<button onClick={() => this.generateMaze()}>Create Maze</button>
237+
<button onClick={() => this.resetWalls()}>Reset Walls</button>
135238
</div>
136239
);
137240
}
138241

139242
}
140243

141244

142-
const getNewGridWithWallToggled = (grid, row, col) => {
245+
const getNewGridWithWallToggled = (grid, row, col, wallStatus) => {
143246
const newGrid = grid.slice();
144247
const node = newGrid[row][col];
145248
newGrid[row][col] = {
146249
...node,
147-
isWall: !node.isWall,
250+
isWall: wallStatus,
148251
};
149252
return newGrid;
150-
};
253+
};
254+
255+
256+
function getRndInteger(min, max) {
257+
return Math.floor(Math.random() * (max - min + 1)) + min;
258+
}

0 commit comments

Comments
 (0)