Skip to content

Commit 8d831e2

Browse files
committed
🎉D5P2 done! also added some typing, docstrings, and changed p1 to use any and a few minor changes.
1 parent fb39615 commit 8d831e2

File tree

1 file changed

+82
-20
lines changed

1 file changed

+82
-20
lines changed

‎aoc_25/solutions/day05.py‎

Lines changed: 82 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
"""Day 5 - Cafeteria"""
22

3-
from typing import Any
3+
from typing import Any, Iterator
44
from utils.aoc_utils import report_results, AoCResult, input_for_day
55

66
IngredientIds = list[int]
77
FreshRanges = list[range]
8+
FreshRange = tuple[int, int]
89

910
EXAMPLE: str = """3-5
1011
10-14
@@ -17,45 +18,106 @@
1718
11
1819
17
1920
32"""
20-
DATA = input_for_day(5, 2025)
21+
DATA: str = input_for_day(5, 2025)
2122

2223

2324
def parse_input(puzzle_input: str) -> tuple[FreshRanges, IngredientIds]:
24-
ranges: FreshRanges = []
25+
"""Convert input of str.
26+
Split on the \n\n, remove any \n from each line.
27+
Then parse fresh ranges into list of ranges, and
28+
ingredient ids into a list of ints.
29+
30+
Args:
31+
puzzle_input (str): Puzzle input.
32+
33+
Returns:
34+
tuple[FreshRanges, IngredientIds]: ranges of fresh ids, fresh ids.
35+
"""
2536
ranges_str, ingredient_ids_str = [
2637
x.splitlines() for x in puzzle_input.split('\n\n')
2738
]
28-
ranges = [
29-
range(start, end + 1) for start, end in (map(int, r.split('-')) for r in ranges_str)
39+
ranges: FreshRanges = [
40+
range(start, end + 1) for start,
41+
end in (map(int, r.split('-')) for r in ranges_str)
3042
]
3143

32-
# ranges_ints = [list(map(int, r.split('-'))) for r in ranges_str]
33-
# for rng in ranges_ints:
34-
# ranges.extend(list(range(rng[0], rng[1]+1)))
35-
3644
ingredient_ids: IngredientIds = list(map(int, ingredient_ids_str))
3745
return ranges, ingredient_ids
3846

3947

40-
def solve_part1(data: Any) -> int:
48+
def merge_ranges(ranges: FreshRanges) -> Iterator[FreshRange]:
49+
"""Merge current ranges if overlap in any way.
50+
51+
Args:
52+
ranges (FreshRanges): ranges of fresh ids
53+
54+
Yields:
55+
Iterator[FreshRange]: merged ranges
56+
"""
57+
# change ranges back to tuples of the start/stop
58+
sorted_rngs: Iterator[FreshRange] = iter(
59+
sorted((x.start, x.stop-1) for x in ranges)
60+
)
61+
start, end = next(sorted_rngs) # get first fresh range
62+
63+
for s, e in sorted_rngs:
64+
# if the next interval starts before/at current end
65+
# they overlap so merge range by getting biggest end
66+
if s <= end:
67+
end = max(end, e)
68+
else:
69+
# if they dont overlap - start a new fresh range
70+
# and yield the current one
71+
yield (start, end)
72+
start, end = s, e
73+
yield start, end
74+
75+
76+
def solve_part2(ranges: FreshRanges) -> int:
77+
"""Sum up the merged range lengths
78+
79+
Args:
80+
ranges (FreshRanges): fresh id ranges.
81+
82+
Returns:
83+
int: sum of lengths of ranges.
84+
"""
85+
# sum the lengths of each range
86+
return sum(len(range(x[0], x[1]+1)) for x in merge_ranges(ranges))
87+
88+
89+
def solve_day05(data: Any) -> tuple[int, int]:
90+
"""solve both days - check if an ingredient id is
91+
in any of the ranges. If so - break and count.
92+
93+
Then apply solve_part2.
94+
95+
Args:
96+
data (Any): Puzzle data.
97+
98+
Returns:
99+
tuple[int, int]: part 1 value, part 2 value.
100+
"""
41101
ranges, ingredient_ids = parse_input(data)
42-
valid_id = 0
43-
for x in ingredient_ids:
44-
for y in ranges:
45-
if x in y:
46-
valid_id += 1
47-
break
48-
return valid_id
102+
valid_id: int = 0
103+
for ingredient in ingredient_ids:
104+
# THE OLD WAY I DID IT.
105+
# for y in ranges:
106+
# if x in y:
107+
# valid_id += 1
108+
# break
109+
if any(ingredient in r for r in ranges):
110+
valid_id += 1
111+
return valid_id, solve_part2(ranges)
49112

50113

51114
@report_results
52115
def solveday(data: Any) -> AoCResult:
53-
p1: int = solve_part1(data)
54-
p2: int = 0
116+
p1, p2 = solve_day05(data)
55117
return p1, p2
56118

57119

58-
expected_test_results: AoCResult = (3, 0)
120+
expected_test_results: AoCResult = (3, 14)
59121

60122

61123
def tests(test_input: Any) -> None:

0 commit comments

Comments
 (0)