2019: d10: ex1: clean-up solution
This commit is contained in:
parent
b42bf6c526
commit
20546f5e81
|
@ -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}")
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue