solution: day 9

This commit is contained in:
Matej Janezic 2024-12-09 20:09:35 +01:00
parent 0000011041
commit 0000012098
Signed by: janezicmatej
GPG Key ID: 4298E230ED37B2C0
2 changed files with 149 additions and 0 deletions

1
data/examples/09.txt Normal file
View File

@ -0,0 +1 @@
2333133121414131402

148
src/bin/09.rs Normal file
View File

@ -0,0 +1,148 @@
use std::ops::Range;
use itertools::Itertools;
fn map_disk(input: &str) -> Vec<Option<usize>> {
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>]) -> usize {
disk.iter()
.enumerate()
.filter(|x| x.1.is_some())
.map(|(i, x)| i * x.unwrap())
.sum()
}
pub fn part_one(input: &str) -> Option<usize> {
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<usize>], mut start: usize) -> Option<Range<usize>> {
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<usize>],
size: usize,
index_limit: usize,
) -> Option<Range<usize>> {
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<usize> {
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)
);
}
}