-
Notifications
You must be signed in to change notification settings - Fork 0
/
simulator.py
131 lines (106 loc) · 4.05 KB
/
simulator.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import enum
def splitlines_with_pad(s):
lines = s.splitlines()
max_len = max(len(l) for l in lines)
return [line.ljust(max_len) for line in lines]
class Brush:
def __init__(self, r, c, direction):
self.r = r
self.c = c
self.direction = direction
def advance(self, advance_fn):
self.direction = advance_fn(self.direction)
def move(self, row_count, col_count):
self.r += self.direction[0]
self.c += self.direction[1]
if self.r >= row_count:
self.r = 0
elif self.r < 0:
self.r = row_count - 1
if self.c >= col_count:
self.c = 0
elif self.c < 0:
self.c = col_count - 1
def __hash__(self):
return hash((self.r, self.c, self.direction))
def __eq__(self, other):
return (self.r, self.c, self.direction) == (other.r, other.c, other.direction)
def __repr__(self):
return f"Brush({self.r}, {self.c}, {self.direction})"
class Simulator:
def __init__(self, grid, language, *, brush_style="bold"):
stability_index = 4
brush_index = 3
self.brushes = set()
fake_lang = (None, None, None, None, 1)
self.grid = [
[(language.get(col, fake_lang)[stability_index], col) for col in row]
for row in splitlines_with_pad(grid)
]
self.row_count = len(self.grid)
self.col_count = max(len(row) for row in self.grid)
self.language = language
for r in range(self.row_count):
for c in range(self.col_count):
char = self.grid[r][c][1]
if char not in self.language:
continue
brush = self.language[char][brush_index]
if brush is not None:
self.add_brush(Brush(r, c, brush))
self.brush_style = brush_style
def add_brush(self, brush):
self.brushes.add(brush)
def simulate(self):
"""Returns whether this was the last step of the simulation."""
locs = set()
brushes = list(self.brushes)
self.brushes.clear()
for brush in brushes:
if self.grid[brush.r][brush.c][1] in self.language:
(advance_fn, reproduce, _, _, _) = self.language[
self.grid[brush.r][brush.c][1]
]
if reproduce:
locs.add((brush.r, brush.c))
self.brushes.add(brush)
brush = Brush(brush.r, brush.c, brush.direction)
brush.advance(advance_fn)
locs.add((brush.r, brush.c))
if brush.direction is not None:
brush.move(self.row_count, self.col_count)
self.brushes.add(brush)
for r, c in locs:
stability, current = self.grid[r][c]
if stability == 1:
(_, _, next_char, _, _) = self.language[current]
stability_index = 4
if next_char in self.language:
transform = (self.language[next_char][stability_index], next_char)
else:
transform = (1, next_char)
else:
transform = (stability - 1, current)
self.grid[r][c] = transform
return len(self.brushes) != 0
def get_grid(self):
return self.grid
def __str__(self):
string = ""
brushes = set((brush.r, brush.c) for brush in self.brushes)
for row in range(self.row_count):
for col in range(self.col_count):
is_brush = (row, col) in brushes
if is_brush:
string += self._format_brush(self.grid[row][col][1])
else:
string += self.grid[row][col][1]
string += "\n"
return string
def _format_brush(self, char):
style = self.brush_style
if style == "bold":
return "\033[1m" + char + "\033[0m"
if style == "inverse":
return "\033[7m" + char + "\033[m"
return char