From db081bed303bc2d55e184ceaab47f8c56ea0eb64 Mon Sep 17 00:00:00 2001 From: Jeremy Kaplan Date: Sat, 8 Aug 2026 14:08:51 -0400 Subject: [PATCH] 2017 Day 13 Part 2 --- 2017/day13.py | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/2017/day13.py b/2017/day13.py index de669c9..4a88f1d 100644 --- a/2017/day13.py +++ b/2017/day13.py @@ -1,7 +1,10 @@ +from math import lcm +from dataclasses import dataclass + with open("input/day13.txt") as f: input = f.read() -scanners = {} +scanners: dict[int, int] = {} for line in input.splitlines(): parts = line.split(": ") @@ -26,4 +29,71 @@ def part1(scanners): return severity +def is_safe(scanners, delay): + for depth in range(max(scanners.keys()) + 1): + r = scanners.get(depth) + if r is None: + continue + + assert r > 1, r + cycle = (r - 1) * 2 + pos = (delay + depth) % cycle + if pos == 0: + return False + return True + + +@dataclass +class Scanner: + depth: int + cycle: int + + +@dataclass(order=True) +class Candidate: + delay: int + increment: int + + def __init__(self, delay: int, increment: int): + self.delay = delay % increment + self.increment = increment + + def __hash__(self): + return hash((self.delay % self.increment, self.increment)) + + def scale(self, scalar: int) -> set["Candidate"]: + res = set() + increment = self.increment * scalar + for i in range(scalar + 1): + res.add(Candidate(self.delay + i * self.increment, increment)) + return res + + def __str__(self): + return f"{self.delay} + k * {self.increment}" + + +def part2(scanner_map: dict[int, int]): + scanners: list[Scanner] = [] + for depth in range(max(scanner_map.keys()) + 1): + r = scanner_map.get(depth) + if r is None: + continue + cycle = (r - 1) * 2 + scanners.append(Scanner(depth, cycle)) + + candidates = {Candidate(0, 1)} + for s in scanners: + next: set[Candidate] = set() + for c in candidates: + scalar = lcm(c.increment, s.cycle) // c.increment + for n in c.scale(scalar): + if (n.delay + s.depth) % s.cycle: + next.add(n) + + candidates = next + + return min(c.delay for c in candidates) + + print(part1(scanners)) +print(part2(scanners))