Quantcast
Channel: Brian Pedersen's Sitecore and .NET Blog
Viewing all articles
Browse latest Browse all 285

C# Game Of Life

$
0
0

The Game Of Life is a cell life simulator devised by the Cambridge mathematician John Conway.

Game Of Life in a Console Application

The simulator serves as an excellent coding example to learn new programming languages. The rules are simple. You have a grid in a predetermined size, each cell can live or die based on a set of rules:

  • If a cell is alive, and there are 0 or 1 living neighbors, the cell dies of loneliness.
  • If a cell is alive, and there are 2 or 3 living neighbors, the cell survives.
  • If a cell is alive, and there are 4 or more living neighbors, the cell dies of overpopulation.
  • If a cell is dead, and there are 3 living neighbors, the cell comes alive.

This is an example of a simple game of life implementation in C# and .net 8. The simulation uses the console output to visualize the game progress.

STEP 1: DEFINE THE GRID SIZE AND THE PRE-SEED A NUMBER OF CELLS

const int BOARD_WIDTH = 80;
const int BOARD_LENGTH = 25;
const int ACTIVE_CELLS_AT_START = 250;

// This is the game of life grid
bool[,] board= new bool[BOARD_WIDTH, BOARD_LENGTH];

// Create a number of living cells to start the simulation
var random = new Random();
for (int i = 0; i < ACTIVE_CELLS_AT_START; i++)
{
  board[random.Next(board.GetLength(0)), random.Next(board.GetLength(1))] = true;
}

First we define the game prerequisites; the size of the grid (called board) and how many cells should be alive when the simulation starts.

Then we populate the grid by randomly setting cells in the grid to true (true meaning alive, false meaning dead).

STEP 2: MAKE AN ALGORITHM TO CALCULATE THE NUMBER OF LIVING NEIGHBORS

int CountNeighbors(bool[,] board, int x, int y)
{
  int ac = 0;
  for (int i = x - 1; i <= x + 1; i++)
  {
    for (int j = y - 1; j <= y + 1; j++)
    {
      if (IsValidIndex(i, j, board.GetLength(0), board.GetLength(1)) && !IsYourself(x, y, i, j) && game[i, j])
        ac++;
    }
  }

  return ac;
}

bool IsValidIndex(int i, int j, int rows, int cols)
{
  return i >= 0 && i < rows && j >= 0 && j < cols;
}

bool IsYourself(int x, int y, int i, int j)
{
  return x == i && y == j;
}

The CountNeighBors takes the game grid and the x/y position of the cell to calculate how many of the 8 neighboring cells are alive.

The white cells are the cells to check

The algorithm needs a double loop to check the neighbors.

But it also needs to be smart enough to count even if the cell is on the edge of the grid. The IsValidIndex checks to see if the cell being investigated is within the board.

Also, we should not count the cell being investigated. The IsYourself checks to see if the cell being investigated is the current cell, and that cell is also disregarded.

STEP 4: CALCULATE THE CELL LIFE

void CalculateCellLife(bool[,] board, int x, int y)
{
  int neighbors = CountNeighbors(board, x, y);
  if (board[x, y] == true)
  {
    if (neighbors <= 1)
      board[x, y] = false;
    if (neighbors >= 4)
      board[x, y] = false;
  }
  else
  {
    if (neighbors == 3)
      board[x, y] = true;
  }
}

This method uses the CountNeighbors function to calculate the number of alive cells surrounding a specified cell, and use the game of life algorithm to determine if the cell in question should die or stay alive. As stated before, the rules are that a living cell will die if there are 0,1 or more than 4 alive surrounding cells, and some alive if there is precisely 3 live cells surrounding it.

STEP 5: THE MAIN GAME LOOP

while (true)
{
  for (int x = 0; x < board.GetLength(0); x++)
  {
    for (int y = 0; y < board.GetLength(1); y++)
    {
      CalculateCellLife(board, x, y);
      DrawCell(x, y, board[x, y]);
    }
  }
}

This is the main game loop that loops forever, takes each cell on the board, calculates if the cell must live or die, and draws the result to screen.

COMPLETE CODE:

This is the code in its completion:

const int BOARD_WIDTH = 80;
const int BOARD_LENGTH = 25;
const int ACTIVE_CELLS_AT_START = 250;

bool[,] board = new bool[BOARD_WIDTH, BOARD_LENGTH];
var random = new Random();

for (int i = 0; i < ACTIVE_CELLS_AT_START; i++)
{
  board[random.Next(board.GetLength(0)), random.Next(board.GetLength(1))] = true;
}

while (true)
{
  for (int x = 0; x < board.GetLength(0); x++)
  {
    for (int y = 0; y < board.GetLength(1); y++)
    {
      CalculateCellLife(board, x, y);
      DrawCell(x, y, board[x, y]);
    }
  }
}

void CalculateCellLife(bool[,] board, int x, int y)
{
  int neighbors = CountNeighbors(board, x, y);
  if (board[x, y] == true)
  {
    if (neighbors <= 1)
      board[x, y] = false;
    if (neighbors >= 4)
      board[x, y] = false;
  }
  else
  {
    if (neighbors == 3)
      board[x, y] = true;
  }
}

void DrawCell(int x, int y, bool isAlive)
{
  Console.SetCursorPosition(x, y);
  if (!isAlive)
  {
    Console.BackgroundColor = ConsoleColor.Black;
    Console.Write(" ");
  }
  else
  {
    Console.BackgroundColor = ConsoleColor.White;
    Console.Write(" ");
  }
}

int CountNeighbors(bool[,] board, int x, int y)
{
  int ac = 0;
  for (int i = x - 1; i <= x + 1; i++)
  {
    for (int j = y - 1; j <= y + 1; j++)
    {
      if (IsValidIndex(i, j, board.GetLength(0), board.GetLength(1)) && !IsYourself(x, y, i, j) && board[i, j])
        ac++;
    }
  }

  return ac;
}

bool IsValidIndex(int i, int j, int rows, int cols)
{
  return i >= 0 && i < rows && j >= 0 && j < cols;
}

bool IsYourself(int x, int y, int i, int j)
{
  return x == i && y == j;
}

MORE TO READ:


Viewing all articles
Browse latest Browse all 285

Trending Articles