Search code examples
c#procedural-generationcellular-automata

Why using Cellular Automata with 2d array gives bad results?


I'm trying to make a procedurally generated map/2d_array using Cellular Automata.

I found a good video explaining Cellular automata and followed it. Video link: https://www.youtube.com/watch?v=slTEz6555Ts

But for some reason I only get a fully filled 2d array with the same value and not a procedurally generated map like 2d array. I tried to Debug it and see what's the problem and for some reason this if statement is always false:

//check if neighbor is a - and if so add neighbor_wall_count
 if (temp_grid[k, j] == '-')
 {
    neighbor_wall_count++;
 }

And I can't find the reason why. Maybe you could help?

Heres all the code:

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //this line string is used for printing
            string line = "";
            //2d array size specifications
            int width = 10;
            int height = 10;
            //density = how much procent will be - in the array when i we make random noise
            int density = 60;
            //create the 2d array
            char[,] grid = new char[width, height];

            //This creates random noise in array or its a function make_noise_grid(density) from video https://www.youtube.com/watch?v=slTEz6555Ts
            for (int y = 0; y < height; y++)
            {
                line = "";
                for(int x = 0; x < width; x++)
                {
                    int rand = new Random().Next(1, 100);
                    if(rand > density)
                    {
                        grid[x, y] = '+';
                    }
                    else
                    {
                        grid[x, y] = '-';
                    }
                    line += grid[x, y];
                }
                Console.WriteLine(line);
            }

            // This is just a divider to divide random noise map from map with applied with cellulat automata
            Console.WriteLine("-------------------------------------------------------------------");

            //This section is the function apply_cellular_automation(grid, count) from video https://www.youtube.com/watch?v=slTEz6555Ts
            //This first for will determine how much times Cellular Automata will be added
            for (int i = 0; i < 1; i++)
            {
                //Create a temporary map
                char[,] temp_grid = grid;
                //Go through array
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        //create variable to store neighbor minuses (-)
                        int neighbor_wall_count = 0;
                        //go through neigbors
                        for (int j = y-1; j <= y+1; j++)
                        {
                            for(int k = x-1; k <= x+1; k++)
                            {
                                //check if in bounds of array if not just assume its -
                                if (j >= 0 && j < grid.GetLength(1) && k >= 0 && k < grid.GetLength(0))
                                {
                                    //check if this is not the coordinate whose neighbors we are checking
                                    if (j != y && k != x)
                                    {
                                        //check if neighbor is a - and if so add neighbor_wall_count
                                        if (temp_grid[k, j] == '-')
                                        {
                                            neighbor_wall_count++;
                                        }
                                    }
                                }
                                else
                                {
                                    neighbor_wall_count++;
                                }
                            }
                        }
                        //if there are more than 4 neighbors that are - make the coordinate a - and if not make it +
                        if (neighbor_wall_count > 4)
                        {
                            grid[x, y] = '-';
                        }
                        else
                        {
                            grid[x, y] = '+';
                        }
                    }
                }
            }

            // this is to print the array when we apply Cellular automata.
            for (int y = 0; y < height; y++)
            {
                line = "";
                for (int x = 0; x < width; x++)
                {
                    line += grid[x, y];
                }
                Console.WriteLine(line);
            }
        }
    }
}

And the result from this:

-------+--
++---+-+--
+--++--+-+
--+--+----
-+--+-----
----+-+---
---+--+++-
-+---++--+
+--+-----+
++---+--+-
-------------------------------------------------------------------
-++-+-+-+-
++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
-++++++++-

Solution

  • Almost 3 years later but i will post this in case this serves to anyone to see a working cellular automata cave system, your fault in your code is the condition in the [k,j] loops of checking if your are in the x and y block, your condition is reversed, this is the correct condition in if: (j != y || k != x)

    This is the working code:

        //this line string is used for printing
        string line = "";
        //2d array size specifications
        int width = 40;
        int height = 40;
        //density = how much procent will be - in the array when i we make random noise
        int density = 40;
        //create the 2d array
        char[,] grid = new char[width, height];
    
        //This creates random noise in array or its a function make_noise_grid(density) from video https://www.youtube.com/watch?v=slTEz6555Ts
        var random = new Random();
        for (int y = 0; y < height; y++)
        {
            line = "";
            for (int x = 0; x < width; x++)
            {
                int rand = random.Next(1, 100);
                if (rand > density)
                {
                    grid[x, y] = '#'; //wall
                }
                else
                {
                    grid[x, y] = '.'; //free space
                }
                line += grid[x, y];
            }
            Console.WriteLine(line);
        }
    
        // This is just a divider to divide random noise map from map with applied with cellulat automata
        Console.WriteLine("\\\\-------------------------------------------------------------------//");
    
        //This section is the function apply_cellular_automation(grid, count) from video https://www.youtube.com/watch?v=slTEz6555Ts
        //This first for will determine how much times Cellular Automata will be added
        for (int i = 0; i < 1; i++)
        {
            //char[,] temp_grid = DeepCopy(width, height, grid);
            char[,] temp_grid = (char[,])grid.Clone();
    
            //Go through array
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    //create variable to store neighbor minuses (-)
                    int neighbor_wall_count = 0;
                    //go through neigbors
                    for (int k = x - 1; k <= x + 1; k++)
                    {
                        for (int j = y - 1; j <= y + 1; j++)
                        {
                            //check if in bounds of array if not just assume its -
                            if (j >= 0 && j < grid.GetLength(1) && k >= 0 && k < grid.GetLength(0))
                            {
                                //check if this is not the coordinate whose neighbors we are checking
                                if (j != y || k != x)
                                {
                                    //check if neighbor is a # and if so add neighbor_wall_count
                                    if (temp_grid[k, j] == '#')
                                    {
                                        neighbor_wall_count++;
                                    }
                                }
                            }
                            else
                            {
                                neighbor_wall_count++;
                            }
                        }
                    }
    
                    if (neighbor_wall_count > 4)
                    {
                        grid[x, y] = '#';
                    }
                    else
                    {
                        grid[x, y] = '.';
                    }
                }
            }
        }
    
        // this is to print the array when we apply Cellular automata.
        for (int y = 0; y < height; y++)
        {
            line = "";
            for (int x = 0; x < width; x++)
            {
                line += grid[x, y];
            }
            Console.WriteLine(line);
        }
    
        Console.ReadKey();
    

    This is the result:

        .##..##...######.###########..###..#####
        ....##..#..#.#.#####.#.###.#.#..#..#.###
        ###.###..######.#.##.#...#.#####.###..##
        #.#.#######...##...##.##..#.#..#..##.###
        #######..##.########.#....#.##.###....#.
        ####...#.####..#.#.#.#.###..#..###..##.#
        ###..###..##.....##.###..##.###.#.#.##.#
        ##..##..#.###.#...##..#.##..##.#..#...##
        .###.#.###.####.#..##....#.....##...##.#
        #.##.########......######.##.##.##.##.#.
        .##.##..##.##...##.##.#.#.######..#.##.#
        #.###..##.###..###########...##..#.#.#..
        ...##.#....##..#.##...#...###..#####.###
        ...##.##......#.....####..####...####...
        .##...#.##.#.##..#...###.##...#.#.##...#
        .##.####....#.#####.##.##.#..#######..#.
        ##########...####.##.####.####..#..#.#.#
        ###.##..#.#.#..####.#...####.#.##..#..#.
        #.#.#####.########.###..#...###.#..#..#.
        #..#.####....###.##########..###....#.#.
        ##..#.###.##..#####.##.##.##...#..#.####
        ####.#.#.#.#...###.#.####.##.#...##.####
        ##.#.##.#.#.###..####.####.####.###.#.#.
        ##.#.###.#.#.##.#.#.#.####...#.#...#.###
        .####.###..#..###...#.###.####...#####..
        #.####.###..#..#.######..#.##.#.......#.
        ..#.#..#.#.##.#..#.#..##..#.....#.######
        ...####.###.#.##...#####.#.###.####.....
        #####..##.##..###.###.#.###.##..#...#...
        ###.#..##.##.#.##.##.##...#......#####.#
        .######...##.###.####.#..#.#.####.#.##.#
        #.#...###.####..###.###.####.###.#.###.#
        ##.###..#..#####...####.###.###..##.#.##
        #..##....##.##.#....#.####..##.#..##..##
        .#..#....##.##.#...####..###.####..##.#.
        #..##..#..####.#..#######.###.#..#.###.#
        ####.#.#...#.#..#######.####.####.#.#.##
        .........####..#....#.##.#..##.##.#..#.#
        ###.#.#...#####.###.##..##...####.###.##
        #..##.#...#..####.###..#########.##.###.
        \\-------------------------------------------------------------------//
        #..#####.###############################
        ##...##...###########.#.###.#.##..#.####
        #..########...##.####.#.#.#.#.....#.####
        #######..############......####.###...##
        ############..###.#.#.#....#....#....###
        #######...##....###.#.#....#.#####....##
        ###......####.....##...###...#.#.#....##
        ###...##.#####.....###........#......###
        ###.#.########.....###.##.....#.......##
        #####.########.....###...#..#.##....##.#
        #####.#######.....########..###....##...
        ...###.....##...####.#.#..#######.#.#.##
        ...###.#........#..#####...###...####...
        .....#...............##...##....####...#
        #..#.###.......#....#####..#.#.#.###....
        ####.####....#####...#####.#...#.##....#
        ########......#######..######.#####....#
        ##########.#.#########.#.#.####........#
        ##.#####.#...#########.####..###.......#
        ##..######.###############....#......#.#
        ###..####.....#############...#....#.###
        ###.#.###.#...###############....#.#.###
        ###.#.##.......#####.######.#......#.###
        ###.#####...####.#.#.##########..#####.#
        #########......#.#.#.#####..#.........##
        .####.###.......#....###..##......####.#
        ...####.###..#....#####....##....#.....#
        #.###..#####.#.#..#######.#......#.#...#
        ######.#####..##...#####...#.....###....
        ######...####.########...#.........##...
        ####...#.####.#.######....#...#..#######
        ######.....#####..####.#.##.#####.######
        #........######.....###########...##.###
        #...#......####....############....#.#.#
        #..#......#####....############...####.#
        ###........##.#...######.########..#####
        #.........###......#############.#.#.###
        ###.......####..######..###..#####.#..##
        #.........######...#...####.######.#.###
        ######.#.###############################