130 lines
3.4 KiB
Rust
130 lines
3.4 KiB
Rust
pub fn process_part1(input: &str) -> u64 {
|
|
let mut ids = Vec::new();
|
|
for (file_id, chunk) in input.trim_end().as_bytes().chunks(2).enumerate() {
|
|
let byte = chunk[0];
|
|
for _ in 0..(byte - 48) {
|
|
ids.push(file_id.to_string());
|
|
}
|
|
if let Some(&byte) = chunk.get(1) {
|
|
for _ in 0..(byte - 48) {
|
|
ids.push(".".into());
|
|
}
|
|
}
|
|
}
|
|
let mut ordered = Vec::new();
|
|
while !ids.is_empty() {
|
|
let id = ids.remove(0);
|
|
if id == "." {
|
|
while let Some(id) = ids.pop() {
|
|
if id != "." {
|
|
ordered.push(id);
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
ordered.push(id);
|
|
}
|
|
}
|
|
let mut res = 0;
|
|
for (multiplier, id) in ordered.iter().enumerate() {
|
|
res += multiplier * id.parse::<usize>().unwrap();
|
|
}
|
|
res as u64
|
|
}
|
|
|
|
pub fn process_part2(input: &str) -> u64 {
|
|
let mut ids = Vec::new();
|
|
for (file_id, chunk) in input.trim_end().as_bytes().chunks(2).enumerate() {
|
|
let byte = chunk[0];
|
|
ids.push((file_id.to_string(), byte - 48));
|
|
if let Some(&byte) = chunk.get(1) {
|
|
ids.push((".".into(), byte - 48));
|
|
}
|
|
}
|
|
let mut from_idx = ids.len() - 1;
|
|
loop {
|
|
if from_idx == 0 {
|
|
break;
|
|
}
|
|
let (id, size) = ids[from_idx].clone();
|
|
if id == *"." {
|
|
from_idx -= 1;
|
|
continue;
|
|
}
|
|
let to_idx = if let Some(idx) = ids.iter().position(|id| id.1 >= size && id.0 == ".") {
|
|
idx
|
|
} else {
|
|
from_idx -= 1;
|
|
continue;
|
|
};
|
|
if from_idx < to_idx {
|
|
from_idx -= 1;
|
|
continue;
|
|
}
|
|
let free_space = ids[to_idx].1;
|
|
match size.cmp(&free_space) {
|
|
std::cmp::Ordering::Less => {
|
|
let remaining_free_space = free_space - size;
|
|
ids[to_idx].1 = remaining_free_space;
|
|
ids[from_idx] = (".".to_string(), size);
|
|
ids.insert(to_idx, (id.clone(), size));
|
|
from_idx -= 1;
|
|
}
|
|
std::cmp::Ordering::Equal => {
|
|
ids[to_idx] = (id.clone(), size);
|
|
ids[from_idx] = (".".to_string(), size);
|
|
from_idx -= 1;
|
|
}
|
|
std::cmp::Ordering::Greater => {
|
|
from_idx -= 1;
|
|
}
|
|
}
|
|
}
|
|
let mut res = 0;
|
|
let mut multiplier = 0;
|
|
for (id, size) in ids.into_iter() {
|
|
if id == *"." {
|
|
multiplier += size as usize;
|
|
continue;
|
|
}
|
|
for _idx in 0..size as usize {
|
|
res += multiplier * id.parse::<usize>().unwrap();
|
|
multiplier += 1;
|
|
}
|
|
}
|
|
res as u64
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
const INPUT_1: &str = "12345";
|
|
const INPUT_2: &str = "2333133121414131402";
|
|
const INPUT_3: &str = "23331331214141314020202";
|
|
|
|
#[test]
|
|
fn part1_simple() {
|
|
let result = process_part1(INPUT_1);
|
|
assert_eq!(result, 60);
|
|
}
|
|
|
|
#[test]
|
|
fn part1_complex_1() {
|
|
let result = process_part1(INPUT_2);
|
|
assert_eq!(result, 1928);
|
|
}
|
|
|
|
#[test]
|
|
fn part1_complex_2() {
|
|
let result = process_part1(INPUT_3);
|
|
assert_eq!(result, 2842);
|
|
}
|
|
|
|
#[test]
|
|
fn part2() {
|
|
let result = process_part2(INPUT_2);
|
|
assert_eq!(result, 2858)
|
|
}
|
|
}
|