mirror of
https://github.com/RussellChamp/advent-of-code-2025-cursor.git
synced 2026-10-27 23:52:34 +00:00
Refactor days 1-2, optimize day 3 part 1 with suffix max
This commit is contained in:
1 parent
0b5c8fa10f
commit
d650dce61b
6 files changed
+133
-149
No files matched your search
+35
-68
@@ -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)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user