mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Compare commits
2 Commits
2d49907692
...
dcb0f4514d
| Author | SHA1 | Date | |
|---|---|---|---|
| dcb0f4514d | |||
| dfee3d4e11 |
60
2024/src/aoc/days/day8.py
Normal file
60
2024/src/aoc/days/day8.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import itertools
|
||||||
|
import math
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
import numpy
|
||||||
|
|
||||||
|
from . import CombinedRunner
|
||||||
|
|
||||||
|
|
||||||
|
def simplify(vec: numpy.array) -> numpy.array:
|
||||||
|
if vec[0] == 0:
|
||||||
|
return numpy.array([0, 1])
|
||||||
|
elif vec[1] == 0:
|
||||||
|
return numpy.array([0, 1])
|
||||||
|
else:
|
||||||
|
div = math.gcd(*vec)
|
||||||
|
return vec // div
|
||||||
|
|
||||||
|
|
||||||
|
class DayRunner(CombinedRunner):
|
||||||
|
@classmethod
|
||||||
|
def run_both(cls, input: str) -> int:
|
||||||
|
grid = input.strip().split("\n")
|
||||||
|
height = len(grid)
|
||||||
|
width = len(grid[0])
|
||||||
|
|
||||||
|
antennae = defaultdict(list)
|
||||||
|
|
||||||
|
for y, line in enumerate(grid):
|
||||||
|
for x, c in enumerate(line):
|
||||||
|
if c != ".":
|
||||||
|
antennae[c].append(numpy.array([x, y]))
|
||||||
|
|
||||||
|
antinodes = set()
|
||||||
|
antinodes2 = set()
|
||||||
|
|
||||||
|
def in_bounds(node: numpy.array) -> bool:
|
||||||
|
return 0 <= node[0] < width and 0 <= node[1] < height
|
||||||
|
|
||||||
|
def add(node: numpy.array):
|
||||||
|
if in_bounds(node):
|
||||||
|
antinodes.add(tuple(node))
|
||||||
|
|
||||||
|
def walk(start: numpy.array, step: numpy.array):
|
||||||
|
for pos in itertools.count(start, step):
|
||||||
|
if in_bounds(pos):
|
||||||
|
antinodes2.add(tuple(pos))
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
for values in antennae.values():
|
||||||
|
for a, b in itertools.combinations(values, 2):
|
||||||
|
add(2 * a - b)
|
||||||
|
add(2 * b - a)
|
||||||
|
|
||||||
|
step = simplify(b - a)
|
||||||
|
walk(b, step)
|
||||||
|
walk(a, -step)
|
||||||
|
|
||||||
|
return len(antinodes), len(antinodes2)
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def get_data(day: int, sub: int | None = None) -> str:
|
||||||
|
basename = f"{day:02d}" if sub is None else f"{day:02d}.{sub}"
|
||||||
|
sample = os.path.dirname(__file__) + f"/samples/{basename}.txt"
|
||||||
|
with open(sample, mode="rt", encoding="utf-8") as f:
|
||||||
|
return f.read()
|
||||||
|
|||||||
12
2024/tests/samples/08.txt
Normal file
12
2024/tests/samples/08.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
............
|
||||||
|
........0...
|
||||||
|
.....0......
|
||||||
|
.......0....
|
||||||
|
....0.......
|
||||||
|
......A.....
|
||||||
|
............
|
||||||
|
............
|
||||||
|
........A...
|
||||||
|
.........A..
|
||||||
|
............
|
||||||
|
............
|
||||||
11
2024/tests/test_day01.py
Normal file
11
2024/tests/test_day01.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from aoc.days.day1 import DayRunner
|
||||||
|
|
||||||
|
from . import get_data
|
||||||
|
|
||||||
|
|
||||||
|
def test_sample_part1() -> None:
|
||||||
|
assert DayRunner.part1(get_data(1)) == 11
|
||||||
|
|
||||||
|
|
||||||
|
def test_sample_part2() -> None:
|
||||||
|
assert DayRunner.part2(get_data(1)) == 31
|
||||||
@@ -1,12 +1,6 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from aoc.days.day2 import DayRunner, is_savable
|
from aoc.days.day2 import DayRunner, is_savable
|
||||||
|
|
||||||
|
from . import get_data
|
||||||
def get_data() -> str:
|
|
||||||
sample = os.path.dirname(__file__) + "/samples/02.txt"
|
|
||||||
with open(sample, mode="rt", encoding="utf-8") as f:
|
|
||||||
return f.read()
|
|
||||||
|
|
||||||
|
|
||||||
def test_individual_samples() -> None:
|
def test_individual_samples() -> None:
|
||||||
@@ -19,8 +13,8 @@ def test_individual_samples() -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_sample_part1() -> None:
|
def test_sample_part1() -> None:
|
||||||
assert DayRunner.part1(get_data()) == 2
|
assert DayRunner.part1(get_data(2)) == 2
|
||||||
|
|
||||||
|
|
||||||
def test_sample_part2() -> None:
|
def test_sample_part2() -> None:
|
||||||
assert DayRunner.part2(get_data()) == 4
|
assert DayRunner.part2(get_data(2)) == 4
|
||||||
20
2024/tests/test_day04.py
Normal file
20
2024/tests/test_day04.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from aoc.days.day4 import DayRunner
|
||||||
|
|
||||||
|
from . import get_data
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"input,answer",
|
||||||
|
[
|
||||||
|
(get_data(4, 1), 4),
|
||||||
|
(get_data(4, 2), 18),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_sample_part1(input: str, answer: int) -> None:
|
||||||
|
assert DayRunner.part1(input) == answer
|
||||||
|
|
||||||
|
|
||||||
|
def test_sample_part2() -> None:
|
||||||
|
assert DayRunner.part2(get_data(4, 2)) == 9
|
||||||
15
2024/tests/test_day05.py
Normal file
15
2024/tests/test_day05.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
from aoc.days.day5 import DayRunner
|
||||||
|
|
||||||
|
from . import get_data
|
||||||
|
|
||||||
|
|
||||||
|
def test_sample_part1() -> None:
|
||||||
|
data = get_data(5)
|
||||||
|
|
||||||
|
assert DayRunner.part1(data) == 143
|
||||||
|
|
||||||
|
|
||||||
|
def test_sample_part2() -> None:
|
||||||
|
data = get_data(5)
|
||||||
|
|
||||||
|
assert DayRunner.part2(data) == 123
|
||||||
@@ -1,17 +1,11 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from aoc.days.day7 import DayRunner
|
from aoc.days.day7 import DayRunner
|
||||||
|
|
||||||
|
from . import get_data
|
||||||
def get_data() -> str:
|
|
||||||
sample = os.path.dirname(__file__) + "/samples/07.txt"
|
|
||||||
with open(sample, mode="rt", encoding="utf-8") as f:
|
|
||||||
return f.read()
|
|
||||||
|
|
||||||
|
|
||||||
def test_sample_part1() -> None:
|
def test_sample_part1() -> None:
|
||||||
assert DayRunner.part1(get_data()) == 3749
|
assert DayRunner.part1(get_data(7)) == 3749
|
||||||
|
|
||||||
|
|
||||||
def test_sample_part2() -> None:
|
def test_sample_part2() -> None:
|
||||||
assert DayRunner.part2(get_data()) == 11387
|
assert DayRunner.part2(get_data(7)) == 11387
|
||||||
|
|||||||
11
2024/tests/test_day08.py
Normal file
11
2024/tests/test_day08.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from aoc.days.day8 import DayRunner
|
||||||
|
|
||||||
|
from . import get_data
|
||||||
|
|
||||||
|
|
||||||
|
def test_sample_part1() -> None:
|
||||||
|
assert DayRunner.part1(get_data(8)) == 14
|
||||||
|
|
||||||
|
|
||||||
|
def test_sample_part2() -> None:
|
||||||
|
assert DayRunner.part2(get_data(8)) == 34
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from aoc.days.day1 import DayRunner
|
|
||||||
|
|
||||||
|
|
||||||
def get_data() -> str:
|
|
||||||
sample = os.path.dirname(__file__) + "/samples/01.txt"
|
|
||||||
with open(sample, mode="rt", encoding="utf-8") as f:
|
|
||||||
return f.read()
|
|
||||||
|
|
||||||
|
|
||||||
def test_sample_part1() -> None:
|
|
||||||
assert DayRunner.part1(get_data()) == 11
|
|
||||||
|
|
||||||
|
|
||||||
def test_sample_part2() -> None:
|
|
||||||
assert DayRunner.part2(get_data()) == 31
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from aoc.days.day4 import DayRunner
|
|
||||||
|
|
||||||
|
|
||||||
def get_data(which: int) -> str:
|
|
||||||
sample = os.path.dirname(__file__) + f"/samples/04.{which}.txt"
|
|
||||||
with open(sample, mode="rt", encoding="utf-8") as f:
|
|
||||||
return f.read()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"input,answer",
|
|
||||||
[
|
|
||||||
(get_data(1), 4),
|
|
||||||
(get_data(2), 18),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_sample_part1(input: str, answer: int) -> None:
|
|
||||||
assert DayRunner.part1(input) == answer
|
|
||||||
|
|
||||||
|
|
||||||
def test_sample_part2() -> None:
|
|
||||||
assert DayRunner.part2(get_data(2)) == 9
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from aoc.days.day5 import DayRunner
|
|
||||||
|
|
||||||
|
|
||||||
def get_data() -> str:
|
|
||||||
sample = os.path.dirname(__file__) + "/samples/05.txt"
|
|
||||||
with open(sample, mode="rt", encoding="utf-8") as f:
|
|
||||||
return f.read()
|
|
||||||
|
|
||||||
|
|
||||||
def test_sample_part1() -> None:
|
|
||||||
data = get_data()
|
|
||||||
|
|
||||||
assert DayRunner.part1(data) == 143
|
|
||||||
|
|
||||||
|
|
||||||
def test_sample_part2() -> None:
|
|
||||||
data = get_data()
|
|
||||||
|
|
||||||
assert DayRunner.part2(data) == 123
|
|
||||||
Reference in New Issue
Block a user