Skip to content

Commit 53fcb4c

Browse files
committed
feat: day 10 completed
1 parent 5be2610 commit 53fcb4c

File tree

4 files changed

+141
-10
lines changed

4 files changed

+141
-10
lines changed

2024/inputs/day10.txt

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
101234653436698943210876543298108967890123211
2+
900945762567787651028945054167211876965254300
3+
812876851008632112987632167054340105874367891
4+
743987945219541003456542108981233234567809892
5+
657641434349898764565876232190543456452912763
6+
898530125896701651698965945087612387301103454
7+
101421056787672340789234876231201293219010989
8+
012336765410589121470125960140340184678321670
9+
987449870323431034561076054057653296501234521
10+
876558901210120345665780143968934187410345438
11+
034569821025001256676891232877065056309654589
12+
125678438136789867589872301986174145218789678
13+
678776569245234798434565432765289036785890541
14+
589989478910135652329806567874376123896781030
15+
431276321210023101210715432990145678765432121
16+
120345290923412302345620121087230109650187656
17+
098010187874503210989430101256521212341090347
18+
187623456365694567876543232344560301032181298
19+
012510589456787655469854741023478912345672107
20+
143421674307897846988767858910890109852109856
21+
231256014210978987671056967378765210763296705
22+
140347123900389034502340191269854307894585014
23+
051298034891276123216521780350123456765674323
24+
565434540762345637897435615443210523456001298
25+
876529651057850136988904306782107610987123367
26+
985018782348943245077211216790108901278994453
27+
123427890167654432106310345889299870122185432
28+
010568921211234501215445432976387761233076541
29+
129877432100235676301456701265456654394567650
30+
431066523231145985490389876014012534585658969
31+
302309012694046796781201078923453421673215678
32+
213218906783459873212212562112969010984504301
33+
304567815612163654304323453007878123435643210
34+
412359854309072345323456894314365036521754965
35+
563456743218781896210567765101254307810867874
36+
694105678907690787890698989210345218987980123
37+
787234563210581654321787876307896210898943321
38+
894563454671410010987345665456987346787652450
39+
763674589582323225676298767645459855898101067
40+
652983673497654134570156958912378764306678998
41+
341672102108987010987667843003569013215463210
42+
030501012896109823478766542103454320176354501
43+
125418923787210734569651033212169010083296101
44+
654327654654323601234569124349078321190187632
45+
789210125345434512103678765678767456783276543

2024/inputs/tests/test_day10.txt

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
89010123
2+
78121874
3+
87430965
4+
96549874
5+
45678903
6+
32019012
7+
01329801
8+
10456732

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

+84-5
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,101 @@
11
from __future__ import annotations
22

33
import time
4+
from functools import cache
5+
from itertools import product
46
from pathlib import Path
57

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

11+
TRAILHEAD = "0"
12+
END_OF_TRAIL = "9"
913

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

15+
def num_trails(contents: list[str], x: int, y: int, unique: bool = False) -> int:
16+
@cache
17+
def _find_all_trail_ends(x: int, y: int) -> set[tuple[int, int]]:
18+
nonlocal contents
19+
curr = contents[x][y]
20+
if curr == END_OF_TRAIL:
21+
return {(x, y)}
1322

14-
def part2(contents: str):
15-
return "Not done yet!"
23+
target = str(int(curr) + 1)
24+
trailheads = set()
25+
for dx, dy in [
26+
[-1, 0],
27+
[0, 1],
28+
[1, 0],
29+
[0, -1],
30+
]:
31+
newx, newy = x + dx, y + dy
32+
if not 0 <= newx < len(contents) or not 0 <= newy < len(contents[0]):
33+
# new point is outside bounds of the contents, ignore
34+
continue
35+
if contents[newx][newy] == target:
36+
trailheads |= _find_all_trail_ends(x=newx, y=newy)
37+
return trailheads
38+
39+
@cache
40+
def _find_num_unique_trails(x: int, y: int) -> int:
41+
# Oddly enough, this was the way I initially tried to solve Part 1
42+
# due to my misunderstanding things. I had to then go back and return a set
43+
# of those trail end coordinates, so as to have a unique set of trail ends,
44+
# which I could then count with len.
45+
# After finding that Part 2 was, indeed, this version,
46+
# I just re-built what I did at first and re-implemented with a flag.
47+
nonlocal contents
48+
curr = contents[x][y]
49+
if curr == END_OF_TRAIL:
50+
return 1
51+
52+
target = str(int(curr) + 1)
53+
trails = 0
54+
for dx, dy in [
55+
[-1, 0],
56+
[0, 1],
57+
[1, 0],
58+
[0, -1],
59+
]:
60+
newx, newy = x + dx, y + dy
61+
if not 0 <= newx < len(contents) or not 0 <= newy < len(contents[0]):
62+
# new point is outside bounds of the contents, ignore
63+
continue
64+
if contents[newx][newy] == target:
65+
trails += _find_num_unique_trails(x=newx, y=newy)
66+
return trails
67+
68+
if unique:
69+
# Part 2
70+
return _find_num_unique_trails(x=x, y=y)
71+
72+
# Part 1
73+
trailhead_set = _find_all_trail_ends(x=x, y=y)
74+
return len(trailhead_set)
75+
76+
77+
def part1(contents: list[str]) -> int:
78+
total = 0
79+
for x, line in enumerate(contents):
80+
for y, char in enumerate(line):
81+
if char == TRAILHEAD:
82+
num = num_trails(contents=contents, x=x, y=y)
83+
total += num
84+
return total
85+
86+
87+
def part2(contents: list[str]) -> int:
88+
total = 0
89+
for x, line in enumerate(contents):
90+
for y, char in enumerate(line):
91+
if char == TRAILHEAD:
92+
num = num_trails(contents=contents, x=x, y=y, unique=True)
93+
total += num
94+
return total
1695

1796

1897
def main():
19-
contents = FILE.read_text()
98+
contents = FILE.read_text().strip().split("\n")
2099

21100
_start1 = time.perf_counter()
22101
result1 = part1(contents)

2024/python/src/grice_py_aoc_2024/day10/test_day10.py

+4-5
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 = 36
12+
EXPECTED_PART_2 = 81
1313

1414

1515
def test_part1():
16-
contents = TEST_FILE.read_text()
16+
contents = TEST_FILE.read_text().strip().split("\n")
1717
result = part1(contents)
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()
22+
contents = TEST_FILE.read_text().strip().split("\n")
2423
result = part2(contents)
2524
assert result == EXPECTED_PART_2

0 commit comments

Comments
 (0)