day9, part2
This commit is contained in:
parent
01b077fc5f
commit
da74a98b8b
1 changed files with 200 additions and 9 deletions
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue