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