2025-01-03 04:31:02 +03:00
|
|
|
import sys
|
|
|
|
sys.path.append('../aoclib')
|
|
|
|
|
|
|
|
from aoclib import Input
|
|
|
|
import re
|
|
|
|
|
|
|
|
class Button:
|
|
|
|
def __init__(self, cost, x, y):
|
|
|
|
self.cost = cost
|
|
|
|
self.x = x
|
|
|
|
self.y = y
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return f'x: {self.x}, y: {self.y}, cost: {self.cost}'
|
|
|
|
|
|
|
|
|
|
|
|
class Prize:
|
|
|
|
def __init__(self, x, y):
|
|
|
|
self.x = x
|
|
|
|
self.y = y
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return f'x: {self.x}, y: {self.y}'
|
|
|
|
|
|
|
|
|
|
|
|
class Machine:
|
|
|
|
def __init__(self, a, b: Button, p: Prize):
|
|
|
|
self.a = a
|
|
|
|
self.b = b
|
|
|
|
self.prize = p
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
s = ''
|
|
|
|
s += 'B_A: ' + self.a.__str__() + '\n'
|
|
|
|
s += 'B_B: ' + self.b.__str__() + '\n'
|
|
|
|
s += 'Prize: ' + self.prize.__str__() + '\n'
|
|
|
|
return s
|
|
|
|
|
|
|
|
|
|
|
|
def parse_input(lines: list[str]) -> list[Machine]:
|
|
|
|
lst = list()
|
|
|
|
brx = re.compile(r'X\+(\d+), Y\+(\d+)')
|
|
|
|
prx = re.compile(r'X=(\d+), Y=(\d+)')
|
|
|
|
|
|
|
|
b_a = None
|
|
|
|
b_b = None
|
|
|
|
m = None
|
|
|
|
for l in lines:
|
|
|
|
if l.startswith('Button A'):
|
|
|
|
m = brx.search(l)
|
|
|
|
b_a = Button(3, int(m.group(1)), int(m.group(2)))
|
|
|
|
if l.startswith('Button B'):
|
|
|
|
m = brx.search(l)
|
|
|
|
b_b = Button(1, int(m.group(1)), int(m.group(2)))
|
|
|
|
if l.startswith('Prize'):
|
|
|
|
m = prx.search(l)
|
|
|
|
p = Prize(int(m.group(1)), int(m.group(2)))
|
|
|
|
machine = Machine(b_a, b_b, p)
|
|
|
|
lst.append(machine)
|
|
|
|
|
|
|
|
return lst
|
|
|
|
|
|
|
|
def _solve1(m: Machine) -> int:
|
2025-01-04 13:53:30 +03:00
|
|
|
# why not brute-force? :)
|
2025-01-03 04:31:02 +03:00
|
|
|
max_a = min(m.prize.x // m.a.x, m.prize.y // m.a.y)+1
|
|
|
|
max_b = min(m.prize.x // m.b.x, m.prize.y // m.b.y)+1
|
|
|
|
|
|
|
|
costs = []
|
|
|
|
for _a in range(max_a):
|
|
|
|
for _b in range(max_b):
|
|
|
|
x, y, cost = m.a.x*_a + m.b.x*_b, m.a.y*_a + m.b.y*_b, m.a.cost*_a + m.b.cost*_b
|
|
|
|
if x == m.prize.x and y == m.prize.y:
|
|
|
|
costs.append(cost)
|
|
|
|
|
|
|
|
if not costs:
|
|
|
|
return None
|
|
|
|
|
|
|
|
return min(costs)
|
|
|
|
|
2025-01-04 13:53:30 +03:00
|
|
|
|
|
|
|
def _solve2(m: Machine) -> int:
|
|
|
|
cost = None
|
|
|
|
times_b = (m.prize.y * m.a.x - m.prize.x * m.a.y) / (m.b.y * m.a.x - m.b.x * m.a.y)
|
|
|
|
times_a = (m.prize.x - m.b.x * times_b) / m.a.x
|
|
|
|
|
|
|
|
#if 100 >= times_a >= 0 and 100 >= times_b >= 0 and times_a.is_integer() and times_b.is_integer():
|
|
|
|
if times_a.is_integer() and times_b.is_integer():
|
|
|
|
cost = int(times_a) * 3 + int(times_b)
|
|
|
|
|
|
|
|
return cost
|
|
|
|
|
|
|
|
|
2025-01-03 04:31:02 +03:00
|
|
|
|
|
|
|
def solve1(lines: list[str]):
|
|
|
|
machines = parse_input(lines)
|
|
|
|
|
|
|
|
cost = 0
|
|
|
|
for m in machines:
|
|
|
|
c = _solve1(m)
|
|
|
|
if not c:
|
|
|
|
continue
|
|
|
|
cost += c
|
|
|
|
|
|
|
|
return cost
|
|
|
|
|
|
|
|
|
|
|
|
def solve2(lines: list[str]):
|
|
|
|
machines = parse_input(lines)
|
|
|
|
|
|
|
|
cost = 0
|
2025-01-04 13:53:30 +03:00
|
|
|
for m in machines:
|
2025-01-03 04:31:02 +03:00
|
|
|
m.prize.x += 10000000000000
|
|
|
|
m.prize.y += 10000000000000
|
2025-01-04 13:53:30 +03:00
|
|
|
c = _solve2(m)
|
2025-01-03 04:31:02 +03:00
|
|
|
if not c:
|
|
|
|
continue
|
|
|
|
cost += c
|
|
|
|
|
|
|
|
return cost
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
#lines = Input('input_test.txt').lines()
|
|
|
|
lines = Input('input.txt').lines()
|
|
|
|
|
|
|
|
#part 1
|
|
|
|
print('part 1:', solve1(lines)) # 27157
|
|
|
|
|
|
|
|
#part 2
|
2025-01-04 13:53:30 +03:00
|
|
|
print('part 2:', solve2(lines)) # 104015411578548
|