2018-12-17 - Reservoir Research
(original .ipynb)
import itertools
import math
from advent import grid_to_file
def parse_single_coord(coord):
axis, value = coord.split("=")
return (axis, int(value))
def parse_range_coord(coord):
axis, range_values_str = coord.split("=")
range_start, range_end = range_values_str.split("..")
return (axis, range(int(range_start), 1 + int(range_end)))
def parse_line(line):
left_coord_str, right_coord_str = line.strip().split(",")
left_coord = parse_single_coord(left_coord_str)
right_coords = parse_range_coord(right_coord_str)
if left_coord[0] == "x":
cols = right_coords[1]
row = left_coord[1]
return zip(cols, [row] * len(cols))
else:
rows = right_coords[1]
col = left_coord[1]
return zip([col] * len(rows), rows)
def parse_coords(lines):
parsed_lines = [ parse_line(line) for line in lines ]
return list(itertools.chain.from_iterable(parsed_lines))
def grid_dimensions(coords):
min_row = math.inf
max_row = 0
min_col = math.inf
max_col = 0
for r, c in coords:
if r > max_row:
max_row = r
if r < min_row:
min_row = r
if c > max_col:
max_col = c
elif c < min_col:
min_col = c
return (min_row, max_row, max_col, min_col)
def build_row(max_col, min_col):
return ["."] * (1 + max_col - min_col)
def build_grid(lines):
coords = parse_coords(lines)
min_row, max_row, max_col, min_col = grid_dimensions(coords)
grid = [ build_row(max_col, min_col) for n in range(max_row + 1)]
for row, col in coords:
grid[row][col - min_col] = "#"
grid[0][500 - min_col] = "+"
return min_row, grid
def drip_down(grid, r, c):
if r+1 < len(grid):
grid[r+1][c] = "|"
def cell_below(grid, r, c):
if (r+1 >= len(grid)):
return "-"
return grid[r+1][c]
def cell_left(grid, r, c):
return grid[r][c-1]
def cell_right(grid, r, c):
return grid[r][c+1]
def fill_left(grid, r, c):
to_fill = []
spill = False
while True:
to_fill.append((r, c))
if cell_left(grid, r, c) == "#":
spill = False
break
elif cell_below(grid, r, c) == ".":
spill = True
break
c -= 1
return (spill, to_fill)
def fill_right(grid, r, c):
to_fill = []
spill = False
while True:
to_fill.append((r, c))
if cell_right(grid, r, c) == "#":
spill = False
break
elif cell_below(grid, r, c) == ".":
spill = True
break
c += 1
return (spill, to_fill)
def fill(grid, r, c):
spill_left, to_fill_left = fill_left(grid, r, c)
spill_right, to_fill_right = fill_right(grid, r, c)
fill_str = "|" if spill_left or spill_right else "~"
grid[r][c] = fill_str
to_fill = to_fill_left + to_fill_right
for (fill_r, fill_c) in to_fill:
grid[fill_r][fill_c] = fill_str
def step_grid(grid):
change_made = False
for r, row in enumerate(grid):
for c, col in enumerate(row):
if col == "+" and grid[r+1][c] != "|":
grid[r+1][c] = "|"
change_made = True
if (col == "|"):
if cell_below(grid, r, c) == ".":
drip_down(grid, r, c)
change_made = True
elif cell_below(grid, r, c) == "#" and cell_right(grid, r, c) != "|" and cell_left(grid, r, c) != "|":
fill(grid, r, c)
change_made = True
elif cell_below(grid, r, c) == "~" and cell_right(grid, r, c) != "|" and cell_left(grid, r, c) != "|":
fill(grid, r, c)
change_made = True
elif cell_below(grid, r, c) == "~" and cell_left(grid, r, c) == ".":
fill(grid, r, c)
change_made = True
elif cell_below(grid, r, c) == "~" and cell_right(grid, r, c) == ".":
fill(grid, r, c)
change_made = True
return change_made
def count_water_tiles(grid, min_row):
count = 0
for r, row in enumerate(grid):
for col in row:
if r >= min_row and (col == "|" or col == "~"):
count += 1
return count
def count_standing_water_tiles(grid):
count = 0
for row in grid:
for col in row:
if col == "~":
count += 1
return count
()
('a',)
('b',)
('c',)
('a', 'b')
('a', 'c')
('b', 'c')
('a', 'b', 'c')
test_input_str = """x=495, y=2..7
y=7, x=495..501
x=501, y=3..7
x=498, y=2..4
x=506, y=1..2
x=498, y=10..13
x=504, y=10..13
y=13, x=498..504"""
palette = {
".": "white",
"#": "orange",
"|": "blue",
"~": "lightblue",
"+": "red"
}
def solve(input_lines, filename, big=False):
min_row, grid = build_grid(input_lines)
changed = True
while changed:
changed = step_grid(grid)
if big:
grid_to_file(grid, palette, filename, show=True, cell_size=1)
else:
grid_to_file(grid, palette, filename, show=True)
total_water_tiles = count_water_tiles(grid, min_row)
print("part 1:", total_water_tiles)
standing_water_tiles = count_standing_water_tiles(grid)
print("part 2:", standing_water_tiles)
solve(test_input_str.split("\n"), "day-17.png")
part 1: 57
part 2: 29
problem = open("day17.txt", "r").readlines()
solve(problem, "day17.png", True)
part 1: 38021
part 2: 32069