feat: Day 5 Completed
All checks were successful
Continuous integration / Check (push) Successful in 38s
Continuous integration / Test Suite (push) Successful in 43s
Continuous integration / Rustfmt (push) Successful in 29s
Continuous integration / Clippy (push) Successful in 40s
Continuous integration / build (push) Successful in 41s

This commit is contained in:
2025-12-07 22:09:42 +00:00
parent 16b0f1960a
commit 6806e5dd19
5 changed files with 1339 additions and 10 deletions

View File

@@ -16,9 +16,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
Box::new(day02::Day02 {}),
Box::new(day03::Day03 {}),
Box::new(day04::Day04 {}),
// Box::new(day05::Day05 {}),
// Box::new(day06::Day06 {}),
// Box::new(day07::Day07 {}),
Box::new(day05::Day05 {}),
Box::new(day06::Day06 {}),
Box::new(day07::Day07 {}),
// Box::new(day08::Day08 {}),
// Box::new(day09::Day09 {}),
// Box::new(day10::Day10 {}),

View File

@@ -5,16 +5,62 @@ pub struct Day05 {}
impl Solution for Day05 {
fn part1(
&self,
_input: &mut Vec<String>,
input: &mut Vec<String>,
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> {
Ok(Box::new("Ready"))
let sep_idx = input.iter().position(|l| l.trim().is_empty());
let (range_lines, id_lines) = match sep_idx {
Some(i) => {
let ranges = &input[..i];
let ids = &input[i + 1..];
(ranges.to_vec(), ids.to_vec())
}
None => {
// if no blank line, assume all ranges then no ids
(input.clone(), Vec::new())
}
};
let ranges = self.parse_ranges(&range_lines);
let merged = self.merge_ranges(ranges);
let mut fresh_count: u64 = 0;
for line in id_lines {
let s = line.trim();
if s.is_empty() {
continue;
}
let id: u64 = s.parse().expect("failed to parse ingredient id");
if self.is_fresh(&merged, id) {
fresh_count += 1;
}
}
Ok(Box::new(fresh_count))
}
fn part2(
&self,
_input: &mut Vec<String>,
input: &mut Vec<String>,
) -> Result<Box<dyn std::fmt::Display>, Box<dyn std::error::Error>> {
Ok(Box::new("Ready"))
let sep_idx = input.iter().position(|l| l.trim().is_empty());
let (range_lines, _) = match sep_idx {
Some(i) => {
let ranges = &input[..i];
let ids = &input[i + 1..];
(ranges.to_vec(), ids.to_vec())
}
None => {
// if no blank line, assume all ranges then no ids
(input.clone(), Vec::new())
}
};
let ranges = self.parse_ranges(&range_lines);
let merged = self.merge_ranges(ranges);
let fresh_set = merged.iter().map(|(s, e)| e - s + 1).sum::<u64>();
Ok(Box::new(fresh_set))
}
fn get_day(&self) -> u8 {
@@ -22,7 +68,81 @@ impl Solution for Day05 {
}
}
impl Day05 {}
impl Day05 {
fn parse_ranges(&self, lines: &[String]) -> Vec<(u64, u64)> {
let mut ranges: Vec<(u64, u64)> = Vec::new();
for line in lines {
let s = line.trim();
if s.is_empty() {
continue;
}
// Expect format "start-end"
if let Some(idx) = s.find('-') {
let a = &s[..idx];
let b = &s[idx + 1..];
let start: u64 = a.parse().expect("failed to parse range start");
let end: u64 = b.parse().expect("failed to parse range end");
// Ensure start <= end (input likely correct, but be defensive)
if start <= end {
ranges.push((start, end));
} else {
ranges.push((end, start));
}
} else {
panic!("range line without '-' found: {}", s);
}
}
ranges
}
/// Merge overlapping/adjacent ranges so membership tests are faster.
/// Ranges are inclusive.
fn merge_ranges(&self, mut ranges: Vec<(u64, u64)>) -> Vec<(u64, u64)> {
if ranges.is_empty() {
return ranges;
}
// sort by start
ranges.sort_by_key(|r| r.0);
let mut merged: Vec<(u64, u64)> = Vec::new();
let mut cur = ranges[0];
for &(s, e) in &ranges[1..] {
if s <= cur.1.saturating_add(1) {
// overlap or adjacent: extend
cur.1 = cur.1.max(e);
} else {
merged.push(cur);
cur = (s, e);
}
}
merged.push(cur);
merged
}
/// Check whether `x` is inside any merged ranges using binary search.
fn is_fresh(&self, merged: &[(u64, u64)], x: u64) -> bool {
// find the first range with start > x, then check previous range (if any)
// equivalent to upper_bound on start
let idx = match merged.binary_search_by(|&(s, _)| {
if s > x {
std::cmp::Ordering::Greater
} else if s <= x {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Equal
}
}) {
// binary_search_by will never return Equal in this comparator (we used <= vs >),
// but handle all cases robustly:
Ok(i) => i,
Err(i) => i,
};
if idx == 0 {
return false;
}
let (s, e) = merged[idx - 1];
x >= s && x <= e
}
}
/// Test from puzzle input
#[cfg(test)]
@@ -44,7 +164,7 @@ mod test {
.unwrap()
.to_string();
assert_eq!(answer, "Ready");
assert_eq!(answer, "3");
}
#[test]
@@ -61,6 +181,6 @@ mod test {
.unwrap()
.to_string();
assert_eq!(answer, "Ready");
assert_eq!(answer, "14");
}
}