-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday14.py
78 lines (62 loc) · 1.96 KB
/
day14.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
import re
from itertools import pairwise
from .shared import Grid, P, Solution
DOWN = P(0, 1)
DOWN_LEFT = P(-1, 1)
DOWN_RIGHT = P(1, 1)
BASICALLY_INF = 10_000
def main(input_: list[str]) -> Solution:
sand_source = P(0, 0) # 500,0 shift everything left 500
grid = parse_rock_formations(input_)
grid[sand_source] = "+"
# Part 1
done = False
while not done:
done = drop_sand(grid, sand_source, part=1)
part1 = len([p for p, v in grid.items() if v == "o"])
# Add floor
floor = P(-BASICALLY_INF, grid.max_y() + 2).line(P(BASICALLY_INF, grid.max_y() + 2))
for p in floor:
grid[p] = "#"
# Part 2
done = False
while not done:
done = drop_sand(grid, sand_source, part=2)
part2 = len([p for p, v in grid.items() if v == "o"])
return Solution(part1, part2)
def parse_rock_formations(scans: list[str]) -> Grid:
grid = Grid()
for scan in scans:
points = [
P(*map(int, p.split(","))).add(P(-500, 0))
for p in re.findall(r"\d+,\d+", scan)
]
rock = []
for a, b in pairwise(points):
rock.extend(a.line(b))
for r in rock:
grid[r] = "#"
return grid
def drop_sand(grid: Grid, source: P, part: int) -> bool:
at_rest = False
current = source
while not at_rest:
if part == 1 and current.y > grid.max_y():
return True
if part == 2 and grid.get(source) == "o":
return True
next_ = current.add(DOWN)
if grid.get(next_) is None:
current = next_
continue
next_ = current.add(DOWN_LEFT)
if grid.get(next_) is None:
current = next_
continue
next_ = current.add(DOWN_RIGHT)
if grid.get(next_) is None:
current = next_
continue
at_rest = True
grid[current] = "o"
return False