advent24-llm / day13 /solution_claude-3-5-sonnet-20241022.py
jerpint's picture
Add solution files
a4da721
from math import gcd
from typing import Optional, Tuple
def extended_gcd(a: int, b: int) -> Tuple[int, int, int]:
if a == 0:
return b, 0, 1
gcd, x1, y1 = extended_gcd(b % a, a)
x = y1 - (b // a) * x1
y = x1
return gcd, x, y
def find_solution(a: int, b: int, c: int) -> Optional[Tuple[int, int]]:
g = gcd(a, b)
if c % g != 0:
return None
# Scale everything down by gcd
a, b, c = a//g, b//g, c//g
# Find base solution using extended GCD
_, x0, y0 = extended_gcd(a, b)
x0 *= c
y0 *= c
# Find the general solution
# x = x0 + k*(b/g)
# y = y0 - k*(a/g)
# We need both x and y to be non-negative
k_min = -(x0 // b) if x0 < 0 else -((y0) // a)
k_max = (y0 // a) if y0 > 0 else (x0 // b)
# Find k that gives minimum positive solution
for k in range(k_min, k_max + 1):
x = x0 + k * b
y = y0 - k * a
if x >= 0 and y >= 0:
return (x, y)
return None
def solve_machine(ax: int, ay: int, bx: int, by: int, px: int, py: int, max_presses: Optional[int] = None) -> Optional[int]:
# Find solution for x-coordinate
sol_x = find_solution(ax, bx, px)
if not sol_x:
return None
# Find solution for y-coordinate
sol_y = find_solution(ay, by, py)
if not sol_y:
return None
# Check if solutions match
if sol_x[0] != sol_y[0] or sol_x[1] != sol_y[1]:
return None
# Check max presses constraint if specified
if max_presses and (sol_x[0] > max_presses or sol_x[1] > max_presses):
return None
# Calculate tokens needed (3 for A, 1 for B)
return 3 * sol_x[0] + sol_x[1]
def parse_input(filename: str):
machines = []
with open(filename, 'r') as f:
lines = f.read().strip().split('\n\n')
for machine in lines:
lines = machine.strip().split('\n')
ax = int(lines[0].split('X+')[1].split(',')[0])
ay = int(lines[0].split('Y+')[1])
bx = int(lines[1].split('X+')[1].split(',')[0])
by = int(lines[1].split('Y+')[1])
px = int(lines[2].split('X=')[1].split(',')[0])
py = int(lines[2].split('Y=')[1])
machines.append((ax, ay, bx, by, px, py))
return machines
def solve_part1(machines):
total_tokens = 0
for machine in machines:
tokens = solve_machine(*machine, max_presses=100)
if tokens is not None:
total_tokens += tokens
return str(total_tokens)
def solve_part2(machines):
offset = 10**13
total_tokens = 0
modified_machines = []
for ax, ay, bx, by, px, py in machines:
modified_machines.append((ax, ay, bx, by, px + offset, py + offset))
for machine in modified_machines:
tokens = solve_machine(*machine)
if tokens is not None:
total_tokens += tokens
return str(total_tokens)
# Read and parse input
machines = parse_input("input.txt")
# Solve part 1
print(solve_part1(machines))
# Solve part 2
print(solve_part2(machines))