Skip to content

Commit 888d424

Browse files
committed
Attempting to use Zustand to update global specific cell state
1 parent 6421cea commit 888d424

File tree

7 files changed

+236
-66
lines changed

7 files changed

+236
-66
lines changed

package-lock.json

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

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"dependencies": {
1616
"react": "^18.2.0",
1717
"react-dom": "^18.2.0",
18-
"react-icons": "^5.2.1"
18+
"react-icons": "^5.2.1",
19+
"zustand": "^4.5.4"
1920
},
2021
"devDependencies": {
2122
"@types/react": "^18.2.66",

src/algorithms/pathfinding/BreadthFirstSearch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export async function BreadthFirstSearch(maze: Cell[][], startCell: Cell, endCel
4242
maze[neighbor.row][neighbor.col].prev = currentCell;
4343
}
4444
}
45-
await sleep(10);
45+
await sleep(0);
4646
setMaze([...maze]);
4747
}
4848

src/algorithms/utils/SleepTime.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,26 @@ export class SleepTime {
55
this.value = value;
66
}
77
}
8-
8+
/*
99
// Sleep function that returns a promise that resolves after a specified time
1010
export function sleep(ms: number): Promise<void> {
1111
return new Promise(resolve => setTimeout(resolve, ms));
12-
}
12+
}
13+
*/
14+
15+
16+
// Helper function to wait for a specified duration using requestAnimationFrame
17+
export const sleep = (ms: number) => {
18+
return new Promise<void>(resolve => {
19+
const start = performance.now();
20+
const frame = () => {
21+
const now = performance.now();
22+
if (now - start >= ms) {
23+
resolve();
24+
} else {
25+
requestAnimationFrame(frame);
26+
}
27+
};
28+
requestAnimationFrame(frame);
29+
});
30+
};

src/components/MazeGrid.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import React from 'react';
2-
import { Cell } from '../algorithms/utils/PathfindingUtils';
32
import { HiChevronDoubleRight, HiOutlineFlag } from "react-icons/hi";
3+
import { useMazeStore } from '../hooks/useMazeStore';
44
import '../styles/pathfinding.css';
55

6-
76
interface MazeGridProps {
8-
maze: Cell[][],
9-
handleMouseDown: (rowIndex: number, colIndex: number) => void,
10-
handleMouseEnter: (rowIndex: number, colIndex: number) => void,
11-
handleMouseUp: () => void
7+
handleMouseDown: (rowIndex: number, colIndex: number) => void;
8+
handleMouseEnter: (rowIndex: number, colIndex: number) => void;
9+
handleMouseUp: () => void;
1210
}
1311

14-
const MazeGrid: React.FC<MazeGridProps> = ({ maze, handleMouseDown, handleMouseEnter, handleMouseUp }) => {
12+
const MazeGrid: React.FC<MazeGridProps> = ({ handleMouseDown, handleMouseEnter, handleMouseUp }) => {
13+
const { maze } = useMazeStore();
14+
1515
return (
1616
<div onMouseUp={handleMouseUp}>
1717
{maze.map((row, rowIndex) => (
@@ -30,8 +30,8 @@ const MazeGrid: React.FC<MazeGridProps> = ({ maze, handleMouseDown, handleMouseE
3030
alignItems: 'center',
3131
justifyContent: 'center'
3232
}}>
33-
{cell.start ? <HiChevronDoubleRight style={{ color: 'black', fontSize: '26px' }} /> : ''}
34-
{cell.end ? <HiOutlineFlag style={{ color: 'black', fontSize: '26px' }} /> : ''}
33+
{cell.start && <HiChevronDoubleRight style={{ color: 'black', fontSize: '26px' }} />}
34+
{cell.end && <HiOutlineFlag style={{ color: 'black', fontSize: '26px' }} />}
3535
</div>
3636
))}
3737
</div>
@@ -40,4 +40,4 @@ const MazeGrid: React.FC<MazeGridProps> = ({ maze, handleMouseDown, handleMouseE
4040
);
4141
};
4242

43-
export default MazeGrid;
43+
export default MazeGrid;

src/hooks/useMazeStore.ts

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// useMazeStore.ts
2+
import create from 'zustand';
3+
import { Cell } from '../algorithms/utils/PathfindingUtils';
4+
5+
interface MazeState {
6+
maze: Cell[][];
7+
startNode: [number, number];
8+
endNode: [number, number];
9+
setMaze: (newMaze: Cell[][]) => void;
10+
setCell: (row: number, col: number, updates: Partial<Cell>) => void;
11+
generateMaze: (width: number, height: number) => void;
12+
clearAttribute: (attribute: keyof Cell) => void;
13+
clearLatestRun: () => void;
14+
populateOptimalPath: (optimalPath: Cell[] | null) => void;
15+
setStartPosition: (flatHeight: number, flatWidth: number) => void;
16+
setEndPosition: (flatHeight: number, flatWidth: number) => void;
17+
drawCell: (row: number, col: number, value: boolean) => void;
18+
moveNode: (row: number, col: number, nodeType: 'start' | 'end') => void;
19+
}
20+
21+
export const useMazeStore = create<MazeState>((set) => ({
22+
maze: [],
23+
startNode: [0, 0],
24+
endNode: [1,1],
25+
setMaze: (newMaze) => set({ maze: newMaze }),
26+
setCell: (row, col, updates) => {
27+
set((state) => {
28+
const newMaze = state.maze.map((r, i) =>
29+
i === row ? r.map((c, j) => (j === col ? { ...c, ...updates } : c)) : r
30+
);
31+
return { maze: newMaze };
32+
});
33+
},
34+
generateMaze: (width, height) => {
35+
let flatHeight = Math.floor((height - (26 + 64)) / 26);
36+
if (flatHeight % 2 === 0) flatHeight += 1;
37+
let flatWidth = Math.floor((width - 326) / 26);
38+
if (flatWidth % 2 === 0) flatWidth += 1;
39+
40+
const newMaze = [];
41+
for (let i = 0; i < flatHeight; i++) {
42+
const row = [];
43+
for (let j = 0; j < flatWidth; j++) {
44+
row.push(new Cell(i, j));
45+
}
46+
newMaze.push(row);
47+
}
48+
set({ maze: newMaze });
49+
},
50+
clearAttribute: (attribute) => {
51+
set((state) => ({
52+
maze: state.maze.map((row) =>
53+
row.map((cell) => ({ ...cell, [attribute]: false }))
54+
),
55+
}));
56+
},
57+
clearLatestRun: () => {
58+
set((state) => {
59+
const clearedMaze = state.maze.map((row) =>
60+
row.map((cell) => ({ ...cell, visited: false, finalPath: false }))
61+
);
62+
return { maze: clearedMaze };
63+
});
64+
},
65+
populateOptimalPath: (optimalPath) => {
66+
if (!optimalPath) {
67+
return;
68+
}
69+
const delay = 50; // Delay in milliseconds between each update
70+
const updateCell = (index: number) => {
71+
if (index >= optimalPath.length) {
72+
return;
73+
}
74+
75+
set((state) => {
76+
const newMaze = state.maze.map((row) =>
77+
row.map((cell) => ({ ...cell }))
78+
);
79+
newMaze[optimalPath[index].row][optimalPath[index].col].finalPath = true;
80+
return { maze: newMaze };
81+
});
82+
83+
// Schedule the next update with delay
84+
requestAnimationFrame(() =>
85+
setTimeout(() => updateCell(index + 1), delay)
86+
);
87+
};
88+
89+
updateCell(0);
90+
},
91+
setStartPosition: (flatHeight, flatWidth) => {
92+
set((state) => {
93+
const rowIndex = Math.floor(flatHeight / 2);
94+
const colIndex = Math.floor(flatWidth / 4);
95+
const newMaze = state.maze.map((row, i) =>
96+
i === rowIndex ? row.map((cell, j) => (j === colIndex ? { ...cell, start: true } : cell)) : row
97+
);
98+
return { maze: newMaze, startNode: [rowIndex, colIndex] };
99+
});
100+
},
101+
setEndPosition: (flatHeight, flatWidth) => {
102+
set((state) => {
103+
const rowIndex = Math.floor(flatHeight / 2);
104+
const colIndex = Math.floor(flatWidth * 3 / 4);
105+
const newMaze = state.maze.map((row, i) =>
106+
i === rowIndex ? row.map((cell, j) => (j === colIndex ? { ...cell, end: true } : cell)) : row
107+
);
108+
return { maze: newMaze, endNode: [rowIndex, colIndex] };
109+
});
110+
},
111+
drawCell: (row, col, value) => {
112+
set((state) => {
113+
const newMaze = state.maze.map((r, i) =>
114+
i === row ? r.map((c, j) => (j === col ? { ...c, wall: value } : c)) : r
115+
);
116+
return { maze: newMaze };
117+
});
118+
},
119+
moveNode: (row, col, nodeType) => {
120+
set((state) => {
121+
const newMaze = state.maze.map((r, i) =>
122+
r.map((c) => {
123+
if (nodeType === 'start' && c.start) {
124+
return { ...c, start: false };
125+
}
126+
if (nodeType === 'end' && c.end) {
127+
return { ...c, end: false };
128+
}
129+
if (i === row && c.col === col) {
130+
return { ...c, [nodeType]: true };
131+
}
132+
return c;
133+
})
134+
);
135+
return nodeType === 'start'
136+
? { maze: newMaze, startNode: [row, col] }
137+
: { maze: newMaze, endNode: [row, col] };
138+
});
139+
},
140+
}));

0 commit comments

Comments
 (0)