Create a gist now

Instantly share code, notes, and snippets.

My implementation of Wireworld in Python
from __future__ import print_function
from time import sleep
import os
type_to_rep = {
'empty': '.',
'head': 'H',
'tail': 'T',
'conductor': '=',
'invalid': 'X',
}
rep_to_type = dict((v, k) for k, v in type_to_rep.items())
class Engine:
def __init__(self, width=None, height=None, text=None, step_time=0.2):
assert (width is not None and height is not None) or text is not None
self.step_time = step_time
if width is not None and height is not None:
self.width = width
self.height = height
self._data = [[type_to_rep['empty']] * height for _ in range(width)]
else:
self.load_from_text(text)
self.width = len(self._data)
self.height = len(self._data[0])
self.x_off = [-1, -1, -1, 0, 0, 1, 1, 1]
self.y_off = [-1, 0, 1, -1, 1, -1, 0, 1]
def load_from_text(self, s):
self._data = [[i for i in j.split(' ')] for j in s.split('\n')]
def dump_to_text(self):
return '\n'.join(' '.join([str(i) for i in b]) for b in self._data)
def __setitem__(self, key, item):
assert isinstance(key, tuple) and len(key) == 2, 'Must provide x and y coordinates for lookup'
if isinstance(key[0], int):
key = (slice(key[0], key[0]+1, None), key[1])
if isinstance(key[1], int):
key = (key[0], slice(key[1], key[1]+1, None))
if isinstance(item, str) and item in type_to_rep:
item = type_to_rep[item]
for i in self._data[key[0]]:
i[key[1]] = [item] * len(i[key[1]])
def __getitem__(self, key):
assert isinstance(key, tuple) and len(key) == 2, 'Must provide x and y coordinates for lookup'
if isinstance(key[0], int) and isinstance(key[1], int):
if key[0] < 0 or key[0] >= self.width or key[1] < 0 or key[1] >= self.height:
return 'invalid'
return rep_to_type[self._data[key[0]][key[1]]]
if isinstance(key[0], int):
key = (slice(key[0], key[0]+1, None), key[1])
if isinstance(key[1], int):
key = (key[0], slice(key[1], key[1]+1, None))
return [[i for i in d[key[1]]] for d in self._data[key[0]]]
def clear_screen(self):
os.system('cls' if os.name == 'nt' else 'clear')
def count_neighbors_of_type(self, t, x, y, ignore):
c = 0
for x_shift, y_shift in zip(self.x_off, self.y_off):
if self[x+x_shift, y+y_shift] == t and (x+x_shift, y+y_shift) not in ignore:
c += 1
return c
def __repr__(self):
message = ' ' + ' '.join([str(i)[-1] for i, _ in enumerate(self._data[0])]) + '\n'
message += '\n'.join(str(c)[-1] + ' ' + ' '.join([str(i) for i in b]) + ' ' + str(c)[-1] for c, b in enumerate(self._data))
message += '\n ' + ' '.join([str(i)[-1] for i, _ in enumerate(self._data[0])])
return message
def step(self):
self.clear_screen()
changed = set()
for x in range(self.width):
for y in range(self.height):
if self[x, y] == 'conductor':
if self.count_neighbors_of_type('head', x, y, changed) in [1, 2]:
self[x, y] = 'head'
changed.add((x, y))
for x in range(self.width):
for y in range(self.height):
if self[x, y] == 'head' and (x, y) not in changed:
self[x, y] = 'tail'
changed.add((x, y))
elif self[x, y] == 'tail' and (x, y) not in changed:
self[x, y] = 'conductor'
changed.add((x, y))
print(self)
def run(self, n_steps=-1):
if n_steps == -1:
while True:
self.step()
sleep(self.step_time)
for i in range(n_steps):
self.step()
sleep(self.step_time)
if __name__ == '__main__':
# coincidence detector
engine = Engine(text='''. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . = = . = = = = = = = . . .
. . . = = = = = = = = . = . = . = . . . . = . .
. = = . . . . . . . . = = = = = = . . . . = . .
= . . = = . . . = = = . . = . . . . . . . = . .
= . . . . = . = . . . . = = = . . . . . = . . .
= . . . . = . = . . . = . . . = = = . = . = = .
= . . . . . = . . . . . = T H . . . = . . . . =
= . . = = = . = = = = . . . . . . = . . . . . =
= . = . . . . . . . . = = = = = = . . . . . . =
= . . = = = T H = = = . . . . . . = . . = = = .
= . . . . . . . . . . = = = = = = . . = . . . =
. = = = = = = = = = = . . . . . . . . . = T H .''')
# print(engine)
engine.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment