Search code examples
pythonrandomnoiseperlin-noisecellular-automata

Cellular Automata returns all 0s [PYTHON]


I have written a program (see below) as an implementation of cellular automata in python. When I run the program, I receive a pattern of random seeded noise and the new pattern that has been run through the program. The "." are zeros and the "#" is a one. The issue is, when I run the program I receive the random noise (looks right) but when I receive the smoothed version, I only get periods (zeros).

app.py

import perlin

line = ""

noise = perlin.Noise(20,20, 420, 1)

print(" ")

for i in range(20):
    line += "="
print(line)

# Parses smoothed map
line = ""

print(" ")
for i in range(len(noise.map)):
    for j in range(len(noise.map[i])):
        if noise.map[i][j] == 0:
            line += "."
        else:
            line += "#"
    print(line)
    line = ""

perlin.py

import numpy as np

class Noise:
    def inbounds(self,x,y):
        if (x >= 0 and x <= self.width) and (y >=0 and y <= self.height):
            return True
        else:
            return False

    def smooth(self,iterations):
        for i in range(iterations):
            temp_map = self.map
            for j in range(self.height):
                for k in range(self.width):
                    neighbor_wall_count = 0
                    for y in range(j-1,j+1):
                        for x in range(k-1, k+1):
                            if self.inbounds(x,y):
                                if y != j or x != k:
                                    if temp_map[y][x] == 1:
                                        neighbor_wall_count += 1
                            else:
                                neighbor_wall_count += 1
                    if neighbor_wall_count > 3:
                        self.map[j][k] = 1
                    else:
                        self.map[j][k] = 0


    def __init__(self, width, height, seed, iter):
        # Sets all of the self variables
        self.width = width
        self.height = height
        self.seed = seed
        np.random.seed(self.seed)
        w, h = self.width, self.height
        # Declares the pattern map list
        map = [[0 for i in range(w)] for j in range(h)]

        #Generator
        for y in range(h):
            for x in range(w):
                map[y][x] = np.random.randint(0,2)
        self.map = map

        # Parser
        line = ""
        for i in range(len(self.map)):
            for j in range(len(self.map[i])):
                if self.map[i][j] == 0:
                    line += "."
                else:
                    line += "#"
            print(line)
            line = ""
        self.smooth(iter)

Output

#..###.#....#...#..#
..#####..##.#.###..#
###.###.###..####...
###....##..###.#.#..
#.#.###..##...##..##
#......#..#..#.##..#
.###.#.#.##..#...##.
##...##....#####..#.
#..##...#....###..#.
#.....#.##.####...##
#..#..#.#.##..##..#.
.#.###.###...#..#..#
...#.##....#..#.##..
#.#..#.#.#.###..####
.#..#....#..##.###..
#..#.#.#........###.
.#####..#.#..####...
##..#.#.##.##..#..##
##.#.#.##.####.#..##
####.........##..##.
 
====================
 
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................

Solution

  • the stop argument in python ranges is excluded from the range (range < stop)

    For a positive step, the contents of a range r are determined by the formula r[i] = start + step*i where i >= 0 and r[i] < stop.

    For a negative step, the contents of the range are still determined by the formula r[i] = start + step*i, but the constraints are i >= 0 and r[i] > stop.

    you can tune the smoothness (eg 3 here), by changing the value of that test:

    if neighbor_wall_count > 3: