71 lines
1.9 KiB
Python
71 lines
1.9 KiB
Python
|
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))
|