From 39060b5faedd40521a1ffd146dc75ff57c931376 Mon Sep 17 00:00:00 2001 From: Daniel Lin Date: Tue, 26 Dec 2023 15:46:50 -0500 Subject: [PATCH] Day 24: Never Tell Me The Odds (part 2) --- README.md | 2 +- py/aoc2023/day24.py | 51 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a6fda807..8da1283b 100644 --- a/README.md +++ b/README.md @@ -28,5 +28,5 @@ Development occurs in language-specific directories: |[Day21.hs](hs/src/Day21.hs)|[Day21.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day21.kt)|[day21.py](py/aoc2023/day21.py)|[day21.rs](rs/src/day21.rs)| |[Day22.hs](hs/src/Day22.hs)|[Day22.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day22.kt)|[day22.py](py/aoc2023/day22.py)|[day22.rs](rs/src/day22.rs)| |[Day23.hs](hs/src/Day23.hs)|[Day23.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day23.kt)||[day23.rs](rs/src/day23.rs)| -|[Day24.hs](hs/src/Day24.hs)|[Day24.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day24.kt) ½|[day24.py](py/aoc2023/day24.py) ½|[day24.rs](rs/src/day24.rs) ½| +|[Day24.hs](hs/src/Day24.hs)|[Day24.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day24.kt) ½|[day24.py](py/aoc2023/day24.py)|[day24.rs](rs/src/day24.rs) ½| |[Day25.hs](hs/src/Day25.hs)|[Day25.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day25.kt)|[day25.py](py/aoc2023/day25.py)|[day25.rs](rs/src/day25.rs)| diff --git a/py/aoc2023/day24.py b/py/aoc2023/day24.py index bff4e78d..54abf1a2 100644 --- a/py/aoc2023/day24.py +++ b/py/aoc2023/day24.py @@ -2,6 +2,8 @@ Day 24: Never Tell Me The Odds """ +from fractions import Fraction + SAMPLE_INPUT = """19, 13, 30 @ -2, 1, -2 18, 19, 22 @ -1, -1, -2 20, 25, 34 @ -2, -2, -4 @@ -50,11 +52,52 @@ def part1(data, lo=200000000000000, hi=400000000000000): def part2(data): """ - >>> part2(SAMPLE_INPUT) # doctest: +SKIP + >>> part2(SAMPLE_INPUT) 47 """ - _parse(data) - raise NotImplementedError() + points = list(_parse(data)) + for i, ((x0, y0, z0), (vx0, vy0, vz0)) in enumerate(points): + + # pylint: disable=cell-var-from-loop + def offset(point): + (x1, y1, z1), (vx1, vy1, vz1) = point + return (x1 - x0, y1 - y0, z1 - z0), (vx1 - vx0, vy1 - vy0, vz1 - vz0) + + for j, ((x1, y1, z1), (vx1, vy1, vz1)) in enumerate(map(offset, points[:i])): + px1 = y1 * vz1 - z1 * vy1 + py1 = z1 * vx1 - x1 * vz1 + pz1 = x1 * vy1 - y1 * vx1 + + for (x2, y2, z2), (vx2, vy2, vz2) in map(offset, points[:j]): + px2 = y2 * vz2 - z2 * vy2 + py2 = z2 * vx2 - x2 * vz2 + pz2 = x2 * vy2 - y2 * vx2 + + mx = py1 * pz2 - pz1 * py2 + my = pz1 * px2 - px1 * pz2 + mz = px1 * py2 - py1 * px2 + + if my * vx1 == mx * vy1 or my * vx2 == mx * vy2: + continue + + u1 = Fraction(y1 * vx1 - x1 * vy1, my * vx1 - mx * vy1) + u2 = Fraction(y2 * vx2 - x2 * vy2, my * vx2 - mx * vy2) + t1, t2 = ( + next( + (m * u - p) / v + for m, p, v in zip((mx, my, mz), (x, y, z), (vx, vy, vz)) + if v + ) + for u, x, y, z, vx, vy, vz in ( + (u1, x1, y1, z1, vx1, vy1, vz1), + (u2, x2, y2, z2, vx2, vy2, vz2), + ) + ) + return int( + x0 + y0 + z0 + (mx + my + mz) * (u1 * t2 - u2 * t1) / (t2 - t1) + ) + + return None -parts = (part1,) +parts = (part1, part2)