EN VI

C# - Conway is Game of Life: unexpected behavior?

2024-03-10 03:00:05
C# - Conway is Game of Life: unexpected behavior

I'm currently try to recreate Conway's Game of Life in a .NET console application.

I hardcoded this pattern

1

which does basically not move and just stays that way through generations; now though I came to the problem that after one generation everything dies.

using System.Linq.Expressions;
using System.Security.Cryptography.X509Certificates;

internal class Program
{
    private static Cell[,] cells;
    private const int MAX = 6;
    public static void Main()
    {
        var rand = new Random();
        cells = new Cell[MAX, MAX];
        for (int row = 0; row < cells.GetLength(0); row++)
        {
            for (int collum = 0; collum < cells.GetLength(1); collum++)
            {
                //  cells[row,collum] = new Cell((rand.Next(0,3) == 1) ? '#' : '0');
                cells[row, collum] = new Cell('0');
            }

        }
        cells[1, 0] = new Cell('#');
        cells[0, 1] = new Cell('#');
        cells[2, 1] = new Cell('#');
        cells[1, 2] = new Cell('#');

        updateConsole();
        Thread.Sleep(1000);
        while (true)
        {
            Thread.Sleep(1000);

            nextGeneration();
        }


    }
    static void updateConsole()
    {
        Console.Clear();
        for (int y = 0; y < cells.GetLength(1); y++)
        {
            for (int x = 0; x < cells.GetLength(0); x++)
            {
                if (cells[x, y].state == '#') Console.ForegroundColor = ConsoleColor.DarkYellow;
                else Console.ForegroundColor = ConsoleColor.DarkBlue;
                Console.Write(cells[x, y].state + " ");
            }
            Console.Write("\n");
        }
    }
    static void nextGeneration()
    {
        for (int _x = 0; _x < MAX; _x++) for (int _y = 0; _y < MAX; _y++) cells[_x, _y].lastState = cells[_x, _y].state;
        for (int y = 0; y < cells.GetLength(1); y++)
        {
            for (int x = 0; x < cells.GetLength(0); x++)
            {
                //cells[x, y].lastState = cells[x, y].state;
                int alive = 0;
                int dx = 0, dy = 0;
                for (int i = 0; i < 6; i++)
                {
                    dx = (int)Math.Round(Math.Cos(i * 45)) + x;
                    dy = (int)Math.Round(Math.Sin(i * 45)) + y;

                    if ((dx >= 0) && (dx < MAX) && (dy >= 0) && (dy < MAX)) { if (cells[dx, dy].lastState == '#') alive++; }
                }

                if (cells[x, y].state == '0')
                {
                    if (alive == 3) cells[x, y].state = '#';
                }
                if (cells[x, y].lastState == '#')
                {
                    if (alive == 2 || alive == 3) { cells[x, y].state = '#'; }
                    else { cells[x, y].state = '0'; }

                }
                //Console.WriteLine("x:" +x +" y:" +y + " = alive:" + alive);

            }
            updateConsole();
        }
    }
    class Cell
    {

        public Cell(char _state)
        {
            this.state = _state;
            this.lastState = _state;
        }
        public char state { get; set; }
        public char lastState { get; set; }
    }
}


// 0 = Dead
// # = alive


I tried to make sure the directions weren't unnecessarily counted twice and checked via debuging if it counted the living neighbours right; So far, no problem. After that I looked if I implemented the game rules right; seemed like it.

Solution:

There are two things that are incorrect about your code. Both of them are in this section:

                for (int i = 0; i < 6; i++)
                {
                    dx = (int)Math.Round(Math.Cos(i * 45)) + x;
                    dy = (int)Math.Round(Math.Sin(i * 45)) + y;

                    if ((dx >= 0) && (dx < MAX) && (dy >= 0) && (dy < MAX)) { if (cells[dx, dy].lastState == '#') alive++; }
                }

The first problem is that there are eight neighbouring squares you need to check, not six. So the 6 in the for loop needs to be 8.

Secondly, Math.Cos and Math.Sin both work in radians rather than degrees. 45° is the same angle as π/4 radians. Replace the use of 45 in your call to both Math.Cos and Math.Sin with Math.PI / 4.

I made these changes to your code, and it worked as expected.


While the above changes work, it seems a little odd to me to use trigonometry for something like this. A simpler solution is to have dx run in a loop from x - 1 to x + 1, and similarly for dy with y, and skip the case where dx == x and dy == y:

                for (dy = y - 1 ; dy <= y + 1; dy++)
                {
                    for (dx = x - 1; dx <= x + 1; dx++)
                    {
                        if (dx != x || dy != y)
                        {
                            if ((dx >= 0) && (dx < MAX) && (dy >= 0) && (dy < MAX)) { if (cells[dx, dy].lastState == '#') alive++; }
                        }
                    }
                }
Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login