adventOfCode/challenges/2024/07-bridgeRepair/main.py
2024-12-07 15:30:32 +00:00

85 lines
1.9 KiB
Python

import sys
from functools import reduce
from typing import Iterable
import math
def parse(instr: str) -> list[tuple[int, list[int]]]:
res = []
for line in instr.splitlines():
spa, spb = line.split(": ")
res.append(
(int(spa), list(map(int, spb.split(" ")))),
)
return res
def ends_with(x: int, y: int) -> bool:
ycard = int(math.log10(y)) + 1
return (x - y) * (10**-ycard) == int(x * (10**-ycard))
def trim_int(x: int, y: int) -> int:
ycard = int(math.log10(y)) + 1
return int((x - y) * (10**-ycard))
def solve(target: int, ns: list[int], use_concat: bool = False) -> bool:
v = ns[-1]
rest = ns[:-1]
if len(rest) == 0:
return target == v
if target % v == 0:
# this represents a possible multiplication
if solve(int(target / v), rest, use_concat):
return True
if use_concat and ends_with(target, v):
# this is a possible concatenation
if solve(trim_int(target, v), rest, use_concat):
return True
# last resort, addition
return solve(target - v, rest, use_concat)
def one(instr: str):
cases = parse(instr)
return reduce(
lambda x, y: x + y,
(
target if solve(target, numbers, use_concat=False) else 0
for (target, numbers) in cases
),
0,
)
def two(instr: str):
cases = parse(instr)
return reduce(
lambda x, y: x + y,
(
target if solve(target, numbers, use_concat=True) else 0
for (target, numbers) in cases
),
0,
)
def _debug(*args, **kwargs):
kwargs["file"] = sys.stderr
print(*args, **kwargs)
if __name__ == "__main__":
if len(sys.argv) < 2 or sys.argv[1] not in ["1", "2"]:
print("Missing day argument", file=sys.stderr)
sys.exit(1)
inp = sys.stdin.read().strip()
if sys.argv[1] == "1":
print(one(inp))
else:
print(two(inp))