Day 24 - Advent of Code 2023

Working solutions for the day 24 puzzles.

Part One

""" day_24_01.py """

# usage: python3 day_24_01.py 200000000000000 400000000000000 < input

import sys
from collections import namedtuple
from itertools import combinations
from math import isclose


Vector3 = namedtuple('Vector3', 'x, y, z')
NULL = Vector3(None, None, None)


def parse(text):
    """ extract coordinate and velocity """
    coordinate, velocity = text.split(' @ ')
    return (Vector3(*map(int, coordinate.split(', '))),
            Vector3(*map(int, velocity.split(', '))))


def line(coordinate, velocity):
    """ calculate coefficients ax + by + c = 0 """
    if velocity.x == 0:
        return (1, 0, -coordinate.x)
    gradient = velocity.y / velocity.x
    return (-gradient, 1, gradient * coordinate.x - coordinate.y)


def future_intersection(u, v):
    """ future intersection of u and v ignoring z axis """
    p1, v1 = parse(u)
    a1, b1, c1 = line(p1, v1)
    p2, v2 = parse(v)
    a2, b2, c2 = line(p2, v2)

    if b1 == 0 and b2 == 0:
        return NULL  # parallel vertical lines

    if b1 != 0:
        m1, y1 = -a1 / b1, -c1 / b1
    if b2 != 0:
        m2, y2 = -a2 / b2, -c2 / b2

    if b1 == 0:  # u is vertical
        x, y = p1.x, m2 * p1.x + y2
    elif b2 == 0:  # v is vertical
        x, y = p2.x, m1 * p2.x + y1
    else:
        if isclose(m1, m2):
            return NULL  # parallel lines
        x = (y2 - y1) / (m1 - m2)
        y = m2 * x + y2

    if (y - p2.y) / v2.y < 0 or (y - p1.y) / v1.y < 0:
        return NULL  # occurs in past for at least one hailstone

    return Vector3(x, y, None)


coord_min, coord_max = int(sys.argv[1]), int(sys.argv[2])
hailstones = sys.stdin.read().splitlines()

answer = 0
for i, j in combinations(hailstones, 2):
    p = future_intersection(i, j)
    if p == NULL:
        continue
    if coord_min <= p.x <= coord_max and coord_min <= p.y <= coord_max:
        answer += 1

print(answer)

Part Two