-
Notifications
You must be signed in to change notification settings - Fork 0
/
day17_numpy.py
105 lines (86 loc) · 2.83 KB
/
day17_numpy.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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
from typing import Tuple
import itertools
import numpy as np
"""
* . is inactive, # is active
* a game can see its 26 immidiate neighbours
* if a game is active and exactly 2 or 3 of its neighbours are active, it remains
active. Otherwise it becomes inactive.
* If a game is inactive but exactly 3 of its neighbours are active, the game
becomes active. Otherwise it remains inactive.
* How many cubes are active after the sixth cycle?
"""
class GameofLife:
def __init__(self, raw: str, n_dims=3) -> None:
self.grid: np.ndarray
self.set_grid(raw, n_dims)
self.cycle: int = 0
def set_grid(self, raw: str, goal_dim: int) -> None:
y_list = []
for y, line in enumerate(raw.splitlines()):
x_list = []
for x, char in enumerate(line):
if char == '#':
x_list.append(1)
else:
x_list.append(0)
y_list.append(x_list)
self.grid = y_list
for d in np.arange(0, goal_dim - 2):
self.grid = [self.grid]
self.grid = np.array(self.grid)
def count_active_neighbours(self, index: Tuple[int, ...]) -> int:
neighbour_slicer = [slice(i - 1, i + 2) if i != 0 else slice(0, 2) for i in index]
neighbours = self.grid[tuple(neighbour_slicer)]
a_neighbours = neighbours.sum() - self.grid[index]
return a_neighbours
def pad_grid(self) -> None:
new_grid = np.zeros([d + 2 for d in self.grid.shape])
new_grid[tuple(slice(1, -1) for d in self.grid.shape)] = self.grid
self.grid = new_grid
def step(self) -> None:
self.pad_grid()
new_grid = np.copy(self.grid)
for index in itertools.product(*[range(d) for d in self.grid.shape]):
a_neighbours = self.count_active_neighbours(index)
is_active = self.grid[index]
if is_active and a_neighbours in (2, 3):
continue
elif not is_active and a_neighbours == 3:
new_grid[index] = 1
else:
new_grid[index] = 0
self.grid = new_grid
def get_tot_active(self):
return self.grid.sum()
def get_tot_active_at_cycle(self, cycle_goal: int = 6) -> int:
assert cycle_goal > self.cycle
while self.cycle != cycle_goal:
self.step()
self.cycle += 1
return self.get_tot_active()
TEST_RAW = """.#.
..#
###"""
#
# Unit tests
#
game = GameofLife(TEST_RAW, n_dims=3)
assert game.get_tot_active_at_cycle() == 112
game = GameofLife(TEST_RAW, n_dims=4)
assert game.get_tot_active_at_cycle() == 848
#
# Problem
#
RAW = """##.#....
...#...#
.#.#.##.
..#.#...
.###....
.##.#...
#.##..##
#.####.."""
game = GameofLife(RAW, n_dims=3)
print(game.get_tot_active_at_cycle())
game = GameofLife(RAW, n_dims=4)
print(game.get_tot_active_at_cycle())