Skip to content

Commit b65f577

Browse files
committed
2022 day 14
1 parent 0e1d167 commit b65f577

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed

2022/14/sandfall.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
from itertools import pairwise
2+
3+
from aoc_common.grid import Cell, Direction
4+
5+
6+
def load_data():
7+
blocked: set[Cell] = set()
8+
with open("input", "r") as f:
9+
for path in f:
10+
path = path.strip()
11+
corners = []
12+
for corner in path.split(" -> "):
13+
c, r = corner.split(",")
14+
corners.append(Cell(int(r), int(c)))
15+
for a, b in pairwise(corners):
16+
a_to_b = b - a
17+
if a_to_b.col == 0:
18+
vec = a_to_b // (abs(a_to_b.row))
19+
else:
20+
vec = a_to_b // abs(a_to_b.col)
21+
22+
blocked.add(a)
23+
while a != b:
24+
a += vec
25+
blocked.add(a)
26+
27+
return blocked
28+
29+
30+
def part1():
31+
blocked = load_data()
32+
walls = blocked.copy()
33+
bottom_row = max(r for (r, c) in blocked)
34+
35+
units_of_sand = 0
36+
done = False
37+
while not done:
38+
pos = Cell(0, 500)
39+
while True:
40+
if pos.row >= bottom_row:
41+
# sand is trickling into the void
42+
done = True
43+
break
44+
if ((candidate := pos + Direction.SOUTH) not in blocked) or ((candidate := pos + Direction.SW) not in blocked) or ((candidate := pos + Direction.SE) not in blocked):
45+
# this unit of sand can move somewhere - move it
46+
pos = candidate
47+
else:
48+
# this unit of sand cannot move, it has come to rest
49+
blocked.add(pos)
50+
units_of_sand += 1
51+
break
52+
53+
min_col = min(c for r, c in blocked)
54+
max_col = max(c for r, c in blocked)
55+
56+
for r in range(bottom_row + 2):
57+
print("".join("#" if Cell(r, c) in walls else "o" if Cell(r, c) in blocked else "." for c in range(min_col-2, max_col+3)))
58+
59+
60+
print(f"Units of sand that can come to rest: {units_of_sand}")
61+
62+
63+
def part2():
64+
blocked = load_data()
65+
walls = blocked.copy()
66+
floor = max(r for (r, c) in blocked) + 2
67+
68+
def is_free(c: Cell):
69+
return c.row != floor and c not in blocked
70+
71+
units_of_sand = 0
72+
while True:
73+
pos = Cell(0, 500)
74+
if pos in blocked:
75+
break
76+
77+
while True:
78+
if (is_free(candidate := pos + Direction.SOUTH)) or (is_free(candidate := pos + Direction.SW)) or (is_free(candidate := pos + Direction.SE)):
79+
# this unit of sand can move somewhere - move it
80+
pos = candidate
81+
else:
82+
# this unit of sand cannot move, it has come to rest
83+
blocked.add(pos)
84+
units_of_sand += 1
85+
break
86+
87+
min_col = min(c for r, c in blocked)
88+
max_col = max(c for r, c in blocked)
89+
90+
for r in range(floor + 1):
91+
print("".join("#" if (r == floor or Cell(r, c) in walls) else "o" if Cell(r, c) in blocked else "." for c in range(min_col-2, max_col+3)))
92+
93+
print(f"Units of sand that can come to rest (part 2): {units_of_sand}")
94+
95+
96+
97+
if __name__ == "__main__":
98+
part1()
99+
part2()

0 commit comments

Comments
 (0)