2019: d10: ex1: clean-up solution

This commit is contained in:
Bruno BELANYI 2019-12-11 16:37:36 +01:00
parent b42bf6c526
commit 20546f5e81

View file

@ -1,79 +1,49 @@
#!/usr/bin/env python #!/usr/bin/env python
import sys import sys
from itertools import chain
from math import gcd 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: def main() -> None:
asteroids = [[c == "#" for c in line.rstrip()] for line in sys.stdin.readlines()] asteroids = [
Position(x, y)
def count_spotted(i: int, j: int) -> int: for y, line in enumerate(sys.stdin.readlines())
def is_valid(pos: Position) -> bool: for x, c in enumerate(line.rstrip())
return 0 <= pos[0] < len(asteroids) and 0 <= pos[1] < len(asteroids[0]) if c == "#"
]
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)
),
),
)
)
def count_spotted(x: int, y: int) -> int:
seen: Set[Position] = set() seen: Set[Position] = set()
ans = 0 ans = 0
radius = 1 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 radius += 1
if len(to_visit) == 0: if len(to_visit) == 0:
break break
for pos in to_visit: for pos in to_visit:
if not asteroids[pos[0]][pos[1]]: rel = (pos.x - x, pos.y - y)
continue # No asteroid there
rel = (pos[0] - i, pos[1] - j)
common = gcd(*rel) common = gcd(*rel)
rel = (rel[0] // common, rel[1] // common) rel = Position(*(a // common for a in rel))
if rel in seen: if rel in seen:
continue # Already have an asteroid on this path continue # Already have an asteroid on this path
seen.add(rel) seen.add(rel)
ans += 1 ans += 1
return ans return ans
ans, y, x = max( ans, x, y = max((count_spotted(*pos), *pos) for pos in asteroids)
(count_spotted(i, j), i, j)
for i in range(len(asteroids))
for j in range(len(asteroids[0]))
)
print(f"({x}, {y}): {ans}") print(f"({x}, {y}): {ans}")