-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path14_Regolith_Reservoir.py
74 lines (56 loc) · 1.67 KB
/
14_Regolith_Reservoir.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
from __future__ import annotations
from aoc import *
from collections import defaultdict
from more_itertools import windowed, chunked, ilen
def read_cave():
cave = defaultdict(int)
for line in read(sep=' -> |,'):
for p1, p2 in windowed(chunked(line, 2), 2):
cave.update((p, 1) for p in Vec2(*p1).line_to(Vec2(*p2)))
floor = max(v.y for v in cave.keys())
return cave, floor
def sand(cave, floor):
cur = Vec2(500, 0)
if cave[cur]:
return
while True:
yield cur
d = cur.down()
if d.y == floor:
cave[cur] = 2
break
elif not cave[d]:
cur = d
elif not cave[d.left()]:
cur = d.left()
elif not cave[d.right()]:
cur = d.right()
else:
cave[cur] = 2
break
def simulate1(cave, floor):
total = 0
while True:
for p in sand(cave, floor+1):
if p.y == floor:
return total
total += 1
def simulate2(cave, floor):
total = 0
while True:
if ilen(sand(cave, floor+2)) == 0:
return total
total += 1
cave, floor = read_cave()
print('Star 1:', simulate1(cave, floor))
cave, floor = read_cave()
print('Star 2:', simulate2(cave, floor))
### Alternative solution for part 2 using BFS ###
def simulate2_bfs(cave: defaultdict, floor):
def is_open(pos: Vec2) -> bool:
return pos.y != floor and pos not in cave
def near(cur: Vec2):
return filter(is_open, [cur.down_left(), cur.down(), cur.down_right()])
return bfs(Vec2(500, 0), near)
cave, floor = read_cave()
print('Star 2 (BFS):', ilen(simulate2_bfs(cave, floor+2)))