Day 9
This commit is contained in:
parent
cc04168468
commit
ec647002cd
137
src/day9.rs
Normal file
137
src/day9.rs
Normal file
@ -0,0 +1,137 @@
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufReader, Read},
|
||||
iter,
|
||||
};
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Block {
|
||||
Free,
|
||||
File { id: usize },
|
||||
}
|
||||
|
||||
impl Block {
|
||||
fn is_free(&self) -> bool {
|
||||
matches!(self, Self::Free)
|
||||
}
|
||||
|
||||
fn file_id(&self) -> usize {
|
||||
match self {
|
||||
Self::File { id } => *id,
|
||||
Self::Free => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_data() -> Vec<Block> {
|
||||
let mut result = vec![];
|
||||
let reader = BufReader::new(File::open("input.txt").unwrap());
|
||||
for (i, b) in reader.bytes().enumerate() {
|
||||
let num = b.unwrap() - b'0';
|
||||
let record = if i % 2 == 0 {
|
||||
Block::File { id: i / 2 }
|
||||
} else {
|
||||
Block::Free
|
||||
};
|
||||
result.extend(iter::repeat(record).take(num as usize));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct LBlock {
|
||||
start: usize,
|
||||
end: usize,
|
||||
}
|
||||
|
||||
impl LBlock {
|
||||
fn len(&self) -> usize {
|
||||
self.end - self.start
|
||||
}
|
||||
}
|
||||
|
||||
fn checksum(mem: &[Block]) -> usize {
|
||||
mem.iter()
|
||||
.enumerate()
|
||||
.filter(|(_i, block)| !block.is_free())
|
||||
.map(|(i, block)| i * block.file_id())
|
||||
.sum()
|
||||
}
|
||||
|
||||
pub fn task1() {
|
||||
let mut data = get_data();
|
||||
let mut lo = 0;
|
||||
let mut ro = data.len() - 1;
|
||||
|
||||
while lo < ro {
|
||||
while lo < data.len() && !data[lo].is_free() {
|
||||
lo += 1;
|
||||
}
|
||||
|
||||
while ro > lo && data[ro].is_free() {
|
||||
ro -= 1;
|
||||
}
|
||||
|
||||
data.swap(lo, ro);
|
||||
lo += 1;
|
||||
ro = ro.saturating_sub(1);
|
||||
}
|
||||
|
||||
println!("{}", checksum(&data));
|
||||
}
|
||||
|
||||
pub fn task2() {
|
||||
let mut data = get_data();
|
||||
let mut free_mem = vec![];
|
||||
let mut files = vec![];
|
||||
for (is_free, mut chunk) in &data
|
||||
.iter()
|
||||
.enumerate()
|
||||
.chunk_by(|(_i, block)| block.is_free())
|
||||
{
|
||||
if is_free {
|
||||
let (fbi, fb) = chunk.next().unwrap();
|
||||
let (last_block_index, _last_block) = chunk.last().unwrap_or((fbi, fb));
|
||||
let c_block = LBlock {
|
||||
start: fbi,
|
||||
end: last_block_index + 1,
|
||||
};
|
||||
free_mem.push(c_block);
|
||||
} else {
|
||||
for (_file_id, mut chunk) in &chunk.chunk_by(|(_i, block)| block.file_id()) {
|
||||
let (fbi, fb) = chunk.next().unwrap();
|
||||
let (lbi, _last_block) = chunk.last().unwrap_or((fbi, fb));
|
||||
let c_block = LBlock {
|
||||
start: fbi,
|
||||
end: lbi + 1,
|
||||
};
|
||||
files.push(c_block);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
for file in files.into_iter().rev() {
|
||||
let size = file.len();
|
||||
let Some((free_index, _)) = free_mem
|
||||
.iter()
|
||||
.find_position(|block| block.len() >= size && block.start < file.start)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let free_mem_block = &mut free_mem[free_index];
|
||||
|
||||
for (file_index, free_index) in
|
||||
(file.start..file.end).zip(free_mem_block.start..free_mem_block.end)
|
||||
{
|
||||
data.swap(file_index, free_index);
|
||||
}
|
||||
|
||||
free_mem_block.start += file.len();
|
||||
}
|
||||
|
||||
println!("{}", checksum(&data));
|
||||
}
|
@ -6,6 +6,7 @@ mod day5;
|
||||
mod day6;
|
||||
mod day7;
|
||||
mod day8;
|
||||
mod day9;
|
||||
|
||||
use std::{
|
||||
fs::File,
|
||||
@ -23,6 +24,6 @@ fn parse_line(line: &str, pattern: char) -> impl Iterator<Item = i32> + '_ {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
day8::task1();
|
||||
day8::task2();
|
||||
day9::task1();
|
||||
day9::task2();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user