mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Super messy 2019 day 10
I accidentally inverted my y-axis and I'm not fixing it.
This commit is contained in:
93
2019/aoc2019/day10.py
Normal file
93
2019/aoc2019/day10.py
Normal file
@@ -0,0 +1,93 @@
|
||||
import math
|
||||
from collections import defaultdict
|
||||
from typing import TextIO, Tuple
|
||||
|
||||
import numpy # type: ignore
|
||||
|
||||
|
||||
def read_asteroids(data: TextIO) -> Tuple[numpy.array, numpy.array]:
|
||||
xs = []
|
||||
ys = []
|
||||
for y, line in enumerate(data):
|
||||
for x, c in enumerate(line):
|
||||
if c == '#':
|
||||
xs.append(x)
|
||||
ys.append(y)
|
||||
|
||||
return numpy.array(xs), -numpy.array(ys)
|
||||
|
||||
|
||||
def asteroids_visible(x: int, y: int, xs: numpy.array, ys: numpy.array) -> int:
|
||||
dx = xs - x
|
||||
dy = ys - y
|
||||
|
||||
div = numpy.abs(numpy.gcd(dx, dy))
|
||||
|
||||
mask = div != 0
|
||||
|
||||
dx[mask] //= div[mask]
|
||||
dy[mask] //= div[mask]
|
||||
|
||||
unique = set(zip(dx, dy))
|
||||
|
||||
return len(unique) - 1 # need to ignore the point itself
|
||||
|
||||
|
||||
def part1(data: TextIO) -> int:
|
||||
xs, ys = read_asteroids(data)
|
||||
|
||||
return max(asteroids_visible(x, y, xs, ys) for x, y in zip(xs, ys))
|
||||
|
||||
|
||||
def part2(data: TextIO) -> int:
|
||||
xs, ys = read_asteroids(data)
|
||||
|
||||
cx, cy = max(zip(xs, ys), key=lambda c: asteroids_visible(c[0], c[1], xs, ys))
|
||||
|
||||
dx = xs - cx
|
||||
dy = ys - cy
|
||||
|
||||
angles = numpy.arctan2(dy, dx)
|
||||
distances = numpy.abs(numpy.copy(dx)) + numpy.abs(numpy.copy(dy))
|
||||
|
||||
to_shoot = defaultdict(list)
|
||||
|
||||
for angle, distance, dx, dy in zip(angles, distances, dx, dy):
|
||||
if distance == 0:
|
||||
# The point itself
|
||||
continue
|
||||
|
||||
to_shoot[angle].append((distance, dx, dy))
|
||||
|
||||
for distances in to_shoot.values():
|
||||
distances.sort(reverse=True)
|
||||
|
||||
unique_angles = sorted(set(angles), reverse=True)
|
||||
|
||||
shot = 0
|
||||
|
||||
# First shoot from up clockwise
|
||||
for angle in unique_angles:
|
||||
if angle > math.pi / 2:
|
||||
continue
|
||||
|
||||
shot += 1
|
||||
|
||||
_, dx, dy = to_shoot[angle].pop()
|
||||
|
||||
# Repeatedly shoot until you reach #200
|
||||
while True:
|
||||
for angle in unique_angles:
|
||||
if not to_shoot[angle]:
|
||||
# Nothing left to shoot
|
||||
continue
|
||||
|
||||
shot += 1
|
||||
|
||||
_, dx, dy = to_shoot[angle].pop()
|
||||
|
||||
if shot == 200:
|
||||
x = cx + dx
|
||||
y = -(cy + dy)
|
||||
return 100 * x + y
|
||||
|
||||
86
2019/tests/test_day10.py
Normal file
86
2019/tests/test_day10.py
Normal file
@@ -0,0 +1,86 @@
|
||||
from io import StringIO
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
|
||||
from aoc2019.day10 import part1, part2
|
||||
|
||||
LARGE_SAMPLE = """\
|
||||
.#..##.###...#######
|
||||
##.############..##.
|
||||
.#.######.########.#
|
||||
.###.#######.####.#.
|
||||
#####.##.#.##.###.##
|
||||
..#####..#.#########
|
||||
####################
|
||||
#.####....###.#.#.##
|
||||
##.#################
|
||||
#####.##.###..####..
|
||||
..######..##.#######
|
||||
####.##.####...##..#
|
||||
.#####..#.######.###
|
||||
##...#.##########...
|
||||
#.##########.#######
|
||||
.####.#.###.###.#.##
|
||||
....##.##.###..#####
|
||||
.#.#.###########.###
|
||||
#.#.#.#####.####.###
|
||||
###.##.####.##.#..##
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.parametrize('visible,field', [
|
||||
(8, dedent("""\
|
||||
.#..#
|
||||
.....
|
||||
#####
|
||||
....#
|
||||
...##
|
||||
""")),
|
||||
(33, dedent("""\
|
||||
......#.#.
|
||||
#..#.#....
|
||||
..#######.
|
||||
.#.#.###..
|
||||
.#..#.....
|
||||
..#....#.#
|
||||
#..#....#.
|
||||
.##.#..###
|
||||
##...#..#.
|
||||
.#....####
|
||||
""")),
|
||||
(35, dedent("""\
|
||||
#.#...#.#.
|
||||
.###....#.
|
||||
.#....#...
|
||||
##.#.#.#.#
|
||||
....#.#.#.
|
||||
.##..###.#
|
||||
..#...##..
|
||||
..##....##
|
||||
......#...
|
||||
.####.###.
|
||||
""")),
|
||||
(41, dedent("""\
|
||||
.#..#..###
|
||||
####.###.#
|
||||
....###.#.
|
||||
..###.##.#
|
||||
##.##.#.#.
|
||||
....###..#
|
||||
..#.#..#.#
|
||||
#..#.#.###
|
||||
.##...##.#
|
||||
.....#.#..
|
||||
""")),
|
||||
(210, LARGE_SAMPLE),
|
||||
])
|
||||
def test_samples_part1(visible: int, field: str) -> None:
|
||||
data = StringIO(field.strip())
|
||||
assert part1(data) == visible
|
||||
|
||||
|
||||
def test_samples_part2():
|
||||
data = StringIO(LARGE_SAMPLE.strip())
|
||||
|
||||
assert part2(data) == 802
|
||||
Reference in New Issue
Block a user