from argparse import ArgumentParser import sys sys.setrecursionlimit(10**7) OFFSET = 10_000_000_000_000 def parse_line(line: str) -> tuple[int, int]: line = line.strip() _, coords = line.split(":", 1) coords = coords.strip() x_part, y_part = coords.split(",") x_val = x_part.strip()[1:].replace("=", "") y_val = y_part.strip()[1:].replace("=", "") return int(x_val), int(y_val) def parse_input(in_path: str) -> list[list[str]]: with open(in_path, "r") as f: content = f.read().strip() blocks = content.split("\n\n") res = [] for block in blocks: lines = block.strip().splitlines() if len(lines) == 3: res.append(lines) return res def extended_gcd(a: int, b: int) -> tuple[int, int, int]: if b == 0: return a, 1, 0 g, x1, y1 = extended_gcd(b, a % b) return g, y1, x1 - (a // b)*y1 def solve_diophantine_system(xa: int, ya: int, xb: int, yb: int, xp: int, yp: int) -> tuple[int, int] | None: # Solve: xa*a + xb*b = xp and ya*a + yb*b = yp D = xa*yb - xb*ya if D == 0: return None a_num = yb*xp - xb*yp b_num = xa*yp - ya*xp if a_num % D != 0 or b_num % D != 0: return None a0 = a_num // D b0 = b_num // D if a0 < 0 or b0 < 0: return None return a0, b0 def main(in_path: str) -> int: machines = parse_input(in_path) costs = [] for m in machines: xa, ya = parse_line(m[0]) xb, yb = parse_line(m[1]) xp, yp = parse_line(m[2]) xp += OFFSET yp += OFFSET sol = solve_diophantine_system(xa, ya, xb, yb, xp, yp) if sol is not None: a, b = sol costs.append(3*a + b) if not costs: return 0 return sum(costs) if __name__ == "__main__": parser = ArgumentParser() parser.add_argument("-f", "--file", required=True) args = parser.parse_args() print(main(args.file))