day9, part2

This commit is contained in:
Joe Ardent 2025-01-05 14:49:47 -08:00
parent 01b077fc5f
commit da74a98b8b

View file

@ -1,6 +1,12 @@
use std::{
collections::HashSet,
fmt::{Debug, Display, Write},
};
fn main() { fn main() {
let input = std::fs::read_to_string("input").unwrap(); let input = std::fs::read_to_string("input").unwrap();
println!("{}", pt1(&input)); println!("{}", pt1(&input));
println!("{}", pt2(&input));
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -10,7 +16,6 @@ enum Cell {
} }
fn pt1(input: &str) -> usize { fn pt1(input: &str) -> usize {
let mut next_id = 0;
let mut map = Vec::new(); let mut map = Vec::new();
let mut frees = Vec::new(); let mut frees = Vec::new();
for (i, c) in input.chars().enumerate() { for (i, c) in input.chars().enumerate() {
@ -21,11 +26,10 @@ fn pt1(input: &str) -> usize {
} }
}; };
if i % 2 == 0 { if i % 2 == 0 {
let cell = Cell::Block(next_id); let cell = Cell::Block(i / 2);
for _ in 0..n { for _ in 0..n {
map.push(cell); map.push(cell);
} }
next_id += 1;
} else { } else {
for _ in 0..n { for _ in 0..n {
frees.push(map.len()); frees.push(map.len());
@ -47,6 +51,100 @@ fn pt1(input: &str) -> usize {
map.swap(free, i); map.swap(free, i);
} }
map.iter()
.enumerate()
.map(|(i, &b)| match b {
Cell::Block(v) => i * v,
_ => 0,
})
.sum()
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
enum Block {
Free(FreeBlock),
// size, id
File(FileBlock),
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
struct FreeBlock {
size: usize,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
struct FileBlock {
size: usize,
id: usize,
}
impl Block {
fn is_free(&self) -> Option<usize> {
match self {
Block::Free(s) => Some(s.size),
_ => None,
}
}
fn size(&self) -> usize {
match self {
Block::Free(block) => block.size,
Block::File(block) => block.size,
}
}
fn set_size(&mut self, s: usize) {
match self {
Block::Free(block) => block.size = s,
Block::File(block) => block.size = s,
}
}
}
fn pt2(input: &str) -> usize {
let mut map = Vec::new();
for (i, c) in input.chars().enumerate() {
let n = match c.to_digit(10) {
Some(n) => n as usize,
_ => {
continue;
}
};
if i % 2 == 0 {
let cell = Block::File(FileBlock { size: n, id: i / 2 });
map.push(cell);
} else {
map.push(Block::Free(FreeBlock { size: n }));
}
}
let mut processed = HashSet::new();
let mut done = false;
while !done {
for i in (0..map.len()).rev() {
if i == 0 {
done = true;
}
match map[i] {
Block::Free(_) => {
continue;
}
Block::File(file) => {
if processed.contains(&file.id) {
continue;
}
processed.insert(file.id);
if move_file(&mut map, i) {
map = compact(&map);
break;
}
}
}
}
}
let map = render_map(&map);
//println!("{map:?}"); //println!("{map:?}");
map.iter() map.iter()
@ -58,14 +156,102 @@ fn pt1(input: &str) -> usize {
.sum() .sum()
} }
enum Block { fn move_file(map: &mut Vec<Block>, file_index: usize) -> bool {
Free(usize), let file_size = map[file_index].size();
// size, id for j in 0..file_index {
Block(usize, usize), if let Some(free_size) = map[j].is_free() {
if map[file_index].size() <= free_size {
map.swap(file_index, j);
let diff = free_size - file_size;
if diff > 0 {
map[file_index].set_size(file_size);
map.insert(j + 1, Block::Free(FreeBlock { size: diff }));
return true;
}
break;
}
}
}
false
} }
fn pt2(input: &str) -> usize { fn render_map(map: &[Block]) -> Vec<Cell> {
todo!() let mut out = Vec::new();
for block in map {
match block {
Block::Free(free) => {
for _ in 0..free.size {
out.push(Cell::Free);
}
}
Block::File(file) => {
for _ in 0..file.size {
out.push(Cell::Block(file.id));
}
}
}
}
out
}
impl Display for Block {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Block::Free(FreeBlock { size: s }) => {
let out = (0..*s).fold(String::new(), |mut out, _| {
let _ = write!(out, ".");
out
});
write!(f, "{out}")
}
Block::File(FileBlock { size: sz, id }) => {
let out = (0..*sz).fold(String::new(), |mut out, _| {
if out.is_empty() {
let _ = write!(out, "{id}");
} else {
let _ = write!(out, "|{id}");
}
out
});
write!(f, "{out}")
}
}
}
}
impl Debug for Block {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Block::Free(s) => write!(f, "free: {}", s.size),
Block::File(b) => write!(f, "{}: {}", b.id, b.size),
}
}
}
fn compact(v: &[Block]) -> Vec<Block> {
let mut out = Vec::new();
let mut i = 0;
while i < v.len() {
match v[i] {
Block::File(file) => out.push(Block::File(file)),
Block::Free(free) => {
let mut total = free.size;
while let Some(next_free_size) = v.get(i + 1).and_then(|b| b.is_free()) {
total += next_free_size;
i += 1;
}
if total > 0 {
out.push(Block::Free(FreeBlock { size: total }));
}
}
}
i += 1;
}
out
} }
#[cfg(test)] #[cfg(test)]
@ -79,4 +265,9 @@ mod test {
let v = pt1(INPUT); let v = pt1(INPUT);
assert_eq!(v, 1928); assert_eq!(v, 1928);
} }
#[test]
fn p2() {
let v = pt2(INPUT);
assert_eq!(v, 2858);
}
} }