Skip to content

Commit add4352

Browse files
committed
feat: 2024 day 8 py
1 parent 7134e9d commit add4352

File tree

5 files changed

+154
-14
lines changed

5 files changed

+154
-14
lines changed

2024/inputs/day08.txt

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
...........6.b....................................
2+
........6................8........................
3+
..Y.......................................o.......
4+
....V...j............B.............c..............
5+
............8.........X.......L...................
6+
.....j..v6.......3.L..................c...........
7+
..Mj.....p3.......b........Z....................J.
8+
..........M...X...................................
9+
V..............v......p.........Z.........c.......
10+
..............3...................................
11+
.......V......U3.............c....................
12+
..........b..v.M.U8...............................
13+
..........j........8.....................J........
14+
..........Y......q........LH..Z...D...........y...
15+
..2Y........PX......6..................BQ.........
16+
...0.Y...............XP...........w...............
17+
.........U.......2...............oH.y.............
18+
0..............9........U.........................
19+
...........P..............W.......z...Oy..........
20+
...................t...p.W..o.............Q.......
21+
.....S.................t.....Q....B...............
22+
S.k..................V..W...p.......H...O......m..
23+
....S.h................W.......................O..
24+
..h..P.2.............Z.............J..............
25+
.........k.......5v.......q...t.s.................
26+
.....Q.....h..........................J...B.......
27+
........0.........l...............................
28+
.S................................................
29+
.............................M....................
30+
2..................e.....o.....y..................
31+
................k.................................
32+
......4......k....t...s.q.........................
33+
.4.......................q........................
34+
.......................z....E.....................
35+
.............0.....d..............................
36+
7..........D........z.............................
37+
.......D..5......7..9.............................
38+
......5..................E........................
39+
D..............K......d..9E..........w.....1..C...
40+
.......K..x.........d....s...........l............
41+
........7......................u...C..............
42+
..K........x..............9..C...u................
43+
4..............s.........................l...T..w.
44+
.......5.....7..................m......T......1...
45+
...........................E...z.m................
46+
......................................u...C.......
47+
.............................em...................
48+
..............................................T...
49+
....................x.......................e.....
50+
.............................1e....w....l.........

2024/inputs/tests/test_day08.txt

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
............
2+
........0...
3+
.....0......
4+
.......0....
5+
....0.......
6+
......A.....
7+
............
8+
............
9+
........A...
10+
.........A..
11+
............
12+
............

2024/python/src/grice_py_aoc_2024/day06/test_day06.py

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ def test_part1():
1818
assert result == EXPECTED_PART_1
1919

2020

21+
@pytest.mark.xfail(reason="Not done yet")
2122
def test_part2():
2223
grid = TEST_FILE.read_text().strip().split("\n")
2324
result = part2(grid=grid)

2024/python/src/grice_py_aoc_2024/day08/main.py

+85-7
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,108 @@
11
from __future__ import annotations
22

33
import time
4+
from collections import defaultdict
45
from pathlib import Path
6+
from typing import Protocol
57

68
DIR = Path(__file__).parent
79
FILE = DIR.parents[3] / "inputs" / f"{DIR.stem}.txt"
810

11+
CoordType = tuple[int, int]
12+
"""Generic coordinate, 2-tuple of ints."""
913

10-
def part1(contents: str):
11-
return "Not done yet!"
1214

15+
class CalcerType(Protocol):
16+
"""Protocol for a caculator func that can be passed to `num_antinodes` function."""
1317

14-
def part2(contents: str):
15-
return "Not done yet!"
18+
def __call__(
19+
self,
20+
grid: list[str],
21+
c1: CoordType,
22+
c2: CoordType,
23+
) -> set[CoordType]: ...
24+
25+
26+
def _calc_anti_nodes(
27+
grid: list[str],
28+
c1: CoordType,
29+
c2: CoordType,
30+
part2: bool = False,
31+
) -> set[CoordType]:
32+
"""Calculates antinodes for the given two points, in part 1."""
33+
len_col, len_row = len(grid), len(grid[0])
34+
permutations = [(c1, c2), (c2, c1)]
35+
new_antinodes: set[CoordType] = set()
36+
37+
if part2:
38+
# Preset the "new" antinodes to include the current nodes
39+
new_antinodes = {c1, c2}
40+
41+
for first, second in permutations:
42+
curr_a, curr_b = first, second
43+
while True:
44+
new_node = (
45+
(2 * curr_b[0]) - curr_a[0],
46+
(2 * curr_b[1]) - curr_a[1],
47+
)
48+
if -1 < new_node[0] < len_col and -1 < new_node[1] < len_row:
49+
new_antinodes.add(new_node)
50+
# TODO accurate swap?
51+
curr_a, curr_b = curr_b, new_node
52+
if not part2:
53+
break
54+
else:
55+
break
56+
57+
return new_antinodes
58+
59+
60+
def num_antinodes(grid: list[str], part2: bool = False) -> int:
61+
"""General method for getting the number of antinodes."""
62+
antinodes: dict[CoordType, list[str]] = defaultdict(list)
63+
nodes: dict[str, set[CoordType]] = defaultdict(set)
64+
65+
for x, line in enumerate(grid):
66+
for y, char in enumerate(line):
67+
if char == ".":
68+
# skip non-antenna
69+
continue
70+
this_coord = (x, y)
71+
for seen_node in nodes[char]:
72+
new_antinodes = _calc_anti_nodes(
73+
grid=grid,
74+
c1=seen_node,
75+
c2=this_coord,
76+
part2=part2,
77+
)
78+
for new_antinode in new_antinodes:
79+
antinodes[new_antinode].append(char)
80+
nodes[char].add(this_coord)
81+
82+
return len(antinodes)
83+
84+
85+
def part1(grid: list[str]) -> int:
86+
"""Part 1 solver."""
87+
return num_antinodes(grid=grid)
88+
89+
90+
def part2(grid: list[str]) -> int:
91+
"""Part 2 solver."""
92+
return num_antinodes(grid=grid, part2=True)
1693

1794

1895
def main():
19-
contents = FILE.read_text()
96+
"""Entrypoint."""
97+
grid = FILE.read_text().strip().split("\n")
2098

2199
_start1 = time.perf_counter()
22-
result1 = part1(contents)
100+
result1 = part1(grid)
23101
_delta1 = time.perf_counter() - _start1
24102
print(f">> Part 1: {result1} ({_delta1:.6f}s)")
25103

26104
_start2 = time.perf_counter()
27-
result2 = part2(contents)
105+
result2 = part2(grid)
28106
_delta2 = time.perf_counter() - _start2
29107
print(f">> Part 2: {result2} ({_delta2:.6f}s)")
30108

2024/python/src/grice_py_aoc_2024/day08/test_day08.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,17 @@
88

99
DIR = Path(__file__).parent
1010
TEST_FILE = DIR.parents[3] / "inputs/tests" / f"test_{DIR.stem}.txt"
11-
EXPECTED_PART_1 = "REPLACE ME!"
12-
EXPECTED_PART_2 = "REPLACE ME!"
11+
EXPECTED_PART_1 = 14
12+
EXPECTED_PART_2 = 34
1313

1414

1515
def test_part1():
16-
contents = TEST_FILE.read_text()
17-
result = part1(contents)
16+
grid = TEST_FILE.read_text().strip().split("\n")
17+
result = part1(grid=grid)
1818
assert result == EXPECTED_PART_1
1919

2020

21-
@pytest.mark.xfail(reason=f"{DIR.stem} P1 incomplete")
2221
def test_part2():
23-
contents = TEST_FILE.read_text()
24-
result = part2(contents)
22+
grid = TEST_FILE.read_text().strip().split("\n")
23+
result = part2(grid=grid)
2524
assert result == EXPECTED_PART_2

0 commit comments

Comments
 (0)