-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcellular_automata.py
94 lines (69 loc) · 2.97 KB
/
cellular_automata.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from scipy.signal import convolve2d
# Parameters
WIDTH, HEIGHT = 200, 200
RULE = "B3/S23"
KERNEL_SIZE = 3 # Moore neighborhood
# Initialize the grid with a sparse random distribution
grid = np.random.choice([0, 1], size=(HEIGHT, WIDTH),
p=[0.85, 0.15]).astype(np.uint8)
def create_kernel(size):
"""Create a convolution kernel of given size."""
kernel = np.ones((size, size), dtype=np.uint8)
kernel[size // 2, size // 2] = 0 # Exclude the center cell
return kernel
def parse_rule(rule):
"""Parse the rule string (e.g., 'B3/S23') into birth and survival conditions."""
if '/' not in rule or not rule.startswith('B') or 'S' not in rule:
raise ValueError("Invalid rule format. Expected 'Bx/Sy'.")
birth, survive = rule.split('/')
try:
birth_conditions = list(map(int, birth[1:]))
survive_conditions = list(map(int, survive[1:]))
except ValueError:
raise ValueError(
"Invalid rule format. Expected 'Bx/Sy' with numeric values.")
return birth_conditions, survive_conditions
def compute_neighbors(grid, kernel):
"""Calculate the number of alive neighbors for each cell."""
return convolve2d(grid, kernel, mode='same', boundary='wrap').astype(np.uint8)
def apply_rule(grid, neighbors, birth_conditions, survive_conditions):
"""Update the grid based on birth and survival rules."""
birth_mask = (grid == 0) & np.isin(neighbors, birth_conditions)
survive_mask = (grid == 1) & np.isin(neighbors, survive_conditions)
grid[:] = 0 # Reset all cells to dead
grid[birth_mask | survive_mask] = 1 # Apply rules
return grid
def update(frame, img, grid, birth_conditions, survive_conditions, kernel):
"""Update function for the animation."""
neighbors = compute_neighbors(grid, kernel)
apply_rule(grid, neighbors, birth_conditions, survive_conditions)
img.set_data(grid) # Update displayed image
return img,
def create_plot(grid):
"""Set up the figure and axis for visualization."""
fig, ax = plt.subplots(figsize=(10, 10))
img = ax.imshow(grid, cmap='gray', interpolation='nearest')
ax.set_title(f"2D Cellular Automaton (Rule {RULE})")
ax.axis('off')
return fig, ax, img
def on_close(event, ani):
"""Stop the animation when the window is closed."""
if ani.event_source is not None:
ani.event_source.stop()
def main():
"""Main function to initialize and run the simulation."""
birth_conditions, survive_conditions = parse_rule(RULE)
kernel = create_kernel(KERNEL_SIZE)
fig, ax, img = create_plot(grid)
ani = animation.FuncAnimation(
fig, update,
fargs=(img, grid, birth_conditions, survive_conditions, kernel),
interval=50, blit=False, cache_frame_data=False
)
fig.canvas.mpl_connect('close_event', lambda event: on_close(event, ani))
plt.show()
if __name__ == "__main__":
main()