1- """Boilerplate solution template for Advent of Code daily challenges.
1+ """Day 2: Gift Shop
22
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.
3+ This module provides the solution for Advent of Code 2025 - Day 2.
64
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.
5+ It identifies invalid product IDs within given ranges. An ID is considered
6+ invalid if it is formed by a repeating sequence of digits.
7+
8+ The module contains a Solution class that inherits from SolutionBase for
9+ parsing ID ranges and summing the invalid IDs found.
910"""
1011
1112from collections .abc import Callable
1516
1617
1718class Solution (SolutionBase ):
18- """Solution template for Advent of Code daily puzzle .
19+ """Find and sum invalid product IDs based on repeating digit patterns .
1920
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 .
21+ This solution processes a string of comma-separated ID ranges (e.g., "1-10,20-30").
22+ It checks each ID in every range to see if it matches a specific pattern of
23+ repeating digits .
2324
24- Subclasses should override these methods with specific implementation logic
25- for parsing input and solving the puzzle requirements .
25+ Part 1 defines an invalid ID as one made of a digit sequence repeated twice (e.g., 1212).
26+ Part 2 expands this to any ID made of a sequence repeated at least twice (e.g., 1212, 121212) .
2627 """
2728
2829 def has_repeated_sequence (self , n : int , num_repeats : int | None = None ) -> bool :
30+ """Check if a number consists of a repeating sequence of digits.
31+
32+ Args:
33+ n: The integer to check.
34+ num_repeats: If an integer, checks for exactly that many repetitions.
35+ If None, checks for any number of repetitions (>= 2).
36+
37+ Returns
38+ -------
39+ bool: True if the number is formed by a repeating sequence, False otherwise.
40+ """
2941 s = str (n )
3042 length = len (s )
3143
@@ -39,6 +51,7 @@ def has_repeated_sequence(self, n: int, num_repeats: int | None = None) -> bool:
3951 size = length // num_repeats
4052 return s == s [:size ] * num_repeats
4153
54+ # Check for any number of repetitions from 2 up to the length of the string
4255 for k in range (2 , length + 1 ):
4356 if length % k == 0 :
4457 size = length // k
@@ -47,37 +60,58 @@ def has_repeated_sequence(self, n: int, num_repeats: int | None = None) -> bool:
4760
4861 return False
4962
50- def solve_part (self , data : list [str ], func : Callable ) -> int :
51- invalid = 0
63+ def solve_part (self , data : list [str ], func : Callable [[int ], bool ]) -> int :
64+ """Generic solver to find and sum invalid IDs based on a check function.
65+
66+ Parses the input string of ranges, iterates through each number, and applies
67+ the provided checking function to identify and sum invalid IDs.
68+
69+ Args:
70+ data: A list containing one string of comma-separated ranges.
71+ func: A callable that takes an integer and returns True if it's invalid.
72+
73+ Returns
74+ -------
75+ int: The sum of all invalid product IDs found.
76+ """
77+ invalid_sum = 0
5278 for line in data [0 ].split ("," ):
5379 start , end = map (int , line .split ("-" ))
54- for product in range (start , end + 1 ):
55- if func (product ):
56- invalid += product
80+ for product_id in range (start , end + 1 ):
81+ if func (product_id ):
82+ invalid_sum += product_id
5783
58- return invalid
84+ return invalid_sum
5985
6086 def part1 (self , data : list [str ]) -> int :
61- """Solve the first part of the daily puzzle.
87+ """Calculate the sum of invalid IDs where a digit sequence is repeated twice.
88+
89+ An ID is invalid if it's formed by a sequence of digits repeated
90+ exactly twice (e.g., `6464` from `64`). This method sums all such
91+ IDs found in the input ranges.
6292
6393 Args:
64- data: List of input strings to be processed
94+ data: A list containing the input string of ID ranges.
6595
6696 Returns
6797 -------
68- int: Solution for part 1 of the puzzle
98+ int: The total sum of invalid IDs for Part 1.
6999 """
70100 check_func = partial (self .has_repeated_sequence , num_repeats = 2 )
71101 return self .solve_part (data , check_func )
72102
73103 def part2 (self , data : list [str ]) -> int :
74- """Solve the second part of the daily puzzle.
104+ """Calculate the sum of invalid IDs where a digit sequence is repeated at least twice.
105+
106+ An ID is invalid if it's formed by a sequence of digits repeated two
107+ or more times (e.g., `1212` or `121212`). This method sums all such
108+ IDs found in the input ranges.
75109
76110 Args:
77- data: List of input strings to be processed
111+ data: A list containing the input string of ID ranges.
78112
79113 Returns
80114 -------
81- int: Solution for part 2 of the puzzle
115+ int: The total sum of invalid IDs for Part 2.
82116 """
83117 return self .solve_part (data , self .has_repeated_sequence )
0 commit comments