AdventOfCode/2018/day17.py

101 lines
2.8 KiB
Python
Raw Normal View History

2018-12-17 17:16:03 +10:30
with open('day17-input', 'r') as file:
data = [l.strip('\n') for l in file]
import numpy as np
import re
Xmin = [int(re.findall(r'x=(\d+)', d)[0]) for d in data]
Xmax = [int(re.findall(r'x=(?:\d+\.\.)?(\d+)', d)[0]) for d in data]
Ymin = [int(re.findall(r'y=(\d+)', d)[0]) for d in data]
Ymax = [int(re.findall(r'y=(?:\d+\.\.)?(\d+)', d)[0]) for d in data]
y_min = min(Ymin)
y_max = max(Ymax)
2018-12-17 20:18:23 +10:30
x_min = min(Xmin) - 1
x_max = 700 - x_min
2018-12-17 17:16:03 +10:30
2018-12-17 20:18:23 +10:30
init_grid = np.zeros((x_max, y_max+1), dtype=np.int64) # 0 = Sand, 1 = Clay, 2 = water, -1 = running water
spring = (500-x_min, 0)
2018-12-17 17:16:03 +10:30
for xmin, xmax, ymin, ymax in zip(Xmin, Xmax, Ymin, Ymax):
2018-12-17 20:18:23 +10:30
init_grid[xmin-x_min:xmax+1-x_min, ymin:ymax+1] = 1
2018-12-17 17:16:03 +10:30
grid = init_grid.copy()
drop_point_blacklist = set() # Cliff drop-offs that are guaranteed to go nowhere
2018-12-17 17:16:03 +10:30
2018-12-17 20:18:23 +10:30
def drop_water(source=spring):
if tuple(source) in drop_point_blacklist:
return False
2018-12-17 17:16:03 +10:30
x, y = source
2018-12-17 20:18:23 +10:30
surface = (grid[x, y:] > 0).argmax()
2018-12-17 17:16:03 +10:30
if surface == 0:
2018-12-17 20:18:23 +10:30
if (grid[x, y-1:] > 0).argmax() == 0:
grid[x, y:] = -1
drop_point_blacklist.add(tuple(source))
2018-12-17 17:16:03 +10:30
return False
2018-12-17 20:18:23 +10:30
surface_y = surface + y
grid[x, y:surface_y] = -1
2018-12-17 17:16:03 +10:30
# Find walls left and right
2018-12-17 20:18:23 +10:30
wall_left = (grid[x:0:-1, surface_y-1] > 0).argmax()
wall_right = (grid[x:, surface_y-1] > 0).argmax()
2018-12-17 17:16:03 +10:30
if wall_left:
left_x = x - wall_left + 1
2018-12-17 20:18:23 +10:30
cliff = (grid[x:left_x-1:-1, surface_y] <= 0).argmax()
2018-12-17 17:16:03 +10:30
if cliff:
wall_left = False
if wall_right:
right_x = x + wall_right #- 1
2018-12-17 20:18:23 +10:30
cliff = (grid[x:right_x, surface_y] <= 0).argmax()
2018-12-17 17:16:03 +10:30
if cliff:
wall_right = False
if wall_right and wall_left:
# Fill level of basin
2018-12-17 20:18:23 +10:30
grid[left_x:right_x, surface_y-1] = 2
2018-12-17 17:16:03 +10:30
return True
2018-12-17 20:18:23 +10:30
cliffs = set()
2018-12-17 17:16:03 +10:30
if not wall_left:
2018-12-17 20:18:23 +10:30
cliff = int((grid[x:0:-1, surface_y] <= 0).argmax())
grid[x-cliff:x, surface_y-1] = -1
if wall_right:
grid[x:right_x, surface_y - 1] = -1
if cliff:
2018-12-17 20:18:23 +10:30
cliffs.add((x - cliff, surface_y))
2018-12-17 17:16:03 +10:30
if not wall_right:
2018-12-17 20:18:23 +10:30
cliff = int((grid[x:, surface_y] <= 0).argmax())
grid[x:x+cliff+1, surface_y-1] = -1
if wall_left:
grid[left_x:x, surface_y-1] = -1
if cliff:
2018-12-17 20:18:23 +10:30
cliffs.add((x + cliff, surface_y))
2018-12-17 17:16:03 +10:30
if cliffs and len([c for c in cliffs if tuple(c) in drop_point_blacklist]) == len(cliffs): # We go to 1 or 2 cliffs, all of which are dead-ends. We are a dead end, stop looking at us.
drop_point_blacklist.add(tuple(source))
return False
2018-12-17 20:18:23 +10:30
succeeded = False
while sum([drop_water(c) for c in cliffs]):
succeeded = True
return succeeded
2018-12-17 17:16:03 +10:30
def visualize():
vis_rows = []
2018-12-17 20:18:23 +10:30
for row in range(y_max+1):
vis_rows.append(''.join([('.', '#', '~', '|')[grid[col, row]] for col in range(x_max)]))
2018-12-17 17:16:03 +10:30
with open('day17-vis', 'w') as file:
file.write('\n'.join(vis_rows))
2018-12-17 20:18:23 +10:30
while drop_water():
pass
2018-12-17 17:16:03 +10:30
2018-12-17 20:18:23 +10:30
print((grid==2).sum() + (grid==-1).sum() - y_min) # Part 1
print((grid==2).sum()) # Part 2
visualize()