Refactor days 1-2, optimize day 3 part 1 with suffix max

This commit is contained in:
Russell Champoux committed 2025-12-04 17:34:11 -05:00
1 parent 0b5c8fa10f
commit d650dce61b
6 files changed
+133 -149

No files matched your search

+35 -68
View File
@@ -1,41 +1,22 @@
use itertools::Itertools;
advent_of_code::solution!(2);
/// Parse a range string like "11-22" into (start, end)
fn parse_range(s: &str) -> Option<(u64, u64)> {
s.trim()
.split('-')
.map(|x| x.parse::<u64>().ok())
.collect_tuple()
.and_then(|(a, b)| Some((a?, b?)))
}
/// Check if a number is "invalid" - made of a pattern repeated exactly twice
fn is_invalid_part1(n: u64) -> bool {
let s = n.to_string();
let len = s.len();
// Must have even length for pattern to repeat exactly twice
if len % 2 != 0 {
return false;
}
let half = len / 2;
s[..half] == s[half..]
}
pub fn part_one(input: &str) -> Option<u64> {
let mut sum = 0u64;
// Parse comma-separated ranges, handling potential whitespace/newlines
for part in input.split(',') {
let part = part.trim();
if part.is_empty() {
continue;
}
// Parse "start-end" range
let mut range_parts = part.split('-');
let start: u64 = range_parts.next()?.parse().ok()?;
let end: u64 = range_parts.next()?.parse().ok()?;
// Check each number in the range
for n in start..=end {
if is_invalid_part1(n) {
sum += n;
}
}
}
Some(sum)
len % 2 == 0 && s[..len / 2] == s[len / 2..]
}
/// Check if a number is "invalid" - made of a pattern repeated at least twice
@@ -44,50 +25,36 @@ fn is_invalid_part2(n: u64) -> bool {
let len = s.len();
// Try each possible pattern length (1 to len/2)
for pattern_len in 1..=len / 2 {
(1..=len / 2).any(|pattern_len| {
// Pattern can only work if it divides evenly
if len % pattern_len != 0 {
continue;
len % pattern_len == 0 && {
let pattern = &s[..pattern_len];
// Check if all chunks match the pattern
s.as_bytes()
.chunks(pattern_len)
.all(|chunk| chunk == pattern.as_bytes())
}
})
}
let pattern = &s[..pattern_len];
let mut is_match = true;
pub fn part_one(input: &str) -> Option<u64> {
let sum = input
.split(',')
.filter_map(|part| parse_range(part))
.flat_map(|(start, end)| start..=end)
.filter(|&n| is_invalid_part1(n))
.sum();
// Check if the entire string is made of this pattern repeated
for i in (pattern_len..len).step_by(pattern_len) {
if &s[i..i + pattern_len] != pattern {
is_match = false;
break;
}
}
if is_match {
return true;
}
}
false
Some(sum)
}
pub fn part_two(input: &str) -> Option<u64> {
let mut sum = 0u64;
for part in input.split(',') {
let part = part.trim();
if part.is_empty() {
continue;
}
let mut range_parts = part.split('-');
let start: u64 = range_parts.next()?.parse().ok()?;
let end: u64 = range_parts.next()?.parse().ok()?;
for n in start..=end {
if is_invalid_part2(n) {
sum += n;
}
}
}
let sum = input
.split(',')
.filter_map(|part| parse_range(part))
.flat_map(|(start, end)| start..=end)
.filter(|&n| is_invalid_part2(n))
.sum();
Some(sum)
}