mirror of
https://github.com/RussellChamp/advent-of-code-2025-cursor.git
synced 2026-10-27 23:52:34 +00:00
Solve Day 5: Cafeteria (fresh ingredient ranges)
This commit is contained in:
1 parent
6f492ae3a1
commit
f95ecc2fe1
3 files changed
+124
-1
No files matched your search
@@ -15,8 +15,9 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
|
|||||||
| [Day 2](./src/bin/02.rs) | `1.1ms` | `3.8ms` |
|
| [Day 2](./src/bin/02.rs) | `1.1ms` | `3.8ms` |
|
||||||
| [Day 3](./src/bin/03.rs) | `85.1µs` | `121.6µs` |
|
| [Day 3](./src/bin/03.rs) | `85.1µs` | `121.6µs` |
|
||||||
| [Day 4](./src/bin/04.rs) | `244.2µs` | `4.1ms` |
|
| [Day 4](./src/bin/04.rs) | `244.2µs` | `4.1ms` |
|
||||||
|
| [Day 5](./src/bin/05.rs) | `196.7µs` | `66.3µs` |
|
||||||
|
|
||||||
**Total: 9.68ms**
|
**Total: 9.94ms**
|
||||||
<!--- benchmarking table --->
|
<!--- benchmarking table --->
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
3-5
|
||||||
|
10-14
|
||||||
|
16-20
|
||||||
|
12-18
|
||||||
|
|
||||||
|
1
|
||||||
|
5
|
||||||
|
8
|
||||||
|
11
|
||||||
|
17
|
||||||
|
32
|
||||||
|
|
||||||
+110
@@ -0,0 +1,110 @@
|
|||||||
|
advent_of_code::solution!(5);
|
||||||
|
|
||||||
|
/// A range of fresh ingredient IDs (inclusive)
|
||||||
|
struct FreshRange {
|
||||||
|
start: u64,
|
||||||
|
end: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FreshRange {
|
||||||
|
fn contains(&self, id: u64) -> bool {
|
||||||
|
id >= self.start && id <= self.end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse the input into fresh ranges and available IDs
|
||||||
|
fn parse_input(input: &str) -> (Vec<FreshRange>, Vec<u64>) {
|
||||||
|
// Normalize line endings and split on blank line
|
||||||
|
let normalized = input.replace("\r\n", "\n");
|
||||||
|
let mut sections = normalized.split("\n\n");
|
||||||
|
|
||||||
|
// Parse fresh ingredient ID ranges
|
||||||
|
let ranges_section = sections.next().unwrap_or("");
|
||||||
|
let ranges: Vec<FreshRange> = ranges_section
|
||||||
|
.lines()
|
||||||
|
.filter(|line| !line.trim().is_empty())
|
||||||
|
.map(|line| {
|
||||||
|
let mut parts = line.split('-');
|
||||||
|
let start: u64 = parts.next().unwrap().parse().unwrap();
|
||||||
|
let end: u64 = parts.next().unwrap().parse().unwrap();
|
||||||
|
FreshRange { start, end }
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Parse available ingredient IDs
|
||||||
|
let ids_section = sections.next().unwrap_or("");
|
||||||
|
let ids: Vec<u64> = ids_section
|
||||||
|
.lines()
|
||||||
|
.filter(|line| !line.trim().is_empty())
|
||||||
|
.map(|line| line.trim().parse().unwrap())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
(ranges, ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if an ingredient ID is fresh (falls within any range)
|
||||||
|
fn is_fresh(id: u64, ranges: &[FreshRange]) -> bool {
|
||||||
|
ranges.iter().any(|range| range.contains(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part_one(input: &str) -> Option<u64> {
|
||||||
|
let (ranges, ids) = parse_input(input);
|
||||||
|
|
||||||
|
let fresh_count = ids.iter().filter(|&&id| is_fresh(id, &ranges)).count();
|
||||||
|
|
||||||
|
Some(fresh_count as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Merge overlapping ranges and count total unique IDs
|
||||||
|
fn count_unique_fresh_ids(mut ranges: Vec<FreshRange>) -> u64 {
|
||||||
|
if ranges.is_empty() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort ranges by start
|
||||||
|
ranges.sort_by_key(|r| r.start);
|
||||||
|
|
||||||
|
// Merge overlapping ranges
|
||||||
|
let mut merged: Vec<FreshRange> = Vec::new();
|
||||||
|
merged.push(FreshRange {
|
||||||
|
start: ranges[0].start,
|
||||||
|
end: ranges[0].end,
|
||||||
|
});
|
||||||
|
|
||||||
|
for range in ranges.into_iter().skip(1) {
|
||||||
|
let last = merged.last_mut().unwrap();
|
||||||
|
// Check if ranges overlap or are adjacent
|
||||||
|
if range.start <= last.end + 1 {
|
||||||
|
// Extend the current range if needed
|
||||||
|
last.end = last.end.max(range.end);
|
||||||
|
} else {
|
||||||
|
// No overlap, start a new range
|
||||||
|
merged.push(range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count total unique IDs across all merged ranges
|
||||||
|
merged.iter().map(|r| r.end - r.start + 1).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part_two(input: &str) -> Option<u64> {
|
||||||
|
let (ranges, _) = parse_input(input);
|
||||||
|
Some(count_unique_fresh_ids(ranges))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_part_one() {
|
||||||
|
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
|
||||||
|
assert_eq!(result, Some(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_part_two() {
|
||||||
|
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
|
||||||
|
assert_eq!(result, Some(14));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user