diff --git a/2019/d10/ex1/ex1.py b/2019/d10/ex1/ex1.py index 79f1ed4..eb538df 100755 --- a/2019/d10/ex1/ex1.py +++ b/2019/d10/ex1/ex1.py @@ -1,79 +1,49 @@ #!/usr/bin/env python import sys -from itertools import chain from math import gcd -from typing import Set, Tuple +from typing import NamedTuple, Set -Position = Tuple[int, int] + +class Position(NamedTuple): + x: int + y: int def main() -> None: - asteroids = [[c == "#" for c in line.rstrip()] for line in sys.stdin.readlines()] - - def count_spotted(i: int, j: int) -> int: - def is_valid(pos: Position) -> bool: - return 0 <= pos[0] < len(asteroids) and 0 <= pos[1] < len(asteroids[0]) - - def pos_around(radius: int) -> Set[Position]: - return set( - chain( - filter( - is_valid, - ( - (i - offset, j - radius) - for offset in range(-radius, radius + 1) - ), - ), - filter( - is_valid, - ( - (i - offset, j + radius) - for offset in range(-radius, radius + 1) - ), - ), - filter( - is_valid, - ( - (i - radius, j - offset) - for offset in range(-radius, radius + 1) - ), - ), - filter( - is_valid, - ( - (i + radius, j - offset) - for offset in range(-radius, radius + 1) - ), - ), - ) - ) + asteroids = [ + Position(x, y) + for y, line in enumerate(sys.stdin.readlines()) + for x, c in enumerate(line.rstrip()) + if c == "#" + ] + def count_spotted(x: int, y: int) -> int: seen: Set[Position] = set() ans = 0 radius = 1 - while asteroids[i][j]: # Only do this if are on an asteroid - to_visit = pos_around(radius) + + while True: + + def is_r_away(pos: Position) -> bool: + return max(abs(pos.x - x), abs(pos.y - y)) == radius + + to_visit = list(filter(is_r_away, asteroids)) radius += 1 if len(to_visit) == 0: break for pos in to_visit: - if not asteroids[pos[0]][pos[1]]: - continue # No asteroid there - rel = (pos[0] - i, pos[1] - j) + rel = (pos.x - x, pos.y - y) common = gcd(*rel) - rel = (rel[0] // common, rel[1] // common) + rel = Position(*(a // common for a in rel)) if rel in seen: continue # Already have an asteroid on this path seen.add(rel) ans += 1 + return ans - ans, y, x = max( - (count_spotted(i, j), i, j) - for i in range(len(asteroids)) - for j in range(len(asteroids[0])) - ) + ans, x, y = max((count_spotted(*pos), *pos) for pos in asteroids) print(f"({x}, {y}): {ans}")