Solve day 5

This commit is contained in:
2025-12-06 23:29:18 -05:00
parent 1311cb830b
commit 7a3463e8cc
5 changed files with 139 additions and 0 deletions

View File

@@ -36,6 +36,7 @@ Timings are given as: [lower-bound **best-estimate** upper-bound]
| 02 | [2.0386 ms **2.0483 ms** 2.0584 ms] | [2.0823 ms **2.0918 ms** 2.1015 ms] | | 02 | [2.0386 ms **2.0483 ms** 2.0584 ms] | [2.0823 ms **2.0918 ms** 2.1015 ms] |
| 03 | [45.711 µs **45.937 µs** 46.177 µs] | [267.18 µs **267.95 µs** 268.75 µs] | | 03 | [45.711 µs **45.937 µs** 46.177 µs] | [267.18 µs **267.95 µs** 268.75 µs] |
| 04 | [143.40 µs **144.00 µs** 144.73 µs] | [1.6165 ms **1.6258 ms** 1.6355 ms] | | 04 | [143.40 µs **144.00 µs** 144.73 µs] | [1.6165 ms **1.6258 ms** 1.6355 ms] |
| 05 | [187.25 µs **188.93 µs** 190.74 µs] | [63.809 µs **64.204 µs** 64.606 µs] |
## Profiling ## Profiling

11
src/day05/input/test1.txt Normal file
View File

@@ -0,0 +1,11 @@
3-5
10-14
16-20
12-18
1
5
8
11
17
32

125
src/day05/mod.rs Normal file
View File

@@ -0,0 +1,125 @@
use std::{fmt::Display, str::FromStr};
use color_eyre::{
Result,
eyre::{Error, eyre},
};
use tracing::{debug, instrument};
pub const INPUT: &str = include_str!("input/input.txt");
#[derive(Clone, Debug)]
struct FreshRange(pub std::ops::RangeInclusive<i64>);
impl FromStr for FreshRange {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parts = s.split('-');
let start = parts
.next()
.ok_or(eyre!("Invalid fresh range: no start"))?
.parse::<i64>()?;
let end = parts
.next()
.ok_or(eyre!("Invalid fresh range: no end"))?
.parse::<i64>()?;
if parts.next().is_some() {
return Err(eyre!("Invalid fresh range: too many parts"));
}
Ok(FreshRange(start..=end))
}
}
impl Display for FreshRange {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}-{}", self.0.start(), self.0.end())
}
}
#[instrument(skip(input))]
pub fn part1(input: &str) -> Result<usize> {
let mut processing_ranges = true;
let mut fresh_ranges = Vec::new();
let mut fresh_ingredients = 0;
for line in input.trim().lines() {
if line.is_empty() {
processing_ranges = false;
continue;
}
if processing_ranges {
let range = line.parse::<FreshRange>()?;
debug!(range = %range);
fresh_ranges.push(range);
} else {
let ingredient = line.parse::<i64>()?;
debug!(ingredient);
for range in &mut fresh_ranges {
if range.0.contains(&ingredient) {
fresh_ingredients += 1;
debug!(fresh_ingredients, "fresh!");
break;
}
}
}
}
Ok(fresh_ingredients)
}
#[instrument(skip(input))]
pub fn part2(input: &str) -> Result<usize> {
let mut fresh_ranges: Vec<Option<FreshRange>> = Vec::new();
for line in input.trim().lines() {
if line.is_empty() {
break;
}
let range = line.parse::<FreshRange>()?;
let mut overlap_range = range.clone();
debug!(range = %range);
for range_slot in fresh_ranges.iter_mut() {
if let Some(existing_range) = range_slot {
if overlap_range.0.end() < existing_range.0.start()
|| overlap_range.0.start() > existing_range.0.end()
{
continue;
}
let start = *overlap_range.0.start().min(existing_range.0.start());
let end = *overlap_range.0.end().max(existing_range.0.end());
if start <= end {
overlap_range = FreshRange(start..=end);
debug!(overlap_range = %overlap_range, existing_range = %existing_range, "merging existing range");
*range_slot = None; // this existing range is now completely merged with the current range
}
}
}
fresh_ranges.push(Some(overlap_range));
}
Ok(fresh_ranges
.iter()
.flatten()
.map(|r| (r.0.end() - r.0.start() + 1) as usize)
.sum())
}
#[cfg(test)]
mod tests {
use super::*;
use test_log::test;
const TEST_INPUT1: &str = include_str!("input/test1.txt");
#[test]
fn test_part1() {
assert_eq!(part1(TEST_INPUT1).unwrap(), 3);
}
#[test]
fn test_part2() {
assert_eq!(part2(TEST_INPUT1).unwrap(), 14);
}
#[test]
fn test_part2_triple_overlap() {
assert_eq!(part2("3-4\n2-5\n1-6").unwrap(), 6);
}
}

View File

@@ -9,6 +9,7 @@ macro_rules! all_days {
2 => day02, 2 => day02,
3 => day03, 3 => day03,
4 => day04, 4 => day04,
5 => day05,
} }
}; };
} }

View File

@@ -2,4 +2,5 @@ pub mod day01;
pub mod day02; pub mod day02;
pub mod day03; pub mod day03;
pub mod day04; pub mod day04;
pub mod day05;
pub mod days; pub mod days;