diff --git a/2019/d10/ex1/ex1.py b/2019/d10/ex1/ex1.py new file mode 100755 index 0000000..79f1ed4 --- /dev/null +++ b/2019/d10/ex1/ex1.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python + +import sys +from itertools import chain +from math import gcd +from typing import Set, Tuple + +Position = Tuple[int, 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) + ), + ), + ) + ) + + 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) + 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) + common = gcd(*rel) + rel = (rel[0] // common, rel[1] // common) + 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])) + ) + print(f"({x}, {y}): {ans}") + + +if __name__ == "__main__": + main()