From c34096a6ec8fd9610c94a6191c3b1f07b19ccc22 Mon Sep 17 00:00:00 2001 From: Kevin Caffrey Date: Thu, 14 Dec 2023 00:54:20 -0500 Subject: [PATCH] day 14 --- README.md | 3 +- data/examples/14.txt | 10 +++ src/bin/14.rs | 185 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 data/examples/14.txt create mode 100644 src/bin/14.rs diff --git a/README.md b/README.md index 475852e..dd7e984 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,9 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www. | [Day 11](./src/bin/11.rs) | `16.3µs` | `15.7µs` | | [Day 12](./src/bin/12.rs) | `137.9µs` | `618.3µs` | | [Day 13](./src/bin/13.rs) | `12.3µs` | `15.9µs` | +| [Day 14](./src/bin/14.rs) | `26.4µs` | `16.2ms` | -**Total: 2.38ms** +**Total: 18.61ms** --- diff --git a/data/examples/14.txt b/data/examples/14.txt new file mode 100644 index 0000000..b92d1a3 --- /dev/null +++ b/data/examples/14.txt @@ -0,0 +1,10 @@ +O....#.... +O.OO#....# +.....##... +OO.#O....O +.O.....O#. +O.#..O.#.# +..O..#O..O +.......O.. +#....###.. +#OO..#.... \ No newline at end of file diff --git a/src/bin/14.rs b/src/bin/14.rs new file mode 100644 index 0000000..ffb13fe --- /dev/null +++ b/src/bin/14.rs @@ -0,0 +1,185 @@ +use std::collections::{hash_map::Entry, HashMap}; + +advent_of_code::solution!(14); + +pub fn part_one(input: &str) -> Option { + let platform = input + .lines() + .map(|line| line.chars().collect::>()) + .collect::>(); + let mut score = 0; + for col in 0..platform[0].len() { + let mut empty_spaces = 0; + for row in 0..platform.len() { + match platform[row][col] { + '.' => empty_spaces += 1, + '#' => empty_spaces = 0, + 'O' => { + let new_row = row - empty_spaces; + score += platform.len() - new_row; + } + _ => unreachable!(), + } + } + } + Some(score as u32) +} + +pub fn part_two(input: &str) -> Option { + let mut platform = input + .lines() + .map(|line| line.chars().collect::>()) + .collect::>(); + let mut old = platform.clone(); + let mut count = 0u64; + let mut seen = HashMap::new(); + while cycle(&mut platform, &mut old) { + count += 1; + let state = print(&platform); + match seen.entry(state) { + Entry::Occupied(val) => { + let cycle_length = count - *val.get(); + let remainder = 1_000_000_000 + - (((1_000_000_000 - count) as f64 / cycle_length as f64).floor() as u64 + * cycle_length + + count); + for _ in 0..remainder { + cycle(&mut platform, &mut old); + } + break; + } + Entry::Vacant(e) => { + e.insert(count); + } + } + } + Some(load(&platform)) +} + +fn north(platform: &mut [Vec]) -> u32 { + let mut score = 0; + for col in 0..platform[0].len() { + let mut empty_spaces = 0; + for row in 0..platform.len() { + match platform[row][col] { + '.' => empty_spaces += 1, + '#' => empty_spaces = 0, + 'O' => { + let new_row = row - empty_spaces; + platform[row][col] = '.'; + platform[new_row][col] = 'O'; + score += platform[0].len() - new_row; + } + _ => unreachable!(), + } + } + } + score as u32 +} + +fn west(platform: &mut [Vec]) { + for row in 0..platform.len() { + let mut empty_spaces = 0; + for col in 0..platform[0].len() { + match platform[row][col] { + '.' => empty_spaces += 1, + '#' => empty_spaces = 0, + 'O' => { + let new_col = col - empty_spaces; + platform[row][col] = '.'; + platform[row][new_col] = 'O'; + } + _ => unreachable!(), + } + } + } +} + +fn south(platform: &mut [Vec]) { + for col in 0..platform[0].len() { + let mut empty_spaces = 0; + for row in (0..platform.len()).rev() { + match platform[row][col] { + '.' => empty_spaces += 1, + '#' => empty_spaces = 0, + 'O' => { + let new_row = row + empty_spaces; + platform[row][col] = '.'; + platform[new_row][col] = 'O'; + } + _ => unreachable!(), + } + } + } +} + +fn east(platform: &mut [Vec]) { + for row in 0..platform.len() { + let mut empty_spaces = 0; + for col in (0..platform[0].len()).rev() { + match platform[row][col] { + '.' => empty_spaces += 1, + '#' => empty_spaces = 0, + 'O' => { + let new_col = col + empty_spaces; + platform[row][col] = '.'; + platform[row][new_col] = 'O'; + } + _ => unreachable!(), + } + } + } +} + +fn cycle(platform: &mut [Vec], old: &mut [Vec]) -> bool { + let mut changed = false; + north(platform); + west(platform); + south(platform); + east(platform); + for r in 0..platform.len() { + for c in 0..platform[0].len() { + if !changed && old[r][c] != platform[r][c] { + changed = true; + } + old[r][c] = platform[r][c]; + } + } + changed +} + +fn load(platform: &Vec>) -> u32 { + let mut score = 0; + for (row_idx, row) in platform.iter().enumerate() { + for ch in row.iter().copied() { + if ch == 'O' { + score += platform.len() - row_idx; + } + } + } + score as u32 +} + +fn print(platform: &[Vec]) -> String { + platform + .iter() + .flat_map(|r| r.iter().chain(std::iter::once(&'\n'))) + .collect::() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part_one() { + let result = part_one(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(136)); + } + + #[test] + fn test_part_two() { + let result = part_two(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(64)); + } +}