|
4 | 4 | # |
5 | 5 |
|
6 | 6 | import sys |
| 7 | +from dataclasses import dataclass |
| 8 | +from typing import Self |
7 | 9 |
|
8 | 10 | from aoc import my_aocd |
9 | 11 | from aoc.common import InputData |
10 | 12 | from aoc.common import SolutionBase |
11 | 13 | from aoc.common import aoc_samples |
12 | 14 | from aoc.range import RangeInclusive |
13 | 15 |
|
14 | | -Input = InputData |
15 | | -Output1 = int |
16 | | -Output2 = int |
17 | | - |
18 | | - |
19 | 16 | TEST = """\ |
20 | 17 | 3-5 |
21 | 18 | 10-14 |
|
31 | 28 | """ |
32 | 29 |
|
33 | 30 |
|
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] |
37 | 35 |
|
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) |
52 | 39 | ranges = set[RangeInclusive]() |
53 | 40 | for line in blocks[0]: |
54 | 41 | lo, hi = map(int, line.split("-")) |
55 | 42 | 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)) |
61 | 64 |
|
62 | 65 | @aoc_samples( |
63 | 66 | ( |
|
0 commit comments