-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaoc2022_23_vis.py
executable file
·129 lines (120 loc) · 4.21 KB
/
aoc2022_23_vis.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
#!/usr/bin/env python3
import sys
import os
sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), "../../lib"))
import visutil
class Map:
def __init__(self, infile):
self.grid = set()
self.elves = 0
self.rounds = 0
for y, r in enumerate(open(infile)):
for x, c in enumerate(r):
if c == '#':
self.grid.add((x,y))
self.elves += 1
self.dirs = [
((0,-1), (-1,-1), (+1,-1)), # N
((0,+1), (-1,+1), (+1,+1)), # S
((-1,0), (-1,-1), (-1,+1)), # W
((+1,0), (+1,-1), (+1,+1)), # E
]
self.bboxfile = os.path.join(os.path.dirname(sys.argv[0]), ".vis_bbox")
self.vis = visutil.Visualizer(default_speed=100, default_zoom=4, novis_arg=True)
if self.vis:
self.bmp = visutil.Bitmap(*self.get_bbox(), border=1)
print("bitmap size:", self.bmp.size)
self.vis.start(source=self.bmp)
self.update_bitmap()
self.vis.write(initial=True)
def get_bbox(self):
try:
with open(self.bboxfile) as f:
return eval(f.read())
except EnvironmentError:
return visutil.get_extent(self.grid)
def save_bbox(self):
try:
with open(self.bboxfile, 'w') as f:
f.write(repr(visutil.get_extent(self.grid)))
except EnvironmentError:
pass
def dump(self, title=None, with_map=True):
if title:
print(title + ":")
x0 = min(x for x,y in self.grid)
y0 = min(y for x,y in self.grid)
x1 = max(x for x,y in self.grid) + 1
y1 = max(y for x,y in self.grid) + 1
if with_map:
for y in range(y0, y1):
print(''.join(".#"[(x,y) in self.grid] for x in range(x0, x1)))
print((y1-y0) * (x1-x0) - self.elves)
if with_map:
print()
def run_single(self):
self.old2new = {}
self.occupied = {}
for x,y in self.grid:
valid_dirs = []
for dirspec in self.dirs:
if not any(((x+dx, y+dy) in self.grid) for dx,dy in dirspec):
valid_dirs.append((x+dirspec[0][0], y+dirspec[0][1]))
if not(valid_dirs) or (len(valid_dirs) == 4):
tx,ty = x,y
else:
tx,ty = valid_dirs[0]
try:
occpos = self.occupied[(tx,ty)]
self.old2new[occpos] = occpos
self.old2new[(x,y)] = (x,y)
except KeyError:
self.old2new[(x,y)] = (tx,ty)
self.occupied[(tx,ty)] = (x,y)
oldgrid = self.grid
self.grid = {*self.old2new.values()}
assert len(self.grid) == self.elves
self.dirs.append(self.dirs.pop(0))
self.rounds += 1
if self.vis:
self.update_bitmap(oldgrid)
self.vis.write()
return not(self.grid == oldgrid)
def run_to(self, end=1, verbosity=0):
if verbosity >= 1:
self.dump("initial")
cont = True
while self.rounds < end:
cont = self.run_single()
if not cont: break
if verbosity >= 2:
self.dump(f"after {self.rounds} rounds")
if (verbosity == 1) or not(cont):
self.dump(f"final state after {self.rounds} rounds")
def update_bitmap(self, oldgrid=None):
if oldgrid is None:
oldgrid = self.grid
self.bmp.clear()
for x, y in (self.grid - oldgrid):
self.bmp.put(x, y, 255, 255, 128)
for x, y in (self.grid & oldgrid):
self.bmp.put(x, y, 192, 192, 64)
def close(self):
if self.vis:
try:
self.vis.write(final=True)
except (EnvironmentError, KeyboardInterrupt):
pass
self.vis.stop()
if __name__ == "__main__":
m = Map("input.txt")
try:
while m.run_single():
if m.rounds == 10:
m.dump(with_map=False)
# if not(m.rounds % 100): print(m.rounds, "...")
print(m.rounds)
m.save_bbox()
except (EnvironmentError, KeyboardInterrupt):
pass
m.close()