1
+ "use client" ;
2
+ import Navbar from '@/components/navbar' ;
3
+ import { createRef , useRef , useState , useEffect } from 'react' ;
4
+ import Menu from "./menu" ;
5
+ import Grid from "./grid" ;
6
+
7
+
8
+ export default function GameOfLifePage ( ) {
9
+
10
+ let gridRef = createRef ( ) ;
11
+
12
+ const [ grid , setGrid ] = useState ( [ ] ) ;
13
+ const [ running , setRunning ] = useState ( false ) ;
14
+ const runningRef = useRef ( false ) ; // Add this ref
15
+
16
+
17
+ useEffect ( ( ) => {
18
+ const width = gridRef . current . offsetWidth ;
19
+ const height = gridRef . current . offsetHeight ;
20
+ const row = Math . max ( Math . floor ( height / 25 ) - 2 , 10 ) ;
21
+ const col = Math . floor ( width / 25 ) ;
22
+ setGrid ( getInitialGrid ( row , col ) ) ;
23
+ } , [ ] ) ;
24
+
25
+ const handleMouseDown = ( row , col ) => {
26
+
27
+ const newGrid = getNewGridWithWallToggled ( grid , row , col ) ;
28
+ setGrid ( newGrid ) ;
29
+
30
+ // this.setState({ mouseIsPressed: true });
31
+ }
32
+
33
+ const handleMouseEnter = ( row , col ) => {
34
+ // if (this.state.mouseIsPressed === false) return;
35
+ // if ((this.state.startNode.row !== row || this.state.startNode.col !== col) && (this.state.endNode.row !== row || this.state.endNode.col !== col)) {
36
+ // const newGrid = getNewGridWithWallToggled(this.state.grid, row, col);
37
+ // this.setState({ grid: newGrid });
38
+ // }
39
+ }
40
+
41
+ const handleMouseUp = ( row , col ) => {
42
+ // this.setState({ mouseIsPressed: false });
43
+ }
44
+
45
+ const handleStart = ( ) => {
46
+ setRunning ( true ) ;
47
+ runningRef . current = true ; // Update ref
48
+
49
+ gameOfLife ( ) ;
50
+ }
51
+
52
+ const handleStop = ( ) => {
53
+ setRunning ( false ) ;
54
+ runningRef . current = false ;
55
+ console . log ( "Simulation stopped" ) ;
56
+ }
57
+
58
+ const handleClearBoard = ( ) => {
59
+ setRunning ( false ) ;
60
+ runningRef . current = false ;
61
+ const width = gridRef . current . offsetWidth ;
62
+ const height = gridRef . current . offsetHeight ;
63
+ const row = Math . max ( Math . floor ( height / 25 ) - 2 , 10 ) ;
64
+ const col = Math . floor ( width / 25 ) ;
65
+ setGrid ( getInitialGrid ( row , col ) ) ;
66
+ }
67
+
68
+ const gameOfLife = async ( ) => {
69
+ let newGrid = getNextGeneration ( grid ) ;
70
+ while ( runningRef . current ) {
71
+ setGrid ( newGrid ) ;
72
+ newGrid = getNextGeneration ( newGrid ) ;
73
+ await sleep ( 200 ) ;
74
+ }
75
+ }
76
+
77
+ return (
78
+ < div className = "flex flex-col h-screen" >
79
+
80
+ < Navbar title = "Game of Life" />
81
+
82
+ < div className = "flex flex-1 overflow-hidden" >
83
+ < Menu
84
+ onStart = { handleStart }
85
+ onStop = { handleStop }
86
+ onClear = { handleClearBoard }
87
+ />
88
+
89
+ < div className = "flex flex-1 flex-col items-center justify-center overflow-auto" >
90
+ < div className = "w-full h-full flex items-center justify-center" ref = { gridRef } >
91
+ < Grid
92
+ grid = { grid }
93
+ onMouseDown = { handleMouseDown }
94
+ onMouseEnter = { handleMouseEnter }
95
+ onMouseUp = { handleMouseUp }
96
+ />
97
+ </ div >
98
+ </ div >
99
+ </ div >
100
+ </ div >
101
+ ) ;
102
+ }
103
+
104
+ const getInitialGrid = ( row , col ) => {
105
+ let grid = [ ] ;
106
+ for ( let i = 0 ; i < row ; i ++ ) {
107
+ let row = [ ] ;
108
+ for ( let j = 0 ; j < col ; j ++ ) {
109
+ row . push ( createNode ( i , j ) ) ;
110
+ }
111
+ grid . push ( row ) ;
112
+ }
113
+ return grid ;
114
+ }
115
+
116
+ const createNode = ( row , col ) => {
117
+ return {
118
+ row,
119
+ col,
120
+ isAlive : false
121
+ }
122
+ }
123
+
124
+ const getNewGridWithWallToggled = ( grid , row , col ) => {
125
+ const newGrid = grid . slice ( ) ;
126
+ const node = newGrid [ row ] [ col ] ;
127
+
128
+ const newNode = {
129
+ ...node ,
130
+ isAlive : ! node . isAlive ,
131
+ } ;
132
+
133
+ newGrid [ row ] [ col ] = newNode ;
134
+ return newGrid ;
135
+ } ;
136
+
137
+ const getNextGeneration = ( grid ) => {
138
+ const newGrid = grid . slice ( ) ;
139
+ for ( let i = 0 ; i < grid . length ; i ++ ) {
140
+ newGrid [ i ] = grid [ i ] . slice ( ) ;
141
+ for ( let j = 0 ; j < grid [ i ] . length ; j ++ ) {
142
+ const node = grid [ i ] [ j ] ;
143
+ const aliveNeighbors = getAliveNeighbors ( grid , node ) ;
144
+
145
+ if ( node . isAlive && ( aliveNeighbors < 2 || aliveNeighbors > 3 ) ) {
146
+ newGrid [ i ] [ j ] = {
147
+ ...node ,
148
+ isAlive : false
149
+ }
150
+ }
151
+ if ( ! node . isAlive && aliveNeighbors === 3 ) {
152
+ newGrid [ i ] [ j ] = {
153
+ ...node ,
154
+ isAlive : true
155
+ }
156
+ }
157
+ }
158
+ }
159
+ return newGrid ;
160
+ }
161
+
162
+ const getAliveNeighbors = ( grid , node ) => {
163
+
164
+ const { row, col } = node ;
165
+ const dirx = [ - 1 , 1 , 0 , 0 , - 1 , - 1 , 1 , 1 ] ;
166
+ const diry = [ 0 , 0 , - 1 , 1 , - 1 , 1 , - 1 , 1 ] ;
167
+ let count = 0 ;
168
+ for ( let i = 0 ; i < 8 ; i ++ ) {
169
+ const newRow = row + dirx [ i ] ;
170
+ const newCol = col + diry [ i ] ;
171
+ if ( newRow >= 0 && newRow < grid . length && newCol >= 0 && newCol < grid [ 0 ] . length && grid [ newRow ] [ newCol ] . isAlive ) {
172
+ count ++ ;
173
+ }
174
+ }
175
+
176
+ return count ;
177
+ }
178
+
179
+ function sleep ( ms ) {
180
+ return new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
181
+ }
0 commit comments