-
Notifications
You must be signed in to change notification settings - Fork 0
/
ca.py
86 lines (67 loc) · 2.81 KB
/
ca.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
import numpy as np
from core.ca import CA
def create_wolfram_ca_instance_from_pattern_and_rule_number(pattern, rule_number):
return WolframCA(len(pattern), len(pattern), rule_number, init_method="specified", initial_states=pattern)
class WolframCA(CA):
def __init__(
self,
width,
height,
rule_number: int,
init_method="random",
initial_states=np.array([])
):
super().__init__(width, height, init_method, initial_states)
self.rule_number = rule_number
self.rule_binary = format(rule_number, '08b')
self.board = np.zeros(shape=(height, width), dtype=int)
self.initialize(init_method, initial_states)
def initialize(self, init_method, initial_states):
match init_method:
case "random":
self.board[0] = np.random.choice([0, 1], size=self.width)
case "center_one":
row = np.zeros(self.width, dtype=int)
row[int(self.width / 2)] = 1
self.board[0] = row
case "specified":
self.board[0] = initial_states
def evolve_step(self, step, current_state=None):
if current_state is not None:
board = current_state
else:
board = self.board.copy()
current_row_idx = step if step < self.height else self.height - 1
current_states = board[current_row_idx]
next_states = np.zeros(self.width, dtype=int)
for col in range(self.width):
left_neighbor = 0 if col == 0 else current_states[col - 1]
right_neighbor = 0 if col == self.width - 1 else current_states[col + 1]
neighbors = [left_neighbor, current_states[col], right_neighbor]
next_state = self.get_next_state(neighbors)
next_states[col] = next_state
board = self.store_next_states(step, next_states, board)
return board
def evolve(self, steps):
current_board = None
for step in range(steps):
current_board = self.evolve_step(step, current_board)
return current_board
def evolve_and_apply(self, steps):
current_board = self.evolve(steps)
self.apply(current_board)
def apply(self, board):
self.board = board
def get_next_state(self, neighbors):
rule_idx = abs(int(''.join(map(str, neighbors)), 2) - 7)
return int(self.rule_binary[rule_idx])
def store_next_states(self, step, next_states, board):
if step < self.height - 1:
board[step + 1] = next_states
else:
board = self.shift_down(next_states, board)
return board
def shift_down(self, next_states, board):
board = np.delete(board, (0,), axis=0)
board = np.vstack([board, next_states])
return board