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