Sean McLemon | Advent of Code

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


2022-12-09 - Rope Bridge

(original .ipynb)

Day 9 puzzle input is a sequence of move instructions - up/down/left/right + a distance - (mine is here). Part 1 involves taking a rope of length two units (well "knots" but w/e) and moving it around, noting how many unique positions the tail sits in. Part 2 is the same, but for a rope of length ten units/knots.

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


test_input_str = """R 4
U 4
L 3
D 1
R 4
D 1
L 5
R 2"""

moves = {
    "U": (-1,  0),
    "D": ( 1,  0),
    "L": ( 0, -1),
    "R": ( 0,  1)
}


def parse_lines(lines):
    for line in lines:
        direction, moves_str = line.split(" ")
        yield direction, int(moves_str)


def move(pos, dr, dc):
    r, c = pos
    return (r+dr, c+dc)


def should_move_knot(hr, hc, tr, tc):
    return abs(hr-tr) > 1 or abs(hc-tc) > 1


def tail_move(hr, hc, tr, tc):
    if should_move_knot(hr, hc, tr, tc):
        dr = hr - tr
        dc = hc - tc
        return (
            0 if dr == 0 else dr//abs(dr), 
            0 if dc == 0 else dc//abs(dc)
        )
    return (0, 0)
    

def part_one(input_str, knot_count=2):
    knots = [(0,0) for _ in range(knot_count)]
    tail_visited = {(0,0)}
    
    for direction, distance in parse_lines(input_str.splitlines()):
        dr, dc = moves[direction]
        while distance > 0:
            next_knots = []
            for i, knot in enumerate(knots):
                if i == 0:
                    knot = move(knot, dr, dc)
                else:
                    knot = move(knot, *tail_move(*next_knots[i-1], *knot))
                    if i+1 == knot_count:
                        tail_visited.add(knot)
                next_knots.append(knot)
            knots = next_knots
            distance -= 1
    
    return len(tail_visited)


assert 13 == part_one(test_input_str)

print("part one:", part_one(puzzle_input_str))
part one: 6339
test_input_str_2 = """R 5
U 8
L 8
D 3
R 17
D 10
L 25
U 20"""

def part_two(input_str):
    return part_one(input_str, 10)


assert 36 == part_two(test_input_str_2)

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