@@ -18,63 +18,113 @@ impl Day02 {
1818
1919 #[ must_use]
2020 pub fn part1 ( & self ) -> u64 {
21+ self . invalid_id_sum ( |repeats| repeats == 2 )
22+ }
23+
24+ #[ must_use]
25+ pub fn part2 ( & self ) -> u64 {
26+ self . invalid_id_sum ( |repeats| repeats > 1 )
27+ }
28+
29+ fn invalid_id_sum ( & self , repeat_filter : impl Fn ( u32 ) -> bool ) -> u64 {
2130 let mut total = 0 ;
31+ let mut streams = Vec :: new ( ) ;
32+
2233 for & [ start, end] in & self . input {
23- ' num_loop: for i in start..=end {
24- let num_digits = i. ilog10 ( ) + 1 ;
34+ let min_digits = start. ilog10 ( ) + 1 ;
35+ let max_digits = end. ilog10 ( ) + 1 ;
36+ for pattern_digits in 1 ..=max_digits / 2 {
37+ for digits in ( min_digits. next_multiple_of ( pattern_digits) ..=max_digits)
38+ . step_by ( pattern_digits as usize )
39+ {
40+ let repeats = digits / pattern_digits;
41+ if !repeat_filter ( repeats) {
42+ continue ;
43+ }
2544
26- if num_digits % 2 != 0 {
27- continue ;
45+ let pow10 = 10u64 . pow ( pattern_digits) ;
46+ let block = if digits == min_digits {
47+ start / 10u64 . pow ( min_digits - pattern_digits)
48+ } else {
49+ pow10 / 10
50+ } ;
51+
52+ streams. push (
53+ RepeatingIdStream {
54+ block,
55+ pow10,
56+ repeats,
57+ range_start : start,
58+ range_end : end,
59+ }
60+ . peekable ( ) ,
61+ )
2862 }
63+ }
2964
30- let pattern_digits = num_digits / 2 ;
31- let divisor = 10u64 . pow ( pattern_digits ) ;
32- let pattern = i % divisor ;
65+ let mut previous_min = None ;
66+ loop {
67+ let mut min = None ;
3368
34- let mut remaining = i;
35- while remaining > 0 {
36- let chunk = remaining % divisor;
37- if chunk != pattern {
38- continue ' num_loop;
69+ // Advance past previous_min (if any), find the next min, and remove any empy streams
70+ streams. retain_mut ( |s| {
71+ if s. peek ( ) . copied ( ) == previous_min {
72+ let _ = s. next ( ) ;
3973 }
40- remaining /= divisor;
41- }
4274
43- total += i;
75+ if let Some ( & next) = s. peek ( ) {
76+ if min. is_none_or ( |n| n > next) {
77+ min = Some ( next) ;
78+ }
79+ true
80+ } else {
81+ false
82+ }
83+ } ) ;
84+
85+ let Some ( min) = min else {
86+ break ;
87+ } ;
88+
89+ total += min;
90+ previous_min = Some ( min) ;
4491 }
4592 }
93+
4694 total
4795 }
96+ }
4897
49- #[ must_use]
50- pub fn part2 ( & self ) -> u64 {
51- let mut total = 0 ;
52- for & [ start, end] in & self . input {
53- for i in start..=end {
54- let num_digits = i. ilog10 ( ) + 1 ;
98+ #[ derive( Clone , Debug ) ]
99+ struct RepeatingIdStream {
100+ block : u64 ,
101+ pow10 : u64 ,
102+ repeats : u32 ,
103+ range_start : u64 ,
104+ range_end : u64 ,
105+ }
55106
56- ' pattern_loop: for pattern_digits in 1 ..=num_digits / 2 {
57- if num_digits % pattern_digits != 0 {
58- continue ;
59- }
60- let divisor = 10u64 . pow ( pattern_digits) ;
61- let pattern = i % divisor;
62-
63- let mut remaining = i;
64- while remaining > 0 {
65- let chunk = remaining % divisor;
66- if chunk != pattern {
67- continue ' pattern_loop;
68- }
69- remaining /= divisor;
70- }
107+ impl Iterator for RepeatingIdStream {
108+ type Item = u64 ;
71109
72- total += i;
73- break ;
74- }
110+ fn next ( & mut self ) -> Option < Self :: Item > {
111+ while self . block < self . pow10 {
112+ let mut n = 0 ;
113+ for _ in 0 ..self . repeats {
114+ n = n * self . pow10 + self . block ;
115+ }
116+ self . block += 1 ;
117+
118+ if n > self . range_end {
119+ // No more solutions in this stream
120+ self . block = self . pow10 ;
121+ return None ;
122+ }
123+ if n >= self . range_start {
124+ return Some ( n) ;
75125 }
76126 }
77- total
127+ None
78128 }
79129}
80130
0 commit comments