diff --git a/2018/d10/ex1/ex1.py b/2018/d10/ex1/ex1.py new file mode 100755 index 0000000..d33ca98 --- /dev/null +++ b/2018/d10/ex1/ex1.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python + +import itertools +import sys +from typing import NamedTuple + + +class Point(NamedTuple): + x: int + y: int + + +class Light(NamedTuple): + pos: Point + vel: Point + + def at(self, time: int) -> Point: + return Point(self.pos.x + self.vel.x * time, self.pos.y + self.vel.y * time) + + +def solve(input: str) -> str: + def parse_light(input: str) -> Light: + pos, vel = map(lambda s: s.split("=<")[1].removesuffix(">"), input.split("> ")) + return Light( + Point(*map(int, map(str.strip, pos.split(",")))), + Point(*map(int, map(str.strip, vel.split(",")))), + ) + + def parse(input: list[str]) -> list[Light]: + return [parse_light(line) for line in input] + + def move_lights(lights: list[Light], time: int) -> set[Point]: + return {l.at(time) for l in lights} + + def bbox_size(points: set[Point]) -> int: + min_x, max_x = min(p.x for p in points), max(p.x for p in points) + min_y, max_y = min(p.y for p in points), max(p.y for p in points) + return (max_x - min_x + 1) * (max_y - min_y + 1) + + def write_message(message: set[Point]) -> str: + min_x, max_x = min(p.x for p in message), max(p.x for p in message) + min_y, max_y = min(p.y for p in message), max(p.y for p in message) + + return "\n".join( + "".join( + "#" if Point(x, y) in message else "." for x in range(min_x, max_x + 1) + ) + for y in range(min_y, max_y + 1) + ) + + lights = parse(input.splitlines()) + max_time = max( + map(abs, itertools.chain.from_iterable((l.pos.x, l.pos.y) for l in lights)) + ) + message = min((move_lights(lights, t) for t in range(max_time)), key=bbox_size) + return write_message(message) + + +def main() -> None: + input = sys.stdin.read() + print(solve(input)) + + +if __name__ == "__main__": + main()