Skip to content

Commit 591ef2a

Browse files
committed
AoC 2025 Day 5 - cleanup
1 parent 97e296f commit 591ef2a

File tree

3 files changed

+47
-45
lines changed

3 files changed

+47
-45
lines changed

src/main/python/AoC2019_04.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import sys
77
from collections import Counter
8-
from typing import Callable
8+
from collections.abc import Callable
99

1010
from aoc.common import InputData
1111
from aoc.common import SolutionBase
@@ -18,7 +18,7 @@
1818

1919
class Solution(SolutionBase[Input, Output1, Output2]):
2020
def parse_input(self, input_data: InputData) -> Input:
21-
a, b = list(input_data)[0].split("-")
21+
a, b = next(iter(input_data)).split("-")
2222
return RangeInclusive.between(int(a), int(b))
2323

2424
def does_not_decrease(self, passw: str) -> bool:
@@ -30,14 +30,14 @@ def is_valid_1(self, passw: str) -> bool:
3030
def is_valid_2(self, passw: str) -> bool:
3131
return self.does_not_decrease(passw) and 2 in Counter(passw).values()
3232

33-
def count_valid(self, range: Input, check: Callable[[str], bool]) -> int:
34-
return sum(check(str(i)) for i in range.iterator())
33+
def count_valid(self, rng: Input, check: Callable[[str], bool]) -> int:
34+
return sum(check(str(i)) for i in rng.iterator())
3535

36-
def part_1(self, range: Input) -> int:
37-
return self.count_valid(range, self.is_valid_1)
36+
def part_1(self, rng: Input) -> int:
37+
return self.count_valid(rng, self.is_valid_1)
3838

39-
def part_2(self, range: Input) -> int:
40-
return self.count_valid(range, self.is_valid_2)
39+
def part_2(self, rng: Input) -> int:
40+
return self.count_valid(rng, self.is_valid_2)
4141

4242
def samples(self) -> None:
4343
assert self.is_valid_1("122345")

src/main/python/AoC2025_05.py

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,15 @@
44
#
55

66
import sys
7+
from dataclasses import dataclass
8+
from typing import Self
79

810
from aoc import my_aocd
911
from aoc.common import InputData
1012
from aoc.common import SolutionBase
1113
from aoc.common import aoc_samples
1214
from aoc.range import RangeInclusive
1315

14-
Input = InputData
15-
Output1 = int
16-
Output2 = int
17-
18-
1916
TEST = """\
2017
3-5
2118
10-14
@@ -31,33 +28,39 @@
3128
"""
3229

3330

34-
class Solution(SolutionBase[Input, Output1, Output2]):
35-
def parse_input(self, input_data: InputData) -> Input:
36-
return input_data
31+
@dataclass(frozen=True)
32+
class Database:
33+
id_ranges: set[RangeInclusive]
34+
available_ids: list[int]
3735

38-
def part_1(self, inputs: Input) -> Output1:
39-
blocks = my_aocd.to_blocks(list(inputs))
40-
ranges = set[range]()
41-
for line in blocks[0]:
42-
lo, hi = map(int, line.split("-"))
43-
ranges.add(range(lo, hi + 1))
44-
ans = 0
45-
for line in blocks[1]:
46-
if any(int(line) in rng for rng in ranges):
47-
ans += 1
48-
return ans
49-
50-
def part_2(self, inputs: Input) -> Output2:
51-
blocks = my_aocd.to_blocks(list(inputs))
36+
@classmethod
37+
def from_input(cls, input_data: InputData) -> Self:
38+
blocks = my_aocd.to_blocks(input_data)
5239
ranges = set[RangeInclusive]()
5340
for line in blocks[0]:
5441
lo, hi = map(int, line.split("-"))
5542
ranges.add(RangeInclusive.between(lo, hi))
56-
merged = RangeInclusive.merge(ranges)
57-
ans = 0
58-
for rng in merged:
59-
ans += rng.len
60-
return ans
43+
pids = [int(line) for line in blocks[1]]
44+
return cls(ranges, pids)
45+
46+
47+
Input = Database
48+
Output1 = int
49+
Output2 = int
50+
51+
52+
class Solution(SolutionBase[Input, Output1, Output2]):
53+
def parse_input(self, input_data: InputData) -> Input:
54+
return Database.from_input(input_data)
55+
56+
def part_1(self, database: Input) -> Output1:
57+
return sum(
58+
any(rng.contains(pid) for rng in database.id_ranges)
59+
for pid in database.available_ids
60+
)
61+
62+
def part_2(self, database: Input) -> Output2:
63+
return sum(rng.len for rng in RangeInclusive.merge(database.id_ranges))
6164

6265
@aoc_samples(
6366
(

src/main/python/aoc/range.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
from __future__ import annotations
2-
3-
from typing import Iterable
4-
from typing import Iterator
1+
from collections.abc import Iterable
2+
from collections.abc import Iterator
53
from typing import NamedTuple
4+
from typing import Self
65

76

87
class Range:
@@ -30,19 +29,19 @@ class RangeInclusive(NamedTuple):
3029
maximum: int
3130

3231
@classmethod
33-
def between(cls, minimum: int, maximum: int) -> RangeInclusive:
34-
return RangeInclusive(minimum, maximum)
32+
def between(cls, minimum: int, maximum: int) -> Self:
33+
return cls(minimum, maximum)
3534

3635
@classmethod
37-
def merge(cls, ranges: Iterable[RangeInclusive]) -> list[RangeInclusive]:
38-
merged = list[RangeInclusive]()
36+
def merge(cls, ranges: Iterable[Self]) -> list[Self]:
37+
merged = list[Self]()
3938
for rng in sorted(ranges):
4039
if len(merged) == 0:
4140
merged.append(rng)
4241
continue
4342
last = merged[-1]
4443
if last.is_overlapped_by(rng):
45-
merged[-1] = RangeInclusive.between(
44+
merged[-1] = cls.between(
4645
last.minimum, max(last.maximum, rng.maximum)
4746
)
4847
else:
@@ -56,7 +55,7 @@ def len(self) -> int:
5655
def contains(self, element: int) -> bool:
5756
return self.minimum <= element <= self.maximum
5857

59-
def is_overlapped_by(self, other: RangeInclusive) -> bool:
58+
def is_overlapped_by(self, other: Self) -> bool:
6059
return (
6160
other.contains(self.minimum)
6261
or other.contains(self.maximum)

0 commit comments

Comments
 (0)