Index

Day 09

part2

AoC link
import math
from dataclasses import dataclass

# input = """\
# R 4
# U 4
# L 3
# D 1
# R 4
# D 1
# L 5
# R 2
# """
# input = """\
# R 5
# U 8
# L 8
# D 3
# R 17
# D 10
# L 25
# U 20
# """
input = open("2022/day09/data.txt").read()

# head/tail start at same position
# iterate in steps
# tail follows head, never more than two spaces away
# R: right
# L: left
# U: up
# D: down
# diagonal spacing also counted

# part1: count all positions Tail visits


@dataclass(frozen=True)
class Point:
    x: int
    y: int


def check_too_far(p1: Point, p2: Point):
    if abs(p1.x - p2.x) > 1:
        return True
    if abs(p1.y - p2.y) > 1:
        return True
    return False


def modify_knots(x_mod, y_mod):
    # head always moves
    knots[0] = Point(knots[0].x + x_mod, knots[0].y + y_mod)

    for k in range(9):
        lead = knots[k]
        follower = knots[k + 1]
        if check_too_far(lead, follower):
            if lead.x == follower.x:
                # in the same column
                knots[k + 1] = Point(
                    follower.x, follower.y + int(math.copysign(1, lead.y - follower.y))
                )
            elif lead.y == follower.y:
                # in the same row
                knots[k + 1] = Point(
                    follower.x + int(math.copysign(1, lead.x - follower.x)), follower.y
                )
            else:
                # diag., move one step diagonally to catch up
                knots[k + 1] = Point(
                    follower.x + int(math.copysign(1, lead.x - follower.x)),
                    follower.y + int(math.copysign(1, lead.y - follower.y)),
                )


# 0: head, -1: tail
knots = [Point(0, 0)] * 10

tail_positions = {knots[-1]}
for line in input.splitlines():
    dir = line[0]
    count = int(line[2:])

    for iter in range(count):

        # move head
        match dir:
            case "R":
                # knots[0] = Point(knots[0].x + 1, knots[0].y)
                modify_knots(1, 0)
                # for k, lead in enumerate(knots[:-2]):
                #     if check_too_far(lead, knots[k + 1]):
                #         tail = Point(knots[k + 1].x + 1, lead.y)
            case "L":
                # knots[0] = Point(knots[0].x - 1, knots[0].y)
                modify_knots(-1, 0)
                # if check_too_far(head, tail):
                #     tail = Point(tail.x - 1, head.y)
            case "U":
                # knots[0] = Point(knots[0].x, knots[0].y + 1)
                modify_knots(0, 1)
                # if check_too_far(head, tail):
                #     tail = Point(head.x, tail.y + 1)
            case "D":
                # knots[0] = Point(knots[0].x, knots[0].y - 1)
                modify_knots(0, -1)
                # if check_too_far(head, tail):
                #     tail = Point(head.x, tail.y - 1)
        tail_positions.add(knots[-1])

print(len(tail_positions))


Output: