from dataclasses import dataclass from functools import cache from itertools import combinations from sys import stdin from z3 import z3 @dataclass(frozen=True, slots=True) class Vec: x: float y: float z: float def __str__(self) -> str: return f"{self.x}, {self.y}, {self.z}" @dataclass(frozen=True, slots=True) class Hailstone: pos: Vec vel: Vec @property @cache def m(self) -> float: return self.vel.y / self.vel.x @property @cache def c(self) -> float: return self.pos.y - self.pos.x / self.vel.x * self.vel.y def __str__(self) -> str: return f"{self.pos} @ {self.vel}" inp: list[Hailstone] = list() for line in stdin: pos, vel = line.rstrip("\n").split(" @ ") pos = Vec(*map(float, pos.split(", "))) vel = Vec(*map(float, vel.split(", "))) inp.append(Hailstone(pos, vel)) def intersection(a: Hailstone, b: Hailstone) -> tuple[float, float] | None: numer = b.c - a.c denom = a.m - b.m if denom == 0: return None xi = numer / denom return xi, xi * a.m + a.c lbound = 200000000000000 ubound = 400000000000000 p1 = 0 for a, b in combinations(inp, 2): inter = intersection(a, b) if inter is None: continue ix, iy = inter a_dist = (ix - a.pos.x) / a.vel.x b_dist = (ix - b.pos.x) / b.vel.x if ( a_dist >= 0 and b_dist >= 0 and lbound <= ix <= ubound and lbound <= iy <= ubound ): p1 += 1 print(p1) a, b, c, x, y, z = (z3.Int(c) for c in "abcxyz") s = z3.Solver() for i, m in enumerate("tuvw"): m = z3.Int(m) h = inp[i] s.add(h.pos.x + h.vel.x * m == x + a * m) s.add(h.pos.y + h.vel.y * m == y + b * m) s.add(h.pos.z + h.vel.z * m == z + c * m) s.check() print(s.model().eval(x + y + z))