Conway's Game of Life with React

Introduction

Conway's Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970. It is a zero-player game, meaning that its evolution is determined by its initial state, requiring no further input. One interacts with the Game of Life by creating an initial configuration and observing how it evolves.

This implementation uses React and Tailwind CSS to create an interactive version of the Game of Life. You can start, stop, randomize, and clear the grid, as well as toggle individual cells by clicking on them.

Game of Life

Technical Explanation

The implementation of Conway's Game of Life involves several key components and concepts:

  1. Grid Representation: The grid is represented as a two-dimensional array of boolean values, where true indicates a live cell and false indicates a dead cell. The grid size is fixed at 30 rows and 50 columns.

  2. Grid Initialization: Two functions are used to initialize the grid: generateEmptyGrid creates an empty grid with all cells dead, and generateRandomGrid creates a grid with random live cells.

  3. Neighbor Calculation: For each cell, the number of live neighbors is calculated using the neighborOffsets array, which defines the relative positions of the eight neighboring cells.

  4. Next Generation Calculation: The calculateNextGeneration function computes the next state of the grid based on the current state. The rules of Conway's Game of Life are applied:

    • A live cell with 2 or 3 live neighbors stays alive; otherwise, it dies.
    • A dead cell with exactly 3 live neighbors becomes alive.
  5. Simulation Control: The simulation is controlled using the running state and the runSimulation function. The useEffect hook ensures that the simulation runs continuously when started and stops when the running state is set to false.

  6. User Interaction: Users can interact with the grid by clicking cells to toggle their state, and use buttons to start/stop the simulation, randomize the grid, and clear the grid.

  7. Styling: Tailwind CSS is used for styling the grid and buttons, providing a responsive and visually appealing interface.

The following code snippet demonstrates the core logic for calculating the next generation of cells:

const calculateNextGeneration = (grid: boolean[][]): boolean[][] => {
  const newGrid = generateEmptyGrid();

  for (let r = 0; r < numRows; r++) {
    for (let c = 0; c < numCols; c++) {
      let neighbors = 0;
      neighborOffsets.forEach(([x, y]) => {
        const newRow = r + x;
        const newCol = c + y;
        if (newRow >= 0 && newRow < numRows && newCol >= 0 && newCol < numCols) {
          neighbors += grid[newRow][newCol] ? 1 : 0;
        }
      });

      if (grid[r][c] && (neighbors === 2 || neighbors === 3)) {
        newGrid[r][c] = true;
      } else if (!grid[r][c] && neighbors === 3) {
        newGrid[r][c] = true;
      }
    }
  }

  return newGrid;
};
Back to home page