diff --git a/README.md b/README.md index 9110b47..72ec3bd 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,10 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www. | [Day 5](./src/bin/05.rs) | `344.6µs` | `323.6µs` | | [Day 6](./src/bin/06.rs) | `488.0µs` | `119.9ms` | | [Day 7](./src/bin/07.rs) | `80.3µs` | `113.7µs` | -| [Day 8](./src/bin/08.rs) | `9.9µs` | `12.2µs` | +| [Day 8](./src/bin/08.rs) | `10.2µs` | `12.4µs` | +| [Day 9](./src/bin/09.rs) | `2.9ms` | `49.1ms` | -**Total: 123.92ms** +**Total: 175.92ms** --- diff --git a/data/examples/09.txt b/data/examples/09.txt new file mode 100644 index 0000000..5ff5aae --- /dev/null +++ b/data/examples/09.txt @@ -0,0 +1 @@ +2333133121414131402 \ No newline at end of file diff --git a/src/bin/09.rs b/src/bin/09.rs new file mode 100644 index 0000000..ee44428 --- /dev/null +++ b/src/bin/09.rs @@ -0,0 +1,132 @@ +use std::ops::Range; +use itertools::Itertools; + +advent_of_code::solution!(9); + +#[derive(Debug)] +struct DiskMap { + data: Vec +} + +impl DiskMap> { + fn parse(input: &str) -> DiskMap> { + let data = (&input.chars().chunks(2)).into_iter() + .enumerate() + .flat_map(|(id_number, mut chunk)| { + let Some(Some(file_size)) = chunk.next().map(|char| char.to_digit(10)) else { return Vec::new() }; + let mut file = vec![Some(id_number); file_size as usize]; + if let Some(Some(free_space)) = chunk.next().map(|char| char.to_digit(10)) { + file.append(&mut vec![None; free_space as usize]); + file + } else { + file + } + }) + .collect(); + DiskMap { + data + } + } + + fn checksum(&self) -> u64 { + let len = self.data.len(); + let mut sum = 0; + let (mut head, mut tail) = (1, len); + while head < tail { + let mut value = None; + if let Some(val) = self.data[head] { + value = Some(val); + } else { + while head < tail { + tail -= 1; + if let Some(val) = self.data[tail] { + value = Some(val); + break; + }; + } + } + let Some(value) = value else { break }; + sum += head * value; + head += 1; + } + sum as u64 + } +} + +#[derive(Default, Clone, Debug)] +struct Interval { + id: u64, + interval: Range, +} + +impl DiskMap { + fn parse_intervals(input: &str) -> DiskMap { + let mut last_index = 0; + let data = (&input.chars().chunks(2)).into_iter() + .enumerate() + .map(|(id_number, mut chunk)| { + let Some(Some(file_size)) = chunk.next().map(|char| char.to_digit(10)) else { return Interval::default() }; + let file = Interval { + id: id_number as u64, + interval: last_index..(last_index + file_size) + }; + last_index = file.interval.end; + if let Some(Some(free_space)) = chunk.next().map(|char| char.to_digit(10)) { + last_index += free_space; + } + file + }) + .collect_vec(); + DiskMap { + data + } + } + + fn checksum(&self) -> u64 { + let mut data = self.data.clone(); + for index in (1..data.len()).rev() { + let interval = &self.data[index]; + let actual_index = data.iter().rposition(|x| x.id == interval.id).unwrap(); + let interval_size = interval.interval.end - interval.interval.start; + let Some((new_index, start_index, _)) = (0..actual_index) + .map(|index| (index, &data[index].interval, &data[index + 1].interval)) + .map(|(index, x, y)| (index, x.end, y.start - x.end)) + .find(|(_, _, size)| size >= &(interval_size)) else { continue }; + let interval = Interval { + interval: start_index..(start_index + interval_size), + ..*interval + }; + data.remove(actual_index); + data.insert(new_index + 1, interval); + } + data.iter() + .map(|Interval { id, interval }| interval.clone().map(|x| id * (x as u64)).sum::()) + .sum() + } +} + +pub fn part_one(input: &str) -> Option { + Some(DiskMap::parse(input).checksum()) +} + +pub fn part_two(input: &str) -> Option { + let disk_map = DiskMap::parse_intervals(input); + Some(disk_map.checksum()) +} + +#[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(1928)); + } + + #[test] + fn test_part_two() { + let result = part_two(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(2858)); + } +}