diff --git a/2025/rust/day-05/Cargo.lock b/2025/rust/day-05/Cargo.lock new file mode 100644 index 0000000..992643d --- /dev/null +++ b/2025/rust/day-05/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "day-05" +version = "0.1.0" diff --git a/2025/rust/day-05/Cargo.toml b/2025/rust/day-05/Cargo.toml new file mode 100644 index 0000000..0c3df26 --- /dev/null +++ b/2025/rust/day-05/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "day-05" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/2025/rust/day-05/src/main.rs b/2025/rust/day-05/src/main.rs new file mode 100644 index 0000000..763c0db --- /dev/null +++ b/2025/rust/day-05/src/main.rs @@ -0,0 +1,124 @@ +use std::fs; + +struct Range { + start: u64, + end: u64, +} + +impl Range { + fn new(start: u64, end: u64) -> Self { + Range { start, end } + } + + fn contains(&self, num: u64) -> bool { + num >= self.start && num <= self.end + } + + fn overlaps(&self, other: &Range) -> bool { + self.contains(other.start) || self.contains(other.end) + } + + fn merge_with(&mut self, overlap: &Range) { + if overlap.start < self.start { + self.start = overlap.start; + } + if overlap.end > self.end { + self.end = overlap.end; + } + } + + fn length(&self) -> u64 { + self.end - self.start + 1 + } +} + +fn main() { + let (ranges, available_ids) = parse_input(&fs::read_to_string("../../inputs/05.txt").unwrap()); + let ranges = merge_overlapping_ranges(ranges); + + println!( + "Number of available IDs in ranges: {}", + count_available_ids_in_ranges(available_ids, &ranges) + ); + println!("Number of IDs in ranges: {}", count_ids_in_ranges(&ranges)); +} + +fn parse_input(contents: &str) -> (Vec, Vec) { + let (ranges, available_ids) = contents.trim().split_once("\n\n").unwrap(); + + let ranges: Vec = ranges + .lines() + .map(|line| line.split_once("-").unwrap()) + .map(|(start, end)| Range::new(start.parse().unwrap(), end.parse().unwrap())) + .collect(); + let available_ids: Vec = available_ids + .lines() + .map(|line| line.parse().unwrap()) + .collect(); + + (ranges, available_ids) +} + +fn merge_overlapping_ranges(mut ranges: Vec) -> Vec { + ranges.sort_by_key(|range| range.start); + + let mut compressed_ranges = vec![ranges.remove(0)]; + + for range in ranges { + let previous = compressed_ranges.last_mut().unwrap(); + + if previous.overlaps(&range) { + previous.merge_with(&range); + } else { + compressed_ranges.push(range); + } + } + + compressed_ranges +} + +fn count_available_ids_in_ranges(available_ids: Vec, ranges: &[Range]) -> usize { + available_ids + .iter() + .filter(|id| ranges.iter().any(|range| range.contains(**id))) + .count() +} + +fn count_ids_in_ranges(ranges: &[Range]) -> u64 { + ranges.iter().map(|range| range.length()).sum() +} + +#[cfg(test)] +mod tests { + use super::*; + + const TEST_INPUT: &str = " +3-5 +10-14 +16-20 +12-18 + +1 +5 +8 +11 +17 +32 +"; + + #[test] + fn test_part1() { + let (ranges, available_ids) = parse_input(TEST_INPUT); + let ranges = merge_overlapping_ranges(ranges); + + assert_eq!(count_available_ids_in_ranges(available_ids, &ranges), 3); + } + + #[test] + fn test_part2() { + let (ranges, _) = parse_input(TEST_INPUT); + let ranges = merge_overlapping_ranges(merge_overlapping_ranges(ranges)); + + assert_eq!(count_ids_in_ranges(&ranges), 14); + } +} diff --git a/flake.lock b/flake.lock index ec6ecaf..675648d 100644 --- a/flake.lock +++ b/flake.lock @@ -3,10 +3,10 @@ "inputs": { "flake": false, "locked": { - "lastModified": 1764840758, - "narHash": "sha256-GTN8SBnhvv6t2oDS1H85xcYAhafy8mpUQWSrCErhtgw=", + "lastModified": 1764926544, + "narHash": "sha256-xIkgV9KrBel6Qwy673iMmmggFGZ9Zz93Hd/lGhRyHRM=", "ref": "refs/heads/main", - "rev": "415a59297c64d0448d22975ca5ad3d8ef064c9f0", + "rev": "27de1eaccb499f25dca8f3505b4c4f42a8e35514", "shallow": true, "type": "git", "url": "ssh://git@github.com/SebastianStork/advent-of-code-inputs.git"