day14 part2

This commit is contained in:
Andrew Glaze 2023-12-14 15:26:10 -05:00
parent 97d8acbad8
commit bece6b708b

View File

@ -1,6 +1,8 @@
use std::collections::HashMap;
use aoc_runner_derive::{aoc, aoc_generator}; use aoc_runner_derive::{aoc, aoc_generator};
#[derive(Debug)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Rock { enum Rock {
Round, Round,
Square, Square,
@ -43,10 +45,8 @@ fn part1(input: &Vec<Vec<Rock>>) -> usize {
Rock::Round => { Rock::Round => {
cur_weight -= 1; cur_weight -= 1;
load += cur_weight; load += cur_weight;
//println!("{}", cur_weight);
}, },
Rock::Square => { Rock::Square => {
//println!("{}", input[0].len() - i);
cur_weight = input[0].len() - i; cur_weight = input[0].len() - i;
}, },
Rock::None => continue Rock::None => continue
@ -56,10 +56,80 @@ fn part1(input: &Vec<Vec<Rock>>) -> usize {
load load
} }
// #[aoc(day14, part2)] #[aoc(day14, part2)]
// fn part2(input: &Vec<Vec<Rock>>) -> String { fn part2(input: &Vec<Vec<Rock>>) -> usize {
// todo!() let mut seen_at = HashMap::new();
// } let mut next_y = Vec::<usize>::new();
let mut map = input.to_vec();
// Functions to get a Rock using a rotated coordinate space
let cycle_parts: &[(Box<dyn Fn(&mut Vec<Vec<Rock>>, usize, usize) -> &mut Rock>, _, _); 4] = &[
(Box::new(|map: &mut Vec<Vec<Rock>>, x: usize, y: usize| &mut map[y][x]),
map[0].len(), map.len()),
(Box::new(|map: &mut Vec<Vec<Rock>>, x: usize, y: usize| &mut map[x][y]),
map.len(), map[0].len()),
(Box::new(|map: &mut Vec<Vec<Rock>>, x: usize, y: usize| { let h = map.len(); &mut map[h - 1 - y][x] }),
map[0].len(), map.len()),
(Box::new(|map: &mut Vec<Vec<Rock>>, x: usize, y: usize| { let w = map[0].len(); &mut map[x][w - 1 - y] }),
map.len(), map[0].len()),
];
let mut cycle = 0;
const END: u32 = 1000000000;
while cycle < END {
// Handle tilts in each direction
for (getter, width, height) in cycle_parts {
next_y.clear();
next_y.resize(*width, 0);
for y in 0..*height {
for x in 0..*width {
let item = getter(&mut map, x, y);
match *item {
Rock::None => {}
Rock::Square => {
next_y[x] = y + 1;
}
Rock::Round => {
*item = Rock::None;
*getter(&mut map, x, next_y[x]) = Rock::Round;
next_y[x] += 1;
}
}
}
}
}
// More compact representation of the current state, for saving in hashmap
let key = map.iter().enumerate().flat_map(|(y, line)| {
line.iter().enumerate().filter_map(move |(x, &ref rock)| {
if rock == &Rock::Round {
Some((x as u8, y as u8))
} else {
None
}
})
}).collect::<Vec<_>>();
cycle += 1;
if let Some(seen_at_cycle) = seen_at.insert(key, cycle) {
// Current state was identical to one we'd already seen, we can skip forward
let diff = cycle - seen_at_cycle;
let remaining = END - cycle;
let skipped = remaining / diff * diff;
cycle += skipped;
}
}
let height = map.len();
map.into_iter().enumerate().flat_map(|(y, line)| line.into_iter().filter_map(move |rock| {
if rock == Rock::Round {
Some(height - y)
} else {
None
}
})).sum()
}
#[cfg(test)] #[cfg(test)]
@ -82,8 +152,8 @@ O.#..O.#.#
assert_eq!(part1(&parse(EX)), 136); assert_eq!(part1(&parse(EX)), 136);
} }
// #[test] #[test]
// fn part2_example() { fn part2_example() {
// assert_eq!(part2(&parse(EX)), "<RESULT>"); assert_eq!(part2(&parse(EX)), 64);
// } }
} }