Day 14
DP is cool but actually wtf
This commit is contained in:
parent
f26ca8924c
commit
c585c139a5
2 changed files with 148 additions and 0 deletions
145
lib/src/day14/mod.rs
Normal file
145
lib/src/day14/mod.rs
Normal file
|
@ -0,0 +1,145 @@
|
|||
use std::{collections::HashMap, num::NonZeroUsize};
|
||||
|
||||
use clru::CLruCache;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::utils::Day;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Day14 {
|
||||
pub input: String,
|
||||
}
|
||||
|
||||
const SIZE: usize = 100; // More efficient to hardcode the input size, for less allocations
|
||||
|
||||
impl Day14 {
|
||||
fn rotate(left: bool, array: &mut [[char; SIZE]; SIZE]) {
|
||||
let mut rot = [['.'; SIZE]; SIZE];
|
||||
match left {
|
||||
false => for i in 0..SIZE {
|
||||
for j in 0..SIZE {
|
||||
rot[i][j] = array[SIZE - j - 1][i];
|
||||
}
|
||||
},
|
||||
true => for i in 0..SIZE {
|
||||
for j in 0..SIZE {
|
||||
rot[i][j] = array[j][SIZE - i - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
*array = rot;
|
||||
}
|
||||
}
|
||||
|
||||
impl Day for Day14 {
|
||||
fn part1(&mut self) -> String {
|
||||
let mut square_rocks = HashMap::<usize /* column index */, usize /* row index */>::new();
|
||||
let mut new_dish = vec![vec![false; self.input.lines().next().unwrap().len()]; self.input.lines().count()];
|
||||
for (i, row) in self.input.lines().enumerate() {
|
||||
for (j, char) in row.chars().enumerate() {
|
||||
match char {
|
||||
'.' => continue,
|
||||
'#' => { square_rocks.insert(j, i); },
|
||||
'O' => {
|
||||
let mut k = square_rocks.get(&j).map(|n| n + 1).unwrap_or(0);
|
||||
loop {
|
||||
if new_dish[k][j] != true { new_dish[k][j] = true; break }
|
||||
else { k += 1; }
|
||||
}
|
||||
},
|
||||
_ => panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dbg print lines
|
||||
// println!(
|
||||
// "{}",
|
||||
// new_dish
|
||||
// .iter()
|
||||
// .map(|l| l.iter().map(|b| if *b { 'O' } else { '.' }).collect::<String>())
|
||||
// .collect::<Vec<_>>()
|
||||
// .join("\n")
|
||||
// );
|
||||
|
||||
new_dish.into_iter().enumerate().map(|(i, line)| line.into_iter().filter_map(|rock| if rock { Some(SIZE - i) } else { None }).sum::<usize>()).sum::<usize>().to_string()
|
||||
}
|
||||
|
||||
fn part2(&mut self) -> String {
|
||||
let mut direction = 0u8; // 0 -> North, 1 -> East, 2 -> South, 3 -> West
|
||||
let mut new_dish: [[char; SIZE]; SIZE] = self.input.lines().map(|line| line.chars().collect_vec().try_into().unwrap()).collect_vec().try_into().unwrap();
|
||||
let mut cache = CLruCache::<(u8, [[char; SIZE]; SIZE]), [[char; SIZE]; SIZE]>::new(NonZeroUsize::new(100).unwrap());
|
||||
|
||||
for i in 0..390625u128 {
|
||||
if i % 100000 == 0 { println!("{:.02}%, {}", i as f64 / 4000000000f64 * 100f64, cache.len()); }
|
||||
|
||||
// Cache check
|
||||
let cache_ref = new_dish.clone();
|
||||
if let Some(result) = cache.get(&(direction, cache_ref)) {
|
||||
new_dish = *result;
|
||||
continue;
|
||||
}
|
||||
|
||||
for _ in 0..10240 {
|
||||
// Based on direction, flip the input
|
||||
match direction {
|
||||
0 => (),
|
||||
1 => Self::rotate(true, &mut new_dish),
|
||||
2 => {
|
||||
for row in new_dish.iter_mut() {
|
||||
row.reverse();
|
||||
}
|
||||
new_dish.reverse();
|
||||
},
|
||||
3 => Self::rotate(false, &mut new_dish),
|
||||
_ => panic!()
|
||||
}
|
||||
|
||||
// Init tracking
|
||||
let mut square_rocks = HashMap::<usize /* column index */, usize /* row index */>::new();
|
||||
let clone = new_dish.clone();
|
||||
|
||||
for (i, row) in clone.iter().enumerate() {
|
||||
for (j, char) in row.iter().enumerate() {
|
||||
match char {
|
||||
'.' => continue,
|
||||
'#' => { square_rocks.insert(j, i); },
|
||||
'O' => {
|
||||
new_dish[i][j] = '.';
|
||||
let mut k = square_rocks.get(&j).map(|n| n + 1).unwrap_or(0);
|
||||
loop {
|
||||
if new_dish[k][j] != 'O' { new_dish[k][j] = 'O'; break }
|
||||
else { k += 1; }
|
||||
}
|
||||
},
|
||||
_ => panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Based on direction, tilt the direction again
|
||||
// Based on direction, flip the input
|
||||
match direction {
|
||||
0 => (),
|
||||
1 => Self::rotate(false, &mut new_dish),
|
||||
2 => {
|
||||
for row in new_dish.iter_mut() {
|
||||
row.reverse();
|
||||
}
|
||||
new_dish.reverse();
|
||||
},
|
||||
3 => Self::rotate(true, &mut new_dish),
|
||||
_ => panic!()
|
||||
}
|
||||
|
||||
// Loop direction
|
||||
if direction != 0 { direction -= 1; } else { direction = 3; }
|
||||
}
|
||||
|
||||
// Cache store
|
||||
cache.put((direction, cache_ref), new_dish);
|
||||
}
|
||||
|
||||
new_dish.into_iter().enumerate().map(|(i, line)| line.into_iter().filter_map(|rock| if rock == 'O' { Some(SIZE - i) } else { None }).sum::<usize>()).sum::<usize>().to_string()
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ use day10::Day10;
|
|||
use day11::Day11;
|
||||
use day12::Day12;
|
||||
use day13::Day13;
|
||||
use day14::Day14;
|
||||
use day2::Day2;
|
||||
use day3::Day3;
|
||||
use day4::Day4;
|
||||
|
@ -24,6 +25,7 @@ pub mod day10;
|
|||
pub mod day11;
|
||||
pub mod day12;
|
||||
pub mod day13;
|
||||
pub mod day14;
|
||||
pub mod day2;
|
||||
pub mod day3;
|
||||
pub mod day4;
|
||||
|
@ -68,6 +70,7 @@ pub fn get_day(day: u8, input: String) -> Box<dyn Day> {
|
|||
cache: CLruCache::new(NonZeroUsize::new(10000).unwrap()),
|
||||
}),
|
||||
13 => Box::new(Day13 { input }),
|
||||
14 => Box::new(Day14 { input }),
|
||||
_ => panic!("Invalid day #"),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue