From 0000012098e30e81ce1ea84ba9aaf4cadb31a024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Jane=C5=BEi=C4=8D?= Date: Mon, 9 Dec 2024 20:09:35 +0100 Subject: [PATCH] solution: day 9 --- data/examples/09.txt | 1 + src/bin/09.rs | 148 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 data/examples/09.txt create mode 100644 src/bin/09.rs diff --git a/data/examples/09.txt b/data/examples/09.txt new file mode 100644 index 000000000..f96c390 --- /dev/null +++ b/data/examples/09.txt @@ -0,0 +1 @@ +2333133121414131402 diff --git a/src/bin/09.rs b/src/bin/09.rs new file mode 100644 index 000000000..5a252be --- /dev/null +++ b/src/bin/09.rs @@ -0,0 +1,148 @@ +use std::ops::Range; + +use itertools::Itertools; + +fn map_disk(input: &str) -> Vec> { + let disk_map = input.chars().filter_map(|x| x.to_digit(10)).collect_vec(); + + let mut disk = Vec::with_capacity(disk_map.len() * 10); + for (i, n) in disk_map.iter().copied().enumerate() { + let id = if i % 2 == 0 { Some(i / 2) } else { None }; + for _ in 0..n { + disk.push(id); + } + } + + disk +} + +fn disk_checksum(disk: &[Option]) -> usize { + disk.iter() + .enumerate() + .filter(|x| x.1.is_some()) + .map(|(i, x)| i * x.unwrap()) + .sum() +} + +pub fn part_one(input: &str) -> Option { + let mut disk = map_disk(input); + + let mut left_ptr = 0; + let mut right_ptr = disk.len() - 1; + + while left_ptr < right_ptr { + if disk[left_ptr].is_some() { + left_ptr += 1; + continue; + } + if disk[right_ptr].is_none() { + right_ptr -= 1; + continue; + } + disk.swap(left_ptr, right_ptr); + left_ptr += 1; + right_ptr -= 1; + } + + disk_checksum(&disk).into() +} + +fn next_move_candidate(disk: &[Option], mut start: usize) -> Option> { + while start > 0 && disk[start].is_none() { + start -= 1; + } + + if start == 0 && disk[start].is_none() { + return None; + } + + let mut end = start; + + while end > 0 + && disk + .get(end) + .copied() + .flatten() + .filter(|&x| Some(x) == disk[start]) + .is_some() + { + end -= 1; + } + + Some(end + 1..start + 1) +} + +fn find_empty_space( + disk: &[Option], + size: usize, + index_limit: usize, +) -> Option> { + let mut i = 0; + + loop { + while i < index_limit && disk[i].is_some() { + i += 1; + } + if i == index_limit { + break; + } + let mut j = i; + while j < index_limit && disk[j].is_none() { + j += 1; + } + if j - i >= size { + return Some(i..i + size); + } + i = j + } + + None +} + +pub fn part_two(input: &str) -> Option { + let mut disk = map_disk(input); + + let mut n = disk.len() - 1; + + while n > 0 { + let c = next_move_candidate(&disk, n); + if c.is_none() { + break; + } + let c = c.unwrap(); + if c.start == 0 { + break; + } + n = c.start - 1; + + let t = find_empty_space(&disk, c.len(), c.start); + if t.is_none() { + continue; + } + let t = t.unwrap(); + c.zip(t).map(|(cc, tt)| disk.swap(cc, tt)).count(); + } + + disk_checksum(&disk).into() +} + +aoc::solution!(9); + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_part_one() { + assert_eq!( + part_one(&aoc::template::read_file("examples", 9)), + Some(1928) + ); + } + #[test] + fn test_part_two() { + assert_eq!( + part_two(&aoc::template::read_file("examples", 9)), + Some(2858) + ); + } +}