|
| 1 | +"""Boilerplate solution template for Advent of Code daily challenges. |
| 2 | +
|
| 3 | +This module provides a template class for solving Advent of Code puzzle problems. |
| 4 | +It includes a base structure with two method stubs (part1 and part2) that can be |
| 5 | +implemented for specific day's challenges. |
| 6 | +
|
| 7 | +The template follows the SolutionBase pattern used across the Advent of Code solutions, |
| 8 | +allowing for consistent handling of input parsing and solution execution. |
| 9 | +""" |
| 10 | + |
| 11 | +from functools import partial |
| 12 | +from typing import Callable |
| 13 | + |
| 14 | +from aoc.models.base import SolutionBase |
| 15 | + |
| 16 | + |
| 17 | +class Solution(SolutionBase): |
| 18 | + """Solution template for Advent of Code daily puzzle. |
| 19 | +
|
| 20 | + This class provides a standardized structure for implementing solutions to |
| 21 | + daily Advent of Code challenges. It inherits from SolutionBase and includes |
| 22 | + method stubs for part1 and part2 of the puzzle. |
| 23 | +
|
| 24 | + Subclasses should override these methods with specific implementation logic |
| 25 | + for parsing input and solving the puzzle requirements. |
| 26 | + """ |
| 27 | + |
| 28 | + def has_repeated_sequence(self, n: int, num_repeats: int = None) -> bool: |
| 29 | + s = str(n) |
| 30 | + length = len(s) |
| 31 | + |
| 32 | + if num_repeats: |
| 33 | + if num_repeats <= 1: |
| 34 | + return False |
| 35 | + |
| 36 | + if length % num_repeats != 0: |
| 37 | + return False |
| 38 | + |
| 39 | + size = length // num_repeats |
| 40 | + return s == s[:size] * num_repeats |
| 41 | + |
| 42 | + else: # Check for any number of repetitions > 1 |
| 43 | + for k in range(2, length + 1): |
| 44 | + if length % k == 0: |
| 45 | + size = length // k |
| 46 | + if s == s[:size] * k: |
| 47 | + return True |
| 48 | + |
| 49 | + return False |
| 50 | + |
| 51 | + def solve_part(self, data: list[str], func: Callable) -> int: |
| 52 | + """Calculates the sum of numbers in ranges that satisfy the check_func.""" |
| 53 | + invalid = 0 |
| 54 | + for line in data[0].split(","): |
| 55 | + start, end = map(int, line.split("-")) |
| 56 | + for product in range(start, end + 1): |
| 57 | + if func(product): |
| 58 | + invalid += product |
| 59 | + |
| 60 | + return invalid |
| 61 | + |
| 62 | + def part1(self, data: list[str]) -> int: |
| 63 | + """Solve the first part of the daily puzzle. |
| 64 | +
|
| 65 | + Args: |
| 66 | + data: List of input strings to be processed |
| 67 | +
|
| 68 | + Returns |
| 69 | + ------- |
| 70 | + int: Solution for part 1 of the puzzle |
| 71 | + """ |
| 72 | + check_for_two_repeats = partial(self.has_repeated_sequence, num_repeats=2) |
| 73 | + return self.solve_part(data, check_for_two_repeats) |
| 74 | + |
| 75 | + def part2(self, data: list[str]) -> int: |
| 76 | + """Solve the second part of the daily puzzle. |
| 77 | +
|
| 78 | + Args: |
| 79 | + data: List of input strings to be processed |
| 80 | +
|
| 81 | + Returns |
| 82 | + ------- |
| 83 | + int: Solution for part 2 of the puzzle |
| 84 | + """ |
| 85 | + return self.solve_part(data, self.has_repeated_sequence) |
0 commit comments