From d8b96c8d592ce5cff2bd15f9d22cad7184f9a084 Mon Sep 17 00:00:00 2001 From: Dany Castillo <31006608+dcastil@users.noreply.github.com> Date: Mon, 25 Dec 2023 18:36:06 +0100 Subject: [PATCH] submit day 14 part 2 --- src/bin/14.rs | 227 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 225 insertions(+), 2 deletions(-) diff --git a/src/bin/14.rs b/src/bin/14.rs index f467b8b..de3c9f0 100644 --- a/src/bin/14.rs +++ b/src/bin/14.rs @@ -1,3 +1,6 @@ +use std::hash::{Hash, Hasher}; +use std::{collections::HashMap, vec}; + advent_of_code::solution!(14); pub fn part_one(input: &str) -> Option { @@ -31,10 +34,230 @@ pub fn part_one(input: &str) -> Option { Some(total_load) } -pub fn part_two(input: &str) -> Option { +pub fn part_two(input: &str) -> Option { + let mut platform = Platform::from_input(input); + let mut cycle_map = HashMap::new(); + + for index in 0..1000 { + platform.tilt_cycle(); + + if let Some(previous_index) = cycle_map.get(&platform) { + let cycle_length = index - previous_index; + + let remaining_cycles = (1_000_000_000 - index - 1) % cycle_length; + + for _ in 0..remaining_cycles { + platform.tilt_cycle(); + } + + return Some(platform.count_load()); + } else { + cycle_map.insert(platform.clone(), index); + } + } + None } +#[derive(PartialEq, Eq, Clone)] +struct Platform { + grid: HashMap, + len_x: usize, + len_y: usize, +} + +impl Platform { + fn from_input(input: &str) -> Platform { + let mut grid = HashMap::new(); + let mut max_x = 0; + let mut max_y = 0; + + for (y, line) in input.lines().enumerate() { + max_y = y; + + for (x, character) in line.chars().enumerate() { + if x > max_x { + max_x = x; + } + + if character == '#' { + grid.insert(Coordinate { x, y }, Element::Fixed); + } else if character == 'O' { + grid.insert(Coordinate { x, y }, Element::Movable); + } + } + } + + Platform { + grid, + len_x: max_x + 1, + len_y: max_y + 1, + } + } + + fn tilt_cycle(&mut self) { + self.tilt(Direction::Up); + self.tilt(Direction::Left); + self.tilt(Direction::Down); + self.tilt(Direction::Right); + } + + fn tilt(&mut self, direction: Direction) { + let mut next_empty_slots = match direction { + Direction::Up => vec![0; self.len_x], + Direction::Down => vec![self.len_y - 1; self.len_x], + Direction::Left => vec![0; self.len_y], + Direction::Right => vec![self.len_x - 1; self.len_y], + }; + + match direction { + Direction::Up => { + for y in 0..self.len_y { + for x in 0..self.len_x { + self.handle_position( + Coordinate { x, y }, + &direction, + &mut next_empty_slots, + ); + } + } + } + Direction::Down => { + for y in (0..self.len_y).rev() { + for x in 0..self.len_x { + self.handle_position( + Coordinate { x, y }, + &direction, + &mut next_empty_slots, + ); + } + } + } + Direction::Left => { + for x in 0..self.len_x { + for y in 0..self.len_y { + self.handle_position( + Coordinate { x, y }, + &direction, + &mut next_empty_slots, + ); + } + } + } + Direction::Right => { + for x in (0..self.len_x).rev() { + for y in 0..self.len_y { + self.handle_position( + Coordinate { x, y }, + &direction, + &mut next_empty_slots, + ); + } + } + } + } + } + + fn handle_position( + &mut self, + coordinate: Coordinate, + direction: &Direction, + next_empty_slots: &mut [usize], + ) { + if let Some(element) = self.grid.get(&coordinate) { + let (outer_index, inner_index) = match direction { + Direction::Up | Direction::Down => (coordinate.y, coordinate.x), + Direction::Left | Direction::Right => (coordinate.x, coordinate.y), + }; + + match element { + Element::Fixed => { + next_empty_slots[inner_index] = match direction { + Direction::Up | Direction::Left => outer_index + 1, + Direction::Down | Direction::Right => { + if outer_index == 0 { + 0 + } else { + outer_index - 1 + } + } + }; + } + Element::Movable => { + let moved_coordinate = match direction { + Direction::Up | Direction::Down => Coordinate { + x: coordinate.x, + y: next_empty_slots[inner_index], + }, + Direction::Left | Direction::Right => Coordinate { + x: next_empty_slots[inner_index], + y: coordinate.y, + }, + }; + + self.grid.remove(&coordinate); + self.grid.insert(moved_coordinate, Element::Movable); + + next_empty_slots[inner_index] = match direction { + Direction::Up | Direction::Left => next_empty_slots[inner_index] + 1, + Direction::Down | Direction::Right => { + if next_empty_slots[inner_index] == 0 { + 0 + } else { + next_empty_slots[inner_index] - 1 + } + } + }; + } + } + } + } + + fn count_load(&self) -> usize { + self.grid + .iter() + .filter_map(|(coordinate, element)| match element { + Element::Movable => Some(self.len_y - coordinate.y), + Element::Fixed => None, + }) + .sum() + } +} + +impl Hash for Platform { + fn hash(&self, state: &mut H) { + for y in 0..self.len_y { + for x in 0..self.len_x { + let coordinate = Coordinate { x, y }; + + if let Some(element) = self.grid.get(&coordinate) { + coordinate.hash(state); + element.hash(state) + } + } + } + } +} + +#[derive(PartialEq, Eq, Hash, Clone, Debug)] +struct Coordinate { + x: usize, + y: usize, +} + +#[derive(PartialEq, Eq, Hash, Clone, Debug)] +enum Element { + Movable, + Fixed, +} + +enum Direction { + Up, + Down, + Left, + Right, +} + #[cfg(test)] mod tests { use super::*; @@ -48,6 +271,6 @@ mod tests { #[test] fn test_part_two() { let result = part_two(&advent_of_code::template::read_file("examples", DAY)); - assert_eq!(result, None); + assert_eq!(result, Some(64)); } }