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
2018-12-17 20:33:32 +10:30
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 ( )
2018-12-17 20:33:32 +10:30
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
2018-12-17 20:33:32 +10:30
def drop_water ( source = spring ) :
2018-12-17 20:26:47 +10:30
if tuple ( source ) in drop_point_blacklist :
return False
2018-12-17 20:33:32 +10:30
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
2018-12-17 20:26:47 +10:30
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 20:33:32 +10:30
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
2018-12-17 20:33:32 +10:30
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
2018-12-17 20:33:32 +10:30
if cliff :
2018-12-17 20:18:23 +10:30
cliffs . add ( ( x + cliff , surface_y ) )
2018-12-17 17:16:03 +10:30
2018-12-17 20:33:32 +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.
2018-12-17 20:26:47 +10:30
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 ( )