Sean McLemon | Advent of Code

Home | Czech | Blog | GitHub | Advent Of Code | Notes


2022-12-14 - Regolith Reservoir

(original .ipynb)

Day 14 puzzle input is a sequence of "->"-separated point pairs which describe rock formations (mine is here). Part 1 dropping grains of sand from a given point, until the sand overflows and drops off to "the abyss". Part two involves assuming there is no abyss, but an infinitely wide floor 2 rows below the lowest rock and pouring sand in until it builds up to the top and finding how many grains this takes.

puzzle_input_str = open("./puzzle_input/day14.txt").read()

test_input_str = """498,4 -> 498,6 -> 496,6
503,4 -> 502,4 -> 502,9 -> 494,9"""


def parse_point(point_str):
    col, row = point_str.split(",")
    return int(row), int(col)


def parse_line(line):
    return [parse_point(point) for point in line.split(" -> ")]


def draw_line(grid, point1, point2):
    from_point = min(point1, point2)
    to_point = max(point1, point2)
    from_row, from_col = from_point
    to_row, to_col = to_point
    for row in range(from_row, to_row+1):
        for col in range(from_col, to_col+1):
            grid[row][col] = "#"


def build_grid(shapes, with_floor=False):
    max_row, max_col = 0, 0
    for shape in shapes:
        for row, col in shape:
            max_row = max(max_row, row)
            max_col = max(max_col, col)

    max_col *= 2 # why not
    grid = []
    for row in range(max_row+1):
        grid.append(["." for _ in range(max_col+1)])
        
    for shape in shapes:
        point = shape[0]
        for next_point in shape[1:]:
            draw_line(grid, point, next_point)
            point = next_point
    
    if with_floor:
        grid.append(["." for _ in range(max_col+1)])
        grid.append(["#" for _ in range(max_col+1)])
    
    return grid


def add_sand(grid):
    r, c = 0, 500
    directions = ((1, 0), (1, -1), (1, 1))
    
    moved = True
    while moved:
        if r+1 == len(grid):
            return False
        moved = False
        for dr, dc in directions:
            if grid[r+dr][c+dc] == ".":
                r += dr
                c += dc
                moved = True
                break
    grid[r][c] = "o"
    return True

def part_one(input_str):
    shapes = [parse_line(line) for line in input_str.splitlines()]
    grid = build_grid(shapes)

    sand = 0
    while add_sand(grid):
        sand += 1
        
    return sand


assert 24 == part_one(test_input_str)

print("part one:", part_one(puzzle_input_str))
part one: 674
def add_sand(grid):
    r, c = 0, 500
    directions = ((1, 0), (1, -1), (1, 1))
    
    moved = True
    while moved:
        moved = False
        for dr, dc in directions:
            if r+1 < len(grid) and grid[r+dr][c+dc] == ".":
                r += dr
                c += dc
                moved = True
                break
        if r == 0 and not moved:
            return False
        
    grid[r][c] = "o"
    return True

def part_two(input_str):
    shapes = [parse_line(line) for line in input_str.splitlines()]
    grid = build_grid(shapes, True)

    sand = 1
    while add_sand(grid):
        sand += 1
        
    return sand


assert 93 == part_two(test_input_str)

print("part two:", part_two(puzzle_input_str))
part two: 24958