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
| import re
class Cube4D(object):
def __init__(self, raw_input):
self.cube = {
f'x{xi}y{yi}z0w0': x
for yi, y in enumerate(raw_input.strip().splitlines())
for xi, x in enumerate(y.strip())
}
def all_neighbours(self, c):
x0, y0, z0, w0 = [int(i) for i in re.match(r'^x(-*\d+)y(-*\d+)z(-*\d+)w(-*\d+)$', c).groups()]
return [
self.cube.get(f'x{x}y{y}z{z}w{w}', '.')
for w in range(w0-1, w0+2)
for z in range(z0-1, z0+2)
for y in range(y0-1, y0+2)
for x in range(x0-1, x0+2)
if (z, y, x, w) != (z0, y0, x0, w0)
]
def count_active_neighbours(self, c):
return len([ n for n in self.all_neighbours(c) if n == '#' ])
def count_all_active(self):
return len([ c for c in self.cube.values() if c == '#' ])
def get_new_state(self, c):
if self.cube.get(c, '.') == '#':
if self.count_active_neighbours(c) in [2, 3]:
return '#'
else:
return '.'
elif self.cube.get(c, '.') == '.' and self.count_active_neighbours(c) == 3:
return '#'
else:
return '.'
def edges(self):
xs = [ int(re.search(r'x(-*\d+)', c).group(1)) for c in self.cube.keys() ]
ys = [ int(re.search(r'y(-*\d+)', c).group(1)) for c in self.cube.keys() ]
zs = [ int(re.search(r'z(-*\d+)', c).group(1)) for c in self.cube.keys() ]
ws = [ int(re.search(r'w(-*\d+)', c).group(1)) for c in self.cube.keys() ]
return min(xs), max(xs), min(ys), max(ys), min(zs), max(zs), min(ws), max(ws)
def cycle(self):
new_cube = {}
xmin, xmax, ymin, ymax, zmin, zmax, wmin, wmax = self.edges()
for x in range(xmin-1, xmax+2):
for y in range(ymin-1, ymax+2):
for z in range(zmin-1, zmax+2):
for w in range(wmin-1, wmax+2):
new_cube[f'x{x}y{y}z{z}w{w}'] = self.get_new_state(f'x{x}y{y}z{z}w{w}')
self.cube = new_cube
if __name__ == '__main__':
c = Cube4D(INPUT)
for _ in range(6):
c.cycle()
print(c.count_all_active())
|