-
Notifications
You must be signed in to change notification settings - Fork 140
Expand file tree
/
Copy pathd17.py
More file actions
95 lines (76 loc) · 2.33 KB
/
d17.py
File metadata and controls
95 lines (76 loc) · 2.33 KB
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
from collections import namedtuple
import re
class Vector(namedtuple('Vector', 'x y')):
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
clay = set()
with open('./17/input.txt') as f:
regex = r'(y)*(x)*=(\d+), (y)*(x)*=(\d+)..(\d+)'
for line in f:
m = re.match(regex, line)
y1, x1, n1, y2, x2, n2, n3 = m.groups()
n1, n2, n3 = int(n1), int(n2), int(n3)
if y1:
for x in range(n2, n3+1):
clay.add(Vector(x, n1))
else:
for y in range(n2, n3+1):
clay.add(Vector(n1, y))
SPRING = Vector(500, 0)
UP = Vector(0, -1)
DOWN = Vector(0, 1)
LEFT = Vector(-1, 0)
RIGHT = Vector(1, 0)
def simulate():
maxy, miny = max(p.y for p in clay), min(p.y for p in clay)
flowing, still, to_fall, to_spread = set(), set(), set(), set()
to_fall.add(SPRING)
while to_fall or to_spread:
while to_fall:
tf = to_fall.pop()
res = fall(tf, maxy, clay, flowing)
if res:
to_spread.add(res)
while to_spread:
ts = to_spread.pop()
rl, rr = spread(ts, clay, flowing, still)
if not rr and not rl:
to_spread.add(ts + UP)
else:
if rl:
to_fall.add(rl)
if rr:
to_fall.add(rr)
# Output
print('Total Water = %d' %
len([p for p in (flowing | still) if p.y >= miny]))
print('Still Water = %d' % len([p for p in still if p.y >= miny]))
def fall(pos, maxy, clay, flowing):
while pos.y < maxy:
posd = pos + DOWN
if posd not in clay:
flowing.add(posd)
pos = posd
elif posd in clay:
return pos
return None
def spread(pos, clay, flowing, still):
temp = set()
pl = spread_r(pos, LEFT, clay, still, temp)
pr = spread_r(pos, RIGHT, clay, still, temp)
if not pl and not pr:
still.update(temp)
else:
flowing.update(temp)
return pl, pr
def spread_r(pos, off, clay, still, temp):
pos1 = pos
while pos1 not in clay:
temp.add(pos1)
pos2 = pos1 + DOWN
if pos2 not in clay and pos2 not in still:
return pos1
pos1 = pos1 + off
return None
if __name__ == '__main__':
simulate()