11import React , { useState , useEffect } from 'react' ;
2+ import useWindowDimensions from '../utils/useWindowDimensions' ;
3+ import '../styles/pathfinding.css' ;
4+ import { HiChevronRight } from "react-icons/hi" ;
5+ import { Cell } from '../algorithms/utils/PathfindingUtils' ;
26
37const PathfindingVisualiser : React . FC = ( ) => {
4- const [ maze , setMaze ] = useState < number [ ] [ ] > ( [ ] ) ;
8+ const { width = 0 , height = 0 } = useWindowDimensions ( ) ;
9+ const [ maze , setMaze ] = useState < Cell [ ] [ ] > ( [ ] ) ;
10+ const [ isDrawing , setIsDrawing ] = useState < boolean > ( false ) ;
11+ const [ drawingValue , setDrawingValue ] = useState < boolean > ( false ) ;
12+ const [ startNode , setStartNode ] = useState < number [ ] > ( [ 0 , 0 ] ) ;
13+ const [ endNode , setEndNode ] = useState < number [ ] > ( [ 0 , 0 ] ) ;
14+ const [ isMovingNode , setIsMovingNode ] = useState < 'start' | 'end' | null > ( null ) ;
515
616 useEffect ( ( ) => {
7- generateMaze ( ) ;
8- } , [ ] ) ;
9-
10- const generateMaze = ( ) => {
11- const rows = 10 ;
12- const cols = 10 ;
13- const newMaze : number [ ] [ ] = [ ] ;
14- for ( let i = 0 ; i < rows ; i ++ ) {
15- const row : number [ ] = [ ] ;
16- for ( let j = 0 ; j < cols ; j ++ ) {
17- row . push ( 1 ) ;
17+ generateTable ( ) ;
18+ } , [ width , height ] ) ;
19+
20+ function setStartPosition ( flatHeight : number , flatWidth : number ) {
21+ const rowIndex = Math . floor ( flatHeight / 2 ) ;
22+ const colIndex = Math . floor ( flatWidth / 4 ) ;
23+ setMaze ( prevMaze => {
24+ const newMaze = [ ...prevMaze ] ;
25+ newMaze [ rowIndex ] [ colIndex ] = new Cell ( rowIndex , colIndex ) ;
26+ newMaze [ rowIndex ] [ colIndex ] . start = true ;
27+ return newMaze ;
28+ } ) ;
29+ setStartNode ( [ rowIndex , colIndex ] ) ;
30+ }
31+
32+ function setEndPosition ( flatHeight : number , flatWidth : number ) {
33+ const rowIndex = Math . floor ( flatHeight / 2 ) ;
34+ const colIndex = Math . floor ( flatWidth * 3 / 4 ) ;
35+ setMaze ( prevMaze => {
36+ const newMaze = [ ...prevMaze ] ;
37+ newMaze [ rowIndex ] [ colIndex ] = new Cell ( rowIndex , colIndex ) ;
38+ newMaze [ rowIndex ] [ colIndex ] . end = true ;
39+ return newMaze ;
40+ } ) ;
41+ setEndNode ( [ rowIndex , colIndex ] ) ;
42+ }
43+
44+ function generateTable ( ) {
45+ const flatHeight = Math . floor ( height / 27 ) ;
46+ const flatWidth = Math . floor ( ( width - 300 ) / 27 ) ;
47+ const newMaze = [ ] ;
48+ for ( let i = 0 ; i < flatHeight ; i ++ ) {
49+ const row = [ ] ;
50+ for ( let j = 0 ; j < flatWidth ; j ++ ) {
51+ row . push ( new Cell ( i , j ) ) ;
1852 }
1953 newMaze . push ( row ) ;
2054 }
21-
2255 setMaze ( newMaze ) ;
56+ setStartPosition ( flatHeight , flatWidth ) ;
57+ setEndPosition ( flatHeight , flatWidth ) ;
58+ }
59+
60+ const handleMouseDown = ( rowIndex : number , colIndex : number ) => {
61+ if ( maze [ rowIndex ] [ colIndex ] . start ) {
62+ setIsMovingNode ( 'start' ) ;
63+ } else if ( maze [ rowIndex ] [ colIndex ] . end ) {
64+ setIsMovingNode ( 'end' ) ;
65+ } else {
66+ setIsDrawing ( true ) ;
67+ const currentCellValue = maze [ rowIndex ] [ colIndex ] ;
68+ setDrawingValue ( currentCellValue . wall ? false : true ) ;
69+ drawCell ( rowIndex , colIndex , currentCellValue . wall ? false : true ) ;
70+ }
71+ } ;
72+
73+ const handleMouseUp = ( ) => {
74+ setIsDrawing ( false ) ;
75+ setIsMovingNode ( null ) ;
76+ } ;
77+
78+ const handleMouseEnter = ( rowIndex : number , colIndex : number ) => {
79+ if ( isDrawing ) {
80+ drawCell ( rowIndex , colIndex , drawingValue ) ;
81+ } else if ( isMovingNode ) {
82+ moveNode ( rowIndex , colIndex , isMovingNode ) ;
83+ }
84+ } ;
85+
86+ const drawCell = ( rowIndex : number , colIndex : number , value : boolean ) => {
87+ if ( rowIndex === startNode [ 0 ] && colIndex === startNode [ 1 ] ) return ;
88+ if ( rowIndex === endNode [ 0 ] && colIndex === endNode [ 1 ] ) return ;
89+ setMaze ( prevMaze => {
90+ const newMaze = [ ...prevMaze ] ;
91+ newMaze [ rowIndex ] [ colIndex ] . wall = value ;
92+ return newMaze ;
93+ } ) ;
94+ } ;
95+
96+ const moveNode = ( rowIndex : number , colIndex : number , nodeType : 'start' | 'end' ) => {
97+ setMaze ( prevMaze => {
98+ const newMaze = [ ...prevMaze ] ;
99+ if ( nodeType === 'start' ) {
100+ newMaze [ startNode [ 0 ] ] [ startNode [ 1 ] ] . start = false ;
101+ newMaze [ rowIndex ] [ colIndex ] . start = true ;
102+ setStartNode ( [ rowIndex , colIndex ] ) ;
103+ } else if ( nodeType === 'end' ) {
104+ newMaze [ endNode [ 0 ] ] [ endNode [ 1 ] ] . end = false ;
105+ newMaze [ rowIndex ] [ colIndex ] . end = true ;
106+ setEndNode ( [ rowIndex , colIndex ] ) ;
107+ }
108+ return newMaze ;
109+ } ) ;
23110 } ;
24111
25112 return (
26- < div >
113+ < div onMouseUp = { handleMouseUp } >
27114 { maze . map ( ( row , rowIndex ) => (
28- < div key = { rowIndex } >
115+ < div key = { rowIndex } className = "pathfinding-row" id = { 'row-' + rowIndex } >
29116 { row . map ( ( cell , colIndex ) => (
30117 < div
31118 key = { colIndex }
119+ onMouseDown = { ( ) => handleMouseDown ( rowIndex , colIndex ) }
120+ onMouseEnter = { ( ) => handleMouseEnter ( rowIndex , colIndex ) }
32121 style = { {
33- width : '20px' ,
34- height : '20px' ,
35- backgroundColor : cell === 1 ? 'black' : 'white' ,
36- border : '1px solid black' ,
37- } }
38- />
122+ width : '26px' ,
123+ height : '26px' ,
124+ backgroundColor : cell . start ? 'lightblue' : ( cell . end ? 'lightgreen' : ( cell . wall ? 'black' : 'white' ) ) ,
125+ border : '.5px solid lightblue' ,
126+ display : 'flex' ,
127+ alignItems : 'center' ,
128+ justifyContent : 'center'
129+ } } >
130+ { cell . start ? < HiChevronRight style = { { color : 'black' , fontSize : '26px' } } /> : '' }
131+ { cell . end ? < HiChevronRight style = { { color : 'black' , fontSize : '26px' , transform : 'rotate(180deg)' } } /> : '' }
132+ </ div >
39133 ) ) }
40134 </ div >
41135 ) ) }
42136 </ div >
43137 ) ;
44138} ;
45139
46- export default PathfindingVisualiser ;
140+ export default PathfindingVisualiser ;
0 commit comments