Game of life problem in C#

The Game of Life is a cellular automaton devised by mathematician John Conway. It consists of a grid of cells that can be alive or dead. The state of each cell in the next generation is determined by its neighbors according to specific rules.

Rules

  1. Underpopulation: Any live cell with fewer than two live neighbors dies.
  2. Overpopulation: Any live cell with more than three live neighbors dies.
  3. Survival: Any live cell with two or three live neighbors lives on to the next generation.
  4. Reproduction: Any dead cell with exactly three live neighbors becomes a live cell.

C# Implementation

Here’s a simple implementation of the Game of Life in C#:

using System;

public class GameOfLife
{
    public static void PrintBoard(bool[,] board)
    {
        for (int i = 0; i < board.GetLength(0); i++)
        {
            for (int j = 0; j < board.GetLength(1); j++)
            {
                Console.Write(board[i, j] ? "1 " : "0 ");
            }
            Console.WriteLine();
        }
    }

    public static void NextGeneration(bool[,] board)
    {
        int rows = board.GetLength(0);
        int cols = board.GetLength(1);
        bool[,] nextBoard = new bool[rows, cols];

        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < cols; j++)
            {
                int liveNeighbors = CountLiveNeighbors(board, i, j, rows, cols);

                if (board[i, j]) // Cell is currently alive
                {
                    nextBoard[i, j] = liveNeighbors == 2 || liveNeighbors == 3;
                }
                else // Cell is currently dead
                {
                    nextBoard[i, j] = liveNeighbors == 3;
                }
            }
        }

        // Update board to the next generation
        Array.Copy(nextBoard, board, nextBoard.Length);
    }

    private static int CountLiveNeighbors(bool[,] board, int row, int col, int rows, int cols)
    {
        int count = 0;
        for (int i = row - 1; i <= row + 1; i++)
        {
            for (int j = col - 1; j <= col + 1; j++)
            {
                if (i >= 0 && i < rows && j >= 0 && j < cols && (i != row || j != col))
                {
                    count += board[i, j] ? 1 : 0;
                }
            }
        }
        return count;
    }

    public static void Main(string[] args)
    {
        // Initial board configuration
        bool[,] board = new bool[,]
        {
            { false, false, false, false, false },
            { false, true, true, false, false },
            { false, false, true, false, false },
            { false, false, false, false, false },
            { false, false, false, false, false }
        };

        Console.WriteLine("Initial State:");
        PrintBoard(board);
        Console.WriteLine();

        for (int generation = 0; generation < 5; generation++)
        {
            NextGeneration(board);
            Console.WriteLine($"Generation {generation + 1}:");
            PrintBoard(board);
            Console.WriteLine();
        }
    }
}

Explanation

  1. Initialization:

    • The board is represented as a 2D boolean array where true represents a live cell and false represents a dead cell.
  2. PrintBoard Method:

    • This method prints the current state of the board, using 1 for live cells and 0 for dead cells.
  3. NextGeneration Method:

    • This method calculates the next state of the board based on the current state. It creates a new board to hold the next generation.
    • For each cell, it counts the number of live neighbors using the CountLiveNeighbors method and applies the rules of the game to determine if the cell will be alive or dead in the next generation.
  4. CountLiveNeighbors Method:

    • This helper method checks the eight possible neighbors around a given cell and counts how many are alive, while ensuring it stays within the boundaries of the board.
  5. Main Method:

    • It initializes a sample board and runs for a specified number of generations, printing the state of the board at each generation.

Output

When you run the program, it will show the evolution of the board over several generations, demonstrating how the configuration changes according to the rules.

Complexity

  • Time Complexity: O(rows * cols) for each generation, since we need to check each cell and its neighbors.
  • Space Complexity: O(rows * cols) for the next board, although in some implementations, this can be optimized to O(1) by modifying the board in place, but it complicates the logic.

This implementation provides a clear structure and easy understanding of how the Game of Life works in C#.