@@ -48,6 +48,55 @@ def life_rule(X: np.ndarray, rulestring: str) -> np.ndarray:
48
48
return birth_rule | survival_rule
49
49
50
50
51
+ def rps_life_rule (X : np .ndarray , cycle_thresholds : list ) -> np .ndarray :
52
+ """A generalized rock-paper-scissors (RPS) life rule that accepts a rulestring in B/S notation
53
+
54
+ An RPS rule is a multistate rule in which states are arranged in a cycle
55
+ e.g. red->green->blue->red. A red cell which has a certain number, N, of green neighbours
56
+ becomes green. A green cell with N blue neighbours becomes blue, and so on.
57
+
58
+ Parameters
59
+ ----------
60
+ X : np.ndarray
61
+ A three-dimensional array of input board matrices, one for each state. The order of the
62
+ matrices defines the cyclic ordering of the states.
63
+ cycle_thresholds : list
64
+ A list of integers, each of which is a number of appropriately coloured neighbours which
65
+ will cause a state transition in a cell.
66
+
67
+ Returns
68
+ -------
69
+ np.ndarray
70
+ Updated boards after applying the rule
71
+ """
72
+ # Compute neighbors matrix for each state.
73
+ neighbors = np .zeros_like (X )
74
+ for state in range (len (X )):
75
+ neighbors [state ] = _count_neighbors (X [state ])
76
+
77
+ updated = np .zeros_like (X )
78
+ for state in range (len (X )):
79
+ # A cell cycles into this state if a sufficient number of its
80
+ # neighbors are in this state.
81
+ cycles_in = np .logical_and (
82
+ X [state - 1 ] == 1 , np .isin (neighbors [state ], cycle_thresholds )
83
+ )
84
+ # Given that it is alive, a cell cycles out of this state if a
85
+ # sufficient number of its neighbors are in the next state.
86
+ # It must also be in this state.
87
+ cycles_out = np .isin (neighbors [(state + 1 ) % len (X )], cycle_thresholds )
88
+ # A cell lives in this state in the next generation if it either is alive
89
+ # and does not cycle out, or it cycles in.
90
+ alive = np .logical_or (
91
+ np .logical_and (X [state ] == 1 , np .logical_not (cycles_out )),
92
+ cycles_in ,
93
+ )
94
+
95
+ updated [state ] = alive
96
+
97
+ return updated
98
+
99
+
51
100
def _parse_rulestring (r : str ) -> Tuple [List [int ], List [int ]]:
52
101
"""Parse a rulestring"""
53
102
pattern = re .compile ("B([0-8]+)?/S([0-8]+)?" )
0 commit comments