Cellular automata in Python
#!/usr/bin/env python3 | |
""" | |
Cellular automata in Python | |
""" | |
import sys | |
Z = '.' | |
O = '#' | |
def init(width=79): | |
""" The initial string | |
""" | |
m = width // 2 | |
s = "" | |
for i in range(m): | |
s += Z | |
s += O | |
for i in range(m): | |
s += Z | |
return s | |
def from_bin(bb): | |
""" | |
>>> from_bin([1,0,0]) | |
4 | |
""" | |
r = 0 | |
for i, b in enumerate(bb): | |
j = len(bb) - i - 1 | |
r += b * 2**j | |
return r | |
def to_bin(i, min_len=8): | |
""" | |
>>> to_bin(4, min_len=5) | |
[0, 0, 1, 0, 0] | |
>>> to_bin(5, min_len=5) | |
[0, 0, 1, 0, 1] | |
""" | |
bs = [] | |
while i > 0: | |
r = i % 2 | |
bs = [r] + bs # Prepend r | |
i = i // 2 | |
if len(bs) < min_len: | |
bs = [0] * (min_len - len(bs)) + bs | |
return bs | |
def b2s(b): | |
r = "" | |
for x in b: | |
r += (O if x == 1 else Z) | |
return r | |
def s2b(s): | |
return [1 if x == O else 0 for x in s] | |
def interpret_rule(rule, state): | |
""" | |
>>> interpret_rule(16, [Z,O,O]) | |
'.' | |
>>> interpret_rule(16, [O,Z,Z]) | |
'#' | |
>>> interpret_rule(16, [Z,Z,O]) | |
'.' | |
""" | |
i = from_bin(s2b(state)) | |
bin_rule = b2s(to_bin(rule, min_len=8)) | |
return bin_rule[::-1][i] # Reverse the rule bits | |
def evolve(rule, state, w=3): | |
""" | |
w is window width (3 for CA) | |
""" | |
m = len(state) | |
s = "" | |
rr = [i for i in range(m)] | |
# Shift starting index left by one | |
rr = [rr[-1]] + rr[:-1] | |
for l in rr: | |
if l > m - w: | |
r = w - m + l | |
cell = state[l:l+w] + state[:r] | |
else: | |
cell = state[l:l+w] | |
s += interpret_rule(rule, cell) | |
return s | |
def main(rule, iters=39): | |
s = init() | |
print(s) | |
for i in range(iters): | |
s = evolve(rule, s) | |
print(s) | |
if __name__ == "__main__": | |
if len(sys.argv) != 2: | |
print("Usage: %s RULENO" % (sys.argv[0])) | |
exit() | |
rule = int(sys.argv[1]) | |
main(rule) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment