2023: d24: ex2: add solution
This commit is contained in:
parent
df75f1c5d2
commit
ee84fa576d
65
2023/d24/ex2/ex2.py
Executable file
65
2023/d24/ex2/ex2.py
Executable file
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
from typing import NamedTuple
|
||||
|
||||
import z3
|
||||
|
||||
|
||||
class Point(NamedTuple):
|
||||
x: int
|
||||
y: int
|
||||
z: int
|
||||
|
||||
|
||||
class HailStone(NamedTuple):
|
||||
pos: Point
|
||||
vel: Point
|
||||
|
||||
|
||||
def solve(input: list[str]) -> int:
|
||||
def parse_line(line: str) -> HailStone:
|
||||
pos, vel = line.split(" @ ")
|
||||
return HailStone(
|
||||
Point(*map(int, pos.split(", "))), Point(*map(int, vel.split(", ")))
|
||||
)
|
||||
|
||||
def parse(input: list[str]) -> list[HailStone]:
|
||||
return [parse_line(line) for line in input]
|
||||
|
||||
# Bringing out the big guns to solve this
|
||||
def run_z3(hailstones: list[HailStone]) -> HailStone:
|
||||
solver = z3.Solver()
|
||||
|
||||
px, py, pz = (z3.Int(f"stone_p{coord}") for coord in ("x", "y", "z"))
|
||||
vx, vy, vz = (z3.Int(f"stone_v{coord}") for coord in ("x", "y", "z"))
|
||||
|
||||
for i, other in enumerate(hailstones):
|
||||
t = z3.Int(f"t_{i}")
|
||||
# Must be in the future
|
||||
solver.add(t >= 0)
|
||||
# Must hit the hailstone
|
||||
solver.add((px + vx * t) == (other.pos.x + other.vel.x * t))
|
||||
solver.add((py + vy * t) == (other.pos.y + other.vel.y * t))
|
||||
solver.add((pz + vz * t) == (other.pos.z + other.vel.z * t))
|
||||
|
||||
assert solver.check() == z3.sat # Sanity check
|
||||
|
||||
model = solver.model()
|
||||
return HailStone(
|
||||
Point(*(model.eval(v).as_long() for v in (px, py, pz))), # type: ignore
|
||||
Point(*(model.eval(v).as_long() for v in (vx, vy, vz))), # type: ignore
|
||||
)
|
||||
|
||||
hailstones = parse(input)
|
||||
stone = run_z3(hailstones)
|
||||
return sum(stone.pos)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
input = sys.stdin.read().splitlines()
|
||||
print(solve(input))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in a new issue