advent-of-code/2022/python/day14.py

149 lines
4.1 KiB
Python
Raw Permalink Normal View History

2022-12-14 07:38:19 +00:00
import matrix
import shared
import itertools
import functools
2022-12-17 03:07:17 +00:00
SAND_START = [0, 500]
2022-12-14 07:38:19 +00:00
def find_bounds(lines):
x = []
y = []
for line in lines:
x.extend(matrix.split_x_out(line))
y.extend(matrix.split_y_out(line))
2022-12-17 03:07:17 +00:00
return shared.minmax(y), shared.minmax(x)
2022-12-14 07:38:19 +00:00
def part1(rows):
def get_next(sand):
2022-12-17 03:07:17 +00:00
next_y = sand[0] + 1
dl = sand[1] - 1
2022-12-14 07:38:19 +00:00
d = sand[1]
2022-12-17 03:07:17 +00:00
dr = sand[1] + 1
return next_y, (dl, d, dr)
lines = [
[
list(reversed(list(map(int, point.split(",")))))
for point in row.split(" -> ")
]
for row in rows
]
(minY, maxY), (minX, maxX) = find_bounds(lines)
mx = matrix.matrix_of_size(maxX + 2, maxY + 2)
2022-12-14 07:38:19 +00:00
walls = []
for line in lines:
2022-12-17 03:07:17 +00:00
for x in range(len(line) - 1):
coords = matrix.coords_between_points(line[x], line[x + 1])
2022-12-14 07:38:19 +00:00
walls.extend(coords)
2022-12-17 03:07:17 +00:00
for y, x in walls:
2022-12-14 07:38:19 +00:00
mx[y][x] = "#"
mx[SAND_START[0]][SAND_START[1]] = "+"
sands = []
try:
2022-12-17 03:07:17 +00:00
for sand_grains in range(900): # produce Sand one unit at a time
2022-12-14 07:38:19 +00:00
last_grain = []
sand = SAND_START[:]
2022-12-17 03:07:17 +00:00
# print("starting sand", sand_grains+1, sand)
2022-12-14 07:38:19 +00:00
while True:
last_grain.append(sand[:])
next_y, (dl, d, dr) = get_next(sand)
if mx[next_y][d] == 0:
2022-12-17 03:07:17 +00:00
# print(mx[next_y][d],"moving_down", end=' ')
# print("moving down")
2022-12-14 07:38:19 +00:00
sand[0] = next_y
elif mx[next_y][dl] == 0:
2022-12-17 03:07:17 +00:00
# print(mx[next_y][dl], "moving left", end=' ')
# print("moving left")
2022-12-14 07:38:19 +00:00
sand[0] = next_y
sand[1] = dl
elif mx[next_y][dr] == 0:
2022-12-17 03:07:17 +00:00
# print(mx[next_y][dr], "moving right", end=' ')
# print("moving right")
2022-12-14 07:38:19 +00:00
sand[0] = next_y
sand[1] = dr
else:
mx[sand[0]][sand[1]] = "o"
2022-12-17 03:07:17 +00:00
# print(mx[next_y][dl], mx[next_y][d], mx[next_y][dr])
# print("STOPPING", end=' ')
2022-12-14 07:38:19 +00:00
break
2022-12-17 03:07:17 +00:00
# matrix.view_matrix(mx, 0,minX-1, maxY+1,maxX+2)
2022-12-14 07:38:19 +00:00
except IndexError:
sands.append(last_grain)
2022-12-17 03:07:17 +00:00
for y, x in sands[-1]:
2022-12-14 07:38:19 +00:00
mx[y][x] = "~"
2022-12-17 03:07:17 +00:00
# matrix.view_matrix(mx, 0,minX-1, maxY+1,maxX+2)
2022-12-14 07:38:19 +00:00
print("done", sand_grains)
2022-12-14 19:00:11 +00:00
@shared.profile
2022-12-14 07:38:19 +00:00
def part2(rows):
2022-12-17 03:07:17 +00:00
lines = [
[
list(reversed(list(map(int, point.split(",")))))
for point in row.split(" -> ")
]
for row in rows
]
(minY, maxY), (minX, maxX) = find_bounds(lines)
2022-12-14 19:00:11 +00:00
walls = {}
_between_points = matrix.coords_between_points
2022-12-14 07:38:19 +00:00
for line in lines:
2022-12-17 03:07:17 +00:00
for x in range(len(line) - 1):
coords = matrix.coords_between_points(line[x], line[x + 1])
2022-12-14 07:38:19 +00:00
for c in coords:
2022-12-14 19:00:11 +00:00
walls[c] = "#"
2022-12-17 03:07:17 +00:00
for y, x in walls:
walls[(y, x)] = "#" # .add((y,x))
2022-12-14 07:38:19 +00:00
floor = maxY + 2
sand_grains = -1
while True:
sand_grains += 1
2022-12-17 03:07:17 +00:00
sand = [0, 500]
2022-12-14 19:00:11 +00:00
2022-12-14 07:38:19 +00:00
if tuple(sand) in walls:
print("done", sand_grains)
break
2022-12-14 19:00:11 +00:00
2022-12-14 07:38:19 +00:00
while True:
2022-12-17 03:07:17 +00:00
next_y = sand[0] + 1
dl = sand[1] - 1
dr = sand[1] + 1
2022-12-14 19:00:11 +00:00
if next_y == floor:
# hit the floor
2022-12-17 03:07:17 +00:00
walls[tuple(sand)] = "#" # Draw stop
2022-12-14 19:00:11 +00:00
break
elif (next_y, sand[1]) not in walls:
2022-12-14 07:38:19 +00:00
sand[0] = next_y
2022-12-14 19:00:11 +00:00
elif (next_y, dl) not in walls:
2022-12-14 07:38:19 +00:00
sand[0] = next_y
sand[1] = dl
2022-12-14 19:00:11 +00:00
elif (next_y, dr) not in walls:
2022-12-14 07:38:19 +00:00
sand[0] = next_y
sand[1] = dr
2022-12-14 19:00:11 +00:00
2022-12-14 07:38:19 +00:00
else:
2022-12-14 19:00:11 +00:00
# Hit something flat
walls[tuple(sand)] = "#"
2022-12-14 07:38:19 +00:00
break
2022-12-17 03:07:17 +00:00
2022-12-14 07:38:19 +00:00
def main():
rows = [row for row in shared.load_rows(14)]
with shared.elapsed_timer() as elapsed:
part1(rows)
print("🕒", elapsed())
with shared.elapsed_timer() as elapsed:
2022-12-14 19:00:11 +00:00
part2(rows)
print("🕒", elapsed())
2022-12-14 07:38:19 +00:00
if __name__ == "__main__":
main()