Adds day 9
This commit is contained in:
parent
bc0aa70ac3
commit
8c116cb59a
1
resources/input9.txt
Normal file
1
resources/input9.txt
Normal file
File diff suppressed because one or more lines are too long
149
src/days/day9.rs
Normal file
149
src/days/day9.rs
Normal file
@ -0,0 +1,149 @@
|
||||
use core::fmt;
|
||||
use std::path::Path;
|
||||
|
||||
use advent_derive::advent_day;
|
||||
|
||||
use crate::{error::AdventError, input::get_input};
|
||||
use super::*;
|
||||
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
enum Sector {
|
||||
Empty,
|
||||
Chunk(u32)
|
||||
}
|
||||
|
||||
impl fmt::Debug for Sector {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Empty => write!(f, "(.)"),
|
||||
Self::Chunk(arg0) => write!(f, "({})", arg0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Part1{
|
||||
drive: Vec<Sector>
|
||||
}
|
||||
type Part2 = Part1;
|
||||
|
||||
impl Part1 {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
drive: vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn read_input_part1(part1: &mut Part1, path: &Path) -> Result<(), AdventError> {
|
||||
let line = get_input(path);
|
||||
let mut reading_file = true;
|
||||
let mut current_file_id = 0;
|
||||
for c in line.chars() {
|
||||
let i = c.to_digit(10).unwrap() as u8;
|
||||
if reading_file {
|
||||
for _ in 0..i {
|
||||
part1.drive.push(Sector::Chunk(current_file_id))
|
||||
}
|
||||
current_file_id += 1;
|
||||
} else {
|
||||
for _ in 0..i {
|
||||
part1.drive.push(Sector::Empty);
|
||||
}
|
||||
}
|
||||
reading_file = !reading_file
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn checksum(drive: &Vec<Sector>) -> usize {
|
||||
drive.iter().enumerate().map(|(i, sector)| {
|
||||
match sector {
|
||||
Sector::Empty => 0,
|
||||
Sector::Chunk(f) => i * (*f as usize),
|
||||
}
|
||||
}).sum()
|
||||
}
|
||||
|
||||
fn solve_part1(part1: &mut Part1) -> Result<String, AdventError> {
|
||||
let mut empty_index = 0;
|
||||
let mut rev_file_index = 0;
|
||||
loop {
|
||||
empty_index += part1.drive.iter().skip(empty_index).position(|s| { *s == Sector::Empty}).unwrap();
|
||||
rev_file_index += part1.drive.iter().rev().skip(rev_file_index).position(|s| { *s != Sector::Empty}).unwrap();
|
||||
let file_index = part1.drive.len() - 1 - rev_file_index;
|
||||
|
||||
if empty_index > file_index {
|
||||
break;
|
||||
}
|
||||
|
||||
part1.drive[empty_index] = part1.drive[file_index];
|
||||
part1.drive[file_index] = Sector::Empty;
|
||||
}
|
||||
|
||||
let checksum: usize = checksum(&part1.drive);
|
||||
Ok(checksum.to_string())
|
||||
}
|
||||
|
||||
fn read_input_part2(part2: &mut Part2, path: &Path) -> Result<(), AdventError> {
|
||||
read_input_part1(part2, path)
|
||||
}
|
||||
|
||||
fn highest_file_id(part2: &Part2) -> u32 {
|
||||
match part2.drive.iter().rev().find(|s| **s != Sector::Empty).unwrap() {
|
||||
Sector::Empty => panic!("Should not happen"),
|
||||
Sector::Chunk(f) => *f,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_pos_and_len(part2: &Part2, id: u32) -> (usize, usize) {
|
||||
let pos = part2.drive.iter().position(|s| match s {
|
||||
Sector::Empty => false,
|
||||
Sector::Chunk(cid) => *cid == id,
|
||||
}).unwrap();
|
||||
|
||||
for j in pos..part2.drive.len() {
|
||||
if part2.drive[j] != Sector::Chunk(id){
|
||||
return (pos, j - pos)
|
||||
}
|
||||
}
|
||||
return (pos, part2.drive.len() - pos)
|
||||
}
|
||||
|
||||
fn find_empty_slice(part2: &Part2, len: usize) -> usize {
|
||||
let mut pos = 0;
|
||||
loop {
|
||||
pos += part2.drive.iter().skip(pos).position(|s| *s == Sector::Empty).unwrap();
|
||||
if pos + len >= part2.drive.len() {
|
||||
return part2.drive.len();
|
||||
}
|
||||
if part2.drive[pos..pos+len].iter().all(|s| *s == Sector::Empty) {
|
||||
return pos;
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn solve_part2(part2: &mut Part2) -> Result<String, AdventError> {
|
||||
let highest_file_id = highest_file_id(part2);
|
||||
for i in (1..highest_file_id + 1).rev() {
|
||||
let (pos, len) = find_pos_and_len(part2, i);
|
||||
let empty_pos = find_empty_slice(part2, len);
|
||||
|
||||
if empty_pos > pos {
|
||||
continue;
|
||||
}
|
||||
for j in empty_pos..empty_pos+len {
|
||||
part2.drive[j] = Sector::Chunk(i);
|
||||
}
|
||||
for j in pos..pos+len {
|
||||
part2.drive[j] = Sector::Empty;
|
||||
}
|
||||
}
|
||||
|
||||
let checksum: usize = checksum(&part2.drive);
|
||||
Ok(checksum.to_string())
|
||||
}
|
||||
|
||||
#[advent_day(Part1, Part2)]
|
||||
struct Day9;
|
@ -23,13 +23,17 @@ pub mod day5;
|
||||
pub mod day6;
|
||||
pub mod day7;
|
||||
pub mod day8;
|
||||
pub mod day9;
|
||||
|
||||
pub mod day14;
|
||||
|
||||
/*
|
||||
use std::path::Path;
|
||||
|
||||
use advent_derive::advent_day;
|
||||
|
||||
use crate::error::AdventError;
|
||||
use super::*;
|
||||
|
||||
|
||||
struct Part1{}
|
||||
|
@ -12,6 +12,7 @@ use day5::Day5;
|
||||
use day6::Day6;
|
||||
use day7::Day7;
|
||||
use day8::Day8;
|
||||
use day9::Day9;
|
||||
use day14::Day14;
|
||||
|
||||
|
||||
@ -49,7 +50,7 @@ fn main() -> Result<(), AdventError> {
|
||||
Box::new(Day6::new()),
|
||||
Box::new(Day7::new()),
|
||||
Box::new(Day8::new()),
|
||||
Box::new(DummyDay::new()),
|
||||
Box::new(Day9::new()),
|
||||
Box::new(DummyDay::new()),
|
||||
Box::new(DummyDay::new()),
|
||||
Box::new(DummyDay::new()),
|
||||
|
Loading…
x
Reference in New Issue
Block a user