Day 9 - Advent of Code 2022

Working solutions for the day 9 puzzles.

Part One

""" day_09_01.py """

# usage: python3 day_09_01.py < input

import sys


def move(way, head_pos, tail_pos):
    """ calculate new head and tail after a step this way """
    x, y = head_pos
    if way == 'U':
        new_head = x, y + 1
    elif way == 'D':
        new_head = x, y - 1
    elif way == 'L':
        new_head = x - 1, y
    elif way == 'R':
        new_head = x + 1, y
    else:
        new_head = x, y
    if not touching(new_head, tail_pos):
        return new_head, adjust(new_head, tail_pos)
    return new_head, tail_pos


def touching(head_pos, tail_pos):
    """ determine if head and tail touch """
    dx = abs(head_pos[0] - tail_pos[0])
    dy = abs(head_pos[1] - tail_pos[1])
    if dx < 2 and dy < 2:
        return True
    return False


def adjust(head_pos, tail_pos):
    """ move tail so is touching and in same row or column """
    sign = lambda x: (x > 0) - (x < 0)
    tx, ty = tail_pos
    tx += sign(head_pos[0] - tx)
    ty += sign(head_pos[1] - ty)
    return tx, ty


head = 0, 0
tail = 0, 0
unique = {tail}
for displacement in sys.stdin:
    direction, length = displacement.split()
    for _ in range(int(length)):
        head, tail = move(direction, head, tail)
        unique = unique | {tail}
print(len(unique))

Part Two

""" day_09_02.py """

# usage: python3 day_09_02.py < input

import sys


def move(way, head_pos, tail_pos):
    """ calculate new head and tail after a step this way """
    x, y = head_pos
    if way == 'U':
        new_head = x, y + 1
    elif way == 'D':
        new_head = x, y - 1
    elif way == 'L':
        new_head = x - 1, y
    elif way == 'R':
        new_head = x + 1, y
    else:
        new_head = x, y
    if not touching(new_head, tail_pos):
        return new_head, adjust(new_head, tail_pos)
    return new_head, tail_pos


def touching(head_pos, tail_pos):
    """ determine if head and tail touch """
    dx = abs(head_pos[0] - tail_pos[0])
    dy = abs(head_pos[1] - tail_pos[1])
    if dx < 2 and dy < 2:
        return True
    return False


def adjust(head_pos, tail_pos):
    """ move tail so is touching and in same row or column """
    sign = lambda x: (x > 0) - (x < 0)
    tx, ty = tail_pos
    tx += sign(head_pos[0] - tx)
    ty += sign(head_pos[1] - ty)
    return tx, ty


size = 10
tail = lambda x: x[-1]
rope = [(0, 0) for _ in range(size)]
unique = {tail(rope)}
for displacement in sys.stdin:
    direction, length = displacement.split()
    for _ in range(int(length)):
        rope[0], rope[1] = move(direction, rope[0], rope[1])
        for i in range(1, size - 1):
            if not touching(rope[i], rope[i + 1]):
                rope[i + 1] = adjust(rope[i], rope[i + 1])
        unique = unique | {tail(rope)}
print(len(unique))