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

147 lines
4.0 KiB
Python
Raw Normal View History

2022-12-14 07:38:19 +00:00
import matrix
import shared
import itertools
import functools
SAND_START = [0,500]
def get_lines(rows):
_rows = []
for row in rows:
_row = []
for point in row.split(" -> "):
_row.append(list(reversed(list(map(int, point.split(","))))))
_rows.append(_row)
return _rows
def find_bounds(lines):
x = []
y = []
for line in lines:
x.extend(matrix.split_x_out(line))
y.extend(matrix.split_y_out(line))
return shared.minmax(y),shared.minmax(x)
def part1(rows):
def get_next(sand):
next_y = sand[0]+1
dl = sand[1]-1
d = sand[1]
dr = sand[1]+1
return next_y, (dl,d,dr)
lines = get_lines(rows)
(minY,maxY), (minX,maxX) = find_bounds(lines)
mx = matrix.matrix_of_size(maxX+2,maxY+2)
walls = []
for line in lines:
for x in range(len(line)-1):
coords = matrix.coords_between_points(line[x], line[x+1])
walls.extend(coords)
for y,x in walls:
mx[y][x] = "#"
mx[SAND_START[0]][SAND_START[1]] = "+"
sands = []
try:
for sand_grains in range(900): # produce Sand one unit at a time
last_grain = []
sand = SAND_START[:]
#print("starting sand", sand_grains+1, sand)
while True:
last_grain.append(sand[:])
next_y, (dl, d, dr) = get_next(sand)
if mx[next_y][d] == 0:
#print(mx[next_y][d],"moving_down", end=' ')
#print("moving down")
sand[0] = next_y
elif mx[next_y][dl] == 0:
#print(mx[next_y][dl], "moving left", end=' ')
#print("moving left")
sand[0] = next_y
sand[1] = dl
elif mx[next_y][dr] == 0:
#print(mx[next_y][dr], "moving right", end=' ')
#print("moving right")
sand[0] = next_y
sand[1] = dr
else:
mx[sand[0]][sand[1]] = "o"
#print(mx[next_y][dl], mx[next_y][d], mx[next_y][dr])
#print("STOPPING", end=' ')
break
#matrix.view_matrix(mx, 0,minX-1, maxY+1,maxX+2)
except IndexError:
sands.append(last_grain)
for y,x in sands[-1]:
mx[y][x] = "~"
#matrix.view_matrix(mx, 0,minX-1, maxY+1,maxX+2)
print("done", sand_grains)
def part2(rows):
def get_next(sand):
next_y = sand[0]+1
dl = sand[1]-1
d = sand[1]
dr = sand[1]+1
return next_y, (dl,d,dr)
def check_air(y,x):
if y == floor:
return False
if (y,x) in walls:
return False
return True
lines = get_lines(rows)
(minY,maxY), (minX,maxX) = find_bounds(lines)
walls = set()
for line in lines:
for x in range(len(line)-1):
coords = matrix.coords_between_points(line[x], line[x+1])
for c in coords:
walls.add(c)
for y,x in walls:
walls.add((y,x))
floor = maxY + 2
sand_grains = -1
while True:
sand_grains += 1
sand = [0,500]
if tuple(sand) in walls:
print("done", sand_grains)
break
while True:
next_y, (dl, d, dr) = get_next(sand)
if check_air(next_y, d):
sand[0] = next_y
elif check_air(next_y,dl):
sand[0] = next_y
sand[1] = dl
elif check_air(next_y, dr):
sand[0] = next_y
sand[1] = dr
else:
walls.add(tuple(sand))
break
#matrix.view_matrix(mx, 0,minX-1, maxY+3,maxX+2)
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:
part2(rows)
print("🕒", elapsed())
if __name__ == "__main__":
main()