mirror of
https://github.com/Noratrieb/advent-of-code.git
synced 2026-01-14 09:35:01 +01:00
this code is way too complicated
This commit is contained in:
parent
7c9d2a2377
commit
6969604ec5
1 changed files with 305 additions and 3 deletions
|
|
@ -1,5 +1,3 @@
|
|||
use std::iter;
|
||||
|
||||
use helper::{Day, Variants};
|
||||
|
||||
pub fn main() {
|
||||
|
|
@ -15,6 +13,8 @@ helper::define_variants! {
|
|||
}
|
||||
part2 {
|
||||
basic => crate::part2,sample_count=1;
|
||||
index => crate::part2_index,sample_count=1000;
|
||||
index_index => crate::part2_index_index;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -29,6 +29,8 @@ impl Day for Day09 {
|
|||
}
|
||||
|
||||
fn part1(input: &str) -> u64 {
|
||||
use std::iter;
|
||||
|
||||
let input = &input[0..input.len() - 1];
|
||||
|
||||
let mut blocks = Vec::new();
|
||||
|
|
@ -74,6 +76,8 @@ fn part1(input: &str) -> u64 {
|
|||
}
|
||||
|
||||
fn part2(input: &str) -> u64 {
|
||||
use std::iter;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum Block {
|
||||
File { id: u16, size: u8 },
|
||||
|
|
@ -158,6 +162,304 @@ fn part2(input: &str) -> u64 {
|
|||
.sum()
|
||||
}
|
||||
|
||||
fn part2_index(input: &str) -> u64 {
|
||||
use std::iter;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum Block {
|
||||
File { id: u16, size: u8 },
|
||||
Space,
|
||||
}
|
||||
#[expect(dead_code)]
|
||||
fn print_blocks(blocks: &[Block]) {
|
||||
for b in blocks {
|
||||
match b {
|
||||
Block::Space { .. } => eprint!("."),
|
||||
Block::File { id, .. } => eprint!("{}", id),
|
||||
}
|
||||
}
|
||||
eprintln!();
|
||||
}
|
||||
|
||||
let input = &input[0..input.len() - 1];
|
||||
|
||||
let mut index = [const { Vec::<usize>::new() }; 10];
|
||||
|
||||
let mut blocks = Vec::<Block>::new();
|
||||
let mut is_file = true;
|
||||
let mut id = 0_u16;
|
||||
for b in input.bytes() {
|
||||
debug_assert!(b.is_ascii_digit());
|
||||
let len = (b - b'0') as usize;
|
||||
if is_file {
|
||||
blocks.extend(iter::repeat_n(
|
||||
Block::File {
|
||||
id,
|
||||
size: len as u8,
|
||||
},
|
||||
len,
|
||||
));
|
||||
id += 1;
|
||||
} else {
|
||||
if len > 0 {
|
||||
index[len].push(blocks.len());
|
||||
}
|
||||
blocks.extend(iter::repeat_n(Block::Space, len));
|
||||
}
|
||||
is_file = !is_file;
|
||||
}
|
||||
|
||||
index.iter_mut().for_each(|v| v.reverse());
|
||||
|
||||
let mut i = blocks.len() - 1;
|
||||
|
||||
// print_blocks(&blocks);
|
||||
|
||||
while i > 0 {
|
||||
match blocks[i] {
|
||||
Block::File { id: _, size } => {
|
||||
let end = i + 1;
|
||||
let size_usize = size as usize;
|
||||
|
||||
let possible_gaps = &mut index[size_usize..];
|
||||
let gap = possible_gaps
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.filter(|(_, gaps)| gaps.last().is_some_and(|gap| *gap < i))
|
||||
.min_by_key(|(_, gaps)| *gaps.last().unwrap());
|
||||
|
||||
match gap {
|
||||
Some((gap_size, chosen_gap)) => {
|
||||
let gap_size = gap_size + size_usize;
|
||||
let chosen_gap = chosen_gap.pop().unwrap();
|
||||
|
||||
blocks.copy_within((end - size_usize)..end, chosen_gap);
|
||||
blocks[(end - size_usize)..][..size_usize].fill(Block::Space);
|
||||
i = i.saturating_sub(size_usize);
|
||||
|
||||
// add gap back to index
|
||||
if gap_size > size_usize {
|
||||
let remaining_size = gap_size - size_usize;
|
||||
let remaining_index = chosen_gap + size_usize;
|
||||
let bucket = &mut index[remaining_size];
|
||||
let back_offset_insert =
|
||||
bucket.iter().rev().position(|gap| *gap > remaining_index);
|
||||
match back_offset_insert {
|
||||
Some(back_offset_insert) => {
|
||||
let len = bucket.len();
|
||||
bucket.insert(len - back_offset_insert, remaining_index);
|
||||
}
|
||||
None => bucket.push(remaining_index),
|
||||
}
|
||||
}
|
||||
|
||||
// print_blocks(&blocks);
|
||||
}
|
||||
None => {
|
||||
i = i.saturating_sub(size_usize);
|
||||
}
|
||||
}
|
||||
}
|
||||
Block::Space { .. } => {
|
||||
i = i.saturating_sub(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// print_blocks(&blocks);
|
||||
|
||||
blocks
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, tile)| match tile {
|
||||
Block::File { id, .. } => Some(*id as u64 * i as u64),
|
||||
_ => None,
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
||||
fn part2_index_index(input: &str) -> u64 {
|
||||
use std::iter;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum Block {
|
||||
File { id: u16, size: u8 },
|
||||
Space,
|
||||
}
|
||||
#[expect(dead_code)]
|
||||
fn print_blocks(blocks: &[Block]) {
|
||||
for b in blocks {
|
||||
match b {
|
||||
Block::Space { .. } => eprint!("."),
|
||||
Block::File { id, .. } => eprint!("{}", id),
|
||||
}
|
||||
}
|
||||
eprintln!();
|
||||
}
|
||||
|
||||
let input = &input[0..input.len() - 1];
|
||||
|
||||
let mut index = [const { Vec::<usize>::new() }; 10];
|
||||
|
||||
let mut blocks = Vec::<Block>::with_capacity(input.len());
|
||||
let mut is_file = true;
|
||||
let mut id = 0_u16;
|
||||
for b in input.bytes() {
|
||||
debug_assert!(b.is_ascii_digit());
|
||||
let len = (b - b'0') as usize;
|
||||
if is_file {
|
||||
blocks.extend(iter::repeat_n(
|
||||
Block::File {
|
||||
id,
|
||||
size: len as u8,
|
||||
},
|
||||
len,
|
||||
));
|
||||
id += 1;
|
||||
} else {
|
||||
if len > 0 {
|
||||
index[len].push(blocks.len());
|
||||
}
|
||||
blocks.extend(iter::repeat_n(Block::Space, len));
|
||||
}
|
||||
is_file = !is_file;
|
||||
}
|
||||
|
||||
index.iter_mut().for_each(|v| v.reverse());
|
||||
|
||||
let mut min_index = [None::<(usize, usize)>; 10];
|
||||
min_index[min_index.len() - 1] = index[min_index.len() - 1]
|
||||
.last()
|
||||
.copied()
|
||||
.map(|gap| (index.len() - 1, gap));
|
||||
for i in (1..(min_index.len() - 1)).rev() {
|
||||
min_index[i] = match (index[i].last().copied(), min_index[i + 1]) {
|
||||
(None, None) => None,
|
||||
(Some(x), None) => Some((i, x)),
|
||||
(None, Some(x)) => Some(x),
|
||||
(Some(x), Some(y)) => {
|
||||
if x < y.1 {
|
||||
Some((i, x))
|
||||
} else {
|
||||
Some(y)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_min_index(index: &[Vec<usize>], min_index: &[Option<(usize, usize)>]) {
|
||||
for bucket in 1..10 {
|
||||
let actual_min_bucket = index[bucket..]
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, gaps)| gaps.last().map(|gap| (i + bucket, *gap)))
|
||||
.min_by_key(|(_, gap)| *gap);
|
||||
assert_eq!(min_index[bucket], actual_min_bucket, "for {bucket}");
|
||||
}
|
||||
}
|
||||
|
||||
let mut i = blocks.len() - 1;
|
||||
|
||||
// print_blocks(&blocks);
|
||||
|
||||
while i > 0 {
|
||||
if cfg!(debug_assertions) {
|
||||
verify_min_index(&index, &min_index);
|
||||
}
|
||||
|
||||
match blocks[i] {
|
||||
Block::File { id: _, size } => {
|
||||
let end = i + 1;
|
||||
let size_usize = size as usize;
|
||||
|
||||
let gap = min_index[size_usize];
|
||||
|
||||
match gap {
|
||||
Some((_, chosen_gap)) if chosen_gap > i => {
|
||||
i = i.saturating_sub(size_usize);
|
||||
}
|
||||
Some((gap_size, chosen_gap)) => {
|
||||
let poppped_gap_offset = index[gap_size].pop().unwrap();
|
||||
debug_assert_eq!(poppped_gap_offset, chosen_gap);
|
||||
|
||||
blocks.copy_within((end - size_usize)..end, chosen_gap);
|
||||
blocks[(end - size_usize)..][..size_usize].fill(Block::Space);
|
||||
i = i.saturating_sub(size_usize);
|
||||
|
||||
// add gap back to index
|
||||
if gap_size > size_usize {
|
||||
let remaining_size = gap_size - size_usize;
|
||||
let remaining_index = chosen_gap + size_usize;
|
||||
let bucket = &mut index[remaining_size];
|
||||
let back_offset_insert =
|
||||
bucket.iter().rev().position(|gap| *gap > remaining_index);
|
||||
match back_offset_insert {
|
||||
Some(back_offset_insert) => {
|
||||
let len = bucket.len();
|
||||
bucket.insert(len - back_offset_insert, remaining_index);
|
||||
}
|
||||
None => bucket.push(remaining_index),
|
||||
}
|
||||
}
|
||||
|
||||
// recompute min_index
|
||||
if gap_size < index.len() - 1 {
|
||||
min_index[gap_size] =
|
||||
match (index[gap_size].last(), min_index[gap_size + 1]) {
|
||||
(None, None) => None,
|
||||
(Some(x), None) => Some((gap_size, *x)),
|
||||
(None, Some(x)) => Some(x),
|
||||
(Some(x), Some(y)) => {
|
||||
if *x < y.1 {
|
||||
Some((gap_size, *x))
|
||||
} else {
|
||||
Some(y)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
min_index[gap_size] =
|
||||
index[gap_size].last().map(|gap| (gap_size, *gap));
|
||||
}
|
||||
for i in (1..gap_size).rev() {
|
||||
min_index[i] = match (index[i].last(), min_index[i + 1]) {
|
||||
(None, None) => None,
|
||||
(Some(x), None) => Some((i, *x)),
|
||||
(None, Some(y)) => Some(y),
|
||||
(Some(x), Some(y)) => {
|
||||
if *x < y.1 {
|
||||
Some((i, *x))
|
||||
} else {
|
||||
Some(y)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print_blocks(&blocks);
|
||||
}
|
||||
None => {
|
||||
i = i.saturating_sub(size_usize);
|
||||
}
|
||||
}
|
||||
}
|
||||
Block::Space { .. } => {
|
||||
i = i.saturating_sub(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print_blocks(&blocks);
|
||||
|
||||
blocks
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, tile)| match tile {
|
||||
Block::File { id, .. } => Some(*id as u64 * i as u64),
|
||||
_ => None,
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
||||
helper::tests! {
|
||||
day09 Day09;
|
||||
part1 {
|
||||
|
|
@ -166,7 +468,7 @@ helper::tests! {
|
|||
}
|
||||
part2 {
|
||||
small => 2858;
|
||||
default => 0;
|
||||
default => 6467290479134;
|
||||
}
|
||||
}
|
||||
helper::benchmarks! {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue