This commit is contained in:
parent
30e0bb3665
commit
67e41503c9
15
poetry.lock
generated
15
poetry.lock
generated
@ -1,4 +1,4 @@
|
|||||||
# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "appnope"
|
name = "appnope"
|
||||||
@ -353,6 +353,17 @@ files = [
|
|||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
traitlets = "*"
|
traitlets = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "more-itertools"
|
||||||
|
version = "10.5.0"
|
||||||
|
description = "More routines for operating on iterables, beyond itertools"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "more-itertools-10.5.0.tar.gz", hash = "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6"},
|
||||||
|
{file = "more_itertools-10.5.0-py3-none-any.whl", hash = "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mpmath"
|
name = "mpmath"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@ -1295,4 +1306,4 @@ files = [
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.10"
|
python-versions = "^3.10"
|
||||||
content-hash = "c91bc307ff4a5b3e8cd1976ebea211c9749fe09d563dd80861f70ce26826cda9"
|
content-hash = "10ecc039b99b304e65eef14905c0fb0fcc7b8fb31328b19c65b54779fcc0e336"
|
||||||
|
@ -16,6 +16,7 @@ scipy = "^1.14.1"
|
|||||||
sympy = "^1.13.3"
|
sympy = "^1.13.3"
|
||||||
networkx = "^3.4.2"
|
networkx = "^3.4.2"
|
||||||
pandas = "^2.2.3"
|
pandas = "^2.2.3"
|
||||||
|
more-itertools = "^10.5.0"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
pyright = "^1.1.389"
|
pyright = "^1.1.389"
|
||||||
|
@ -1,7 +1,79 @@
|
|||||||
|
import math
|
||||||
|
from dataclasses import dataclass
|
||||||
from typing import Any, Iterator
|
from typing import Any, Iterator
|
||||||
|
|
||||||
|
import parse # pyright: ignore[reportMissingTypeStubs]
|
||||||
|
|
||||||
from ..base import BaseSolver
|
from ..base import BaseSolver
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Machine:
|
||||||
|
prize: tuple[int, int]
|
||||||
|
button_a: tuple[int, int]
|
||||||
|
button_b: tuple[int, int]
|
||||||
|
|
||||||
|
|
||||||
|
def read_machine(block: str) -> Machine:
|
||||||
|
ba = parse.parse( # type: ignore
|
||||||
|
"""Button A: X{bax:d}, Y{bay:d}
|
||||||
|
Button B: X{bbx:d}, Y{bby:d}
|
||||||
|
Prize: X={px:d}, Y={py:d}""",
|
||||||
|
block,
|
||||||
|
)
|
||||||
|
return Machine(
|
||||||
|
prize=(ba["px"], ba["py"]), # type: ignore
|
||||||
|
button_a=(ba["bax"], ba["bay"]), # type: ignore
|
||||||
|
button_b=(ba["bbx"], ba["bby"]), # type: ignore
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def diophantine(a: int, b: int, c: int) -> tuple[int, int]:
|
||||||
|
q, r = divmod(a, b)
|
||||||
|
if r == 0:
|
||||||
|
return (0, c // b)
|
||||||
|
else:
|
||||||
|
u, v = diophantine(b, r, c)
|
||||||
|
return (v, u - q * v)
|
||||||
|
|
||||||
|
|
||||||
|
def solve(machine: Machine) -> int:
|
||||||
|
(ax, ay), (bx, by), (px, py) = machine.button_a, machine.button_b, machine.prize
|
||||||
|
dx, dy = math.gcd(ax, bx), math.gcd(ay, by)
|
||||||
|
|
||||||
|
if px % dx != 0 or py % dy != 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
xa, xb = diophantine(ax, bx, px)
|
||||||
|
ya, yb = diophantine(ay, by, py)
|
||||||
|
|
||||||
|
# expr (x): xa - kx * bx / dx, xb + kx * ax / dx
|
||||||
|
# expr (y): ya - ky * by / dy, yb + ky * ay / dy
|
||||||
|
|
||||||
|
num = ay * (ya - xa) + by * (yb - xb)
|
||||||
|
den = (ax * by - ay * bx) // dx
|
||||||
|
|
||||||
|
if num % den != 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
kx = num // den
|
||||||
|
pa, pb = xa - kx * bx // dx, xb + kx * ax // dx
|
||||||
|
return 3 * pa + pb
|
||||||
|
|
||||||
|
|
||||||
class Solver(BaseSolver):
|
class Solver(BaseSolver):
|
||||||
def solve(self, input: str) -> Iterator[Any]: ...
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
machines = [read_machine(block) for block in input.split("\n\n")]
|
||||||
|
|
||||||
|
yield sum(map(solve, machines))
|
||||||
|
|
||||||
|
shift = 10000000000000
|
||||||
|
machines = [
|
||||||
|
Machine(
|
||||||
|
prize=(shift + m.prize[0], shift + m.prize[1]),
|
||||||
|
button_a=m.button_a,
|
||||||
|
button_b=m.button_b,
|
||||||
|
)
|
||||||
|
for m in machines
|
||||||
|
]
|
||||||
|
yield sum(map(solve, machines))
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,15 @@
|
|||||||
|
Button A: X+94, Y+34
|
||||||
|
Button B: X+22, Y+67
|
||||||
|
Prize: X=8400, Y=5400
|
||||||
|
|
||||||
|
Button A: X+26, Y+66
|
||||||
|
Button B: X+67, Y+21
|
||||||
|
Prize: X=12748, Y=12176
|
||||||
|
|
||||||
|
Button A: X+17, Y+86
|
||||||
|
Button B: X+84, Y+37
|
||||||
|
Prize: X=7870, Y=6450
|
||||||
|
|
||||||
|
Button A: X+69, Y+23
|
||||||
|
Button B: X+27, Y+71
|
||||||
|
Prize: X=18641, Y=10279
|
Loading…
Reference in New Issue
Block a user