From 9a495ccd77b9ccf825c3ab94f96332bbbf951e7a Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Mon, 12 Dec 2022 21:10:53 +0100 Subject: [PATCH] 2022 - Day 12 --- 2022/input/12/input | 41 ++++++++ 2022/input/12/test-1 | 5 + 2022/src/bin/day12.rs | 219 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 265 insertions(+) create mode 100644 2022/input/12/input create mode 100644 2022/input/12/test-1 create mode 100644 2022/src/bin/day12.rs diff --git a/2022/input/12/input b/2022/input/12/input new file mode 100644 index 0000000..7f1b7da --- /dev/null +++ b/2022/input/12/input @@ -0,0 +1,41 @@ +abcccccccccccaaaaacccccccaaaaaaccccccccccccccccccccccccccccccccaaaaaaaaaaaaaacccccccccccccccccccaaaaaacccccccacccccccccaaccaaccccccccccccccccccccccccccccccaaaaaa +abcccccccccccaaaaaaacccccaaaaaaccccccccaaccccccccccaaaaccccccccaaaaaaaaaaaaaccccccccccccccccccccaaaaaaccccaaaacccccccccaaaaaaccccccccccccccccccccccccccccccccaaaa +abccccccccccaaaaaaaacccccaaaaaccccccccaaaacccccccccaaaacccccccccccaaaaaaacccccccccccccccccccccccaaaaacccccaaaaaaccccccccaaaaacccccccccccaaaccccccccccccccccccaaaa +abccccccccccaaaaaaaaccccccaaaaacccccccaaaacccccccccaaaacccccaaaccccaaaaaaccccccccccccccccccccccccaaaaacccccaaaaacccccccaaaaaacccccccccccaaaacccccccccccccccccaaaa +abccccccccccaaaaaaccccccccaaaaacccccccaaaaccccccccccaaacccccaaaaccaaaaaaaacccccccccccccccccccccccaaaaaccccaaaaacccccccaaaaaaaaccccccccccaaaaccaaccccccccccccaaaaa +abcccccccccccccaaaccccccccccccccccccccccccccccccccccccccccccaaaaccaaaaaaaaccccccccccccccccccccccccccccccccaccaaccccaaaaaaaaaaacccccccccccaaaaaaccccccccccccccaccc +abcacccccccccccccaaaccccccccccccccaaacccccccccccccccccccccccaaaccaaaacccaaacccccccccccccccccccccccaacccccccccccccccaaacccaaccccccccccccccaaaalllllccccccccccccccc +abaacccccccccccccaaaaaacccccccccccaaaccccccccccccccccccccccccccccaaaccccaaaccccccccccccccccccccccaaccccccccccccccccaaaaaaaaccccccccccccccckklllllllccccaaaccccccc +abaaaaacccccccccaaaaaaacccccccccaaaaaaaacccccaacccccccccccccccccccccccccaaaccccccccaacccccccccaaaaacaacaacaacccccaaaaaaaaccccccccccccaaakkkkllllllllcccaaaccccccc +abaaaaaccccccccaaaaaaaacccccccccaaaaaaaacccccaaaaaacccccccccccccccccccccaaaccccccaaaacacccccccaaaaaaaacaaaaaccccaaaaaaaaaccccccccckkkkkkkkkklsssslllcccaaaaaacccc +abaaaccccccccccaaaaaaacccccccccccaaaaacccccccaaaaaaccccccccccccccccccaaaaaaaaccccaaaaaacccccccccaaaaacaaaaacccccaaaaaaaacccaaaccjjkkkkkkkkkssssssslllcccaaaaacccc +abaaaccccccccccccaaaaaacccccaacccaaaaaaccccaaaaaaaccaaaccccccccccccccaaaaaaaacccccaaaacccccccccaaaaaccaaaaaacccccccaaaaaaccaaaajjjjkkkkkkssssssssslllcddaaaaccccc +abcaaacccccccccccaaaaaacaaacaacccaaaaaaccccaaaaaaaaaaaaaaccccccccccccccaaaaaccccccaaaaccccaaaaaaacaaacccaaaaaaacccaaaaaaaccaaajjjjrrrrrrssssuuuussqmmddddaaaccccc +abccaacccccccccccaaccccccaaaaacccaaaccaccccaaaaaaaaaaaaaacccccccccccccaaaaaacccccaacaaccccaaaaacccaaccccacccaaaaaaaaaccaaccaaajjjrrrrrrrrssuuuuuvqqmmmdddaaaccccc +abccccccccaaccccccccccccccaaaaaacccccccccccccaaaaaaaaaaaccccccccccccccaaaaaacccccccccccccaaaaaaccccccccccccaaaaaaaaaacccccccccjjjrrruuuuuuuuuuuvvqqmmmmddddaccccc +abaacccccaaaaccccccccccccaaaaaaacccccccccccccaacccccaaaaacccccccccccccaccaaacccccccccccccaaaaaacccccccccccaaaaaaaaccccccccccccjjjrrruuuuuuuuxyyvvqqqmmmddddcccccc +abaacccccaaaacccccccccccaaaaaaccccccccaaccccccccacccaaaaacccccccccccccccccccccccccccccccccaaaaacccccccccccaaaaaaacccccccccccccjjjrrttuxxxxuxxyyvvqqqqmmmmddddcccc +abaacccccaaaacccccccccccaacaaacccccaaaaacccaaaaaaaccccccccccccccccccccccccccccccccccccccccaaacccccccccccccccaaaaaaccccccccccccjjjrrtttxxxxxxyyyvvqqqqqmmmmdddcccc +abacccccccccccccccccccccccccaaccccccaaaaaccaaaaaaaccccccccaaccccccccccccccccccccccccccccccccccccccccccccccccaaaaaaccccccccccccjjjqrrttxxxxxxyyyvvvvqqqqmmmdddcccc +abccccccccccccccccccccccccccccccccccaaaaaccaaaaaaacccccccaaaccccccccccaaaccccccccccccccccccaaaccccccccccccccaaccccccccccaaccccjjjqqqtttxxxxxyyyyyvvvqqqqmmmeeeccc +SbaaccccccaccaaacccccccccccccccccccaaaaacccaaaaaaaaccccaaaaaaaacccccccaaacaaccccccccccccccaaaaaaccccccccccccccccccccccaaaaaaccciiiqqqttxxxxEzyyyyyvvvqqqnnneeeccc +abaaccccccaaaaaaccccccccccccccccccccccaaccaaaaaaaaaacccaaaaaaaacccccaaaaaaaaccccccccccccccaaaaaaccccccccccccccccccccccaaaaaaccciiiqqtttxxxyyyyyyyvvvvqqqnnneeeccc +abaaaaacccaaaaaaccccccccccccccccccccccccccaaaaaaaaaaccccaaaaaaccccccaaaaaaaaccccccccccccccaaaaaacccccccccccccccccccccccaaaaacciiiqqqttxxyyyyyyywvvvvrrrqnnneeeccc +abaaaaacccaaaaaaaccccccccaaaccccccccccccccaacaaaccccccccaaaaaaccccccaaaaaaaccccccccccccccccaaaaaccccccccccccccccccccccaaaaaccciiiqqtttxxxyyyyywwwvrrrrrnnneeecccc +abaaaccccaaaaaaaaccccccccaaaacccccccccccccccccaaccccccccaaaaaaccccccccaaaaaccccccccccccccccaacaaccccccccccccccccccccccaaaaaccciiqqqttxxxwwwwyyywwrrrrnnnnneeecccc +abaaaccccaaaaaaaaccccccccaaaacccccaaaaacccccccaaccccccccaaccaacccccccaaacaaacccccccccccccccccccccccccccccccccccccccccccccccccciiqqqtttwwwwwwywwwrrrrnnnnneeeccccc +abcaaaccccccaaaccccccccccaaaccccccaaaaacccccccccccccaaaaccccccccccccccaacccccccccccccccccccccccccccccccaaaacccccccccccccccccciiiqqqtttssssswwwwwrrrnnnneeeecccccc +abccaaccccccaaaccccccccccccccccccaaaaaacccccccccccccaaaaccccccccccccccccccccccccccccccccccccccccccccccaaaaacccccccccccccccccciiiqqqqtssssssswwwwrronnnfeeeacccccc +abcccccccccccccccccccccccccccccccaaaaaacccccccccccccaaaaccccccccccccccccccccccccccccccccccccccccccccccaaaaaaccccccccccccccccciiiiqqppssssssswwwwrroonfffeaacccccc +abcccccccccccccccccccccccccccccccaaaaaacaaaccccccccccaacccccccccccccccccccccccccccccccccaaacccccccccccaaaaaaccccccccccccccccccihhpppppppppsssssrrroonfffaaaaacccc +abcccccccccccccccccccccccccccccccccaacccaaaaacccccccccccccccccccccccccccccccccccccccccccaaaaaaccccccccaaaaaccccccccccccccccccchhhhppppppppppssssrooofffaaaaaacccc +abccccccccaaaccccccccccccccccccccccccccaaaaacccccccccccccccccccccccccccccccccccccaccccaaaaaaaaccccccccccaaacccccccccccccccccccchhhhhhhhhpppposssoooofffaaaaaccccc +abccccccccaaaacccccaaccccccccccccccccccaaaaaccccccccccccccccccccccccaaccccccccccaaccccaaaaaaaacccccccccccccccccccccccccccccccccchhhhhhhhhgppooooooofffaaaaacccccc +abaaccccccaaaacccccaacaaccccccccccccccccaaaaacccccccccccccccaacaaccaaaaaaccccaaaaacaacaaaaaaacccccccccccccccccccccccccccccccccccccchhhhhhgggooooooffffaaaaaaccccc +abaaacccccaaaacccccaaaaaccccccccccccccccaaccccccccccccccccccaaaaaccaaaaaaccccaaaaaaaacccaaaaaccccccccccccccccccccccccaaacaacccccccccccccgggggooooffffccccaacccccc +abaaaccccccccccccaaaaaaccccaaccccccccccccccccccaaacccccccccccaaaaaaaaaaaacaacccaaaaaccccaacaaacccccccccccccccccccccccaaaaaaccccccccccccccaggggggggfffcccccccccccc +abaaaccccccccccccaaaaaaaacaaaaccccccccaaaccccccaaaacccccccccaaaaaaaaaaaaaaaaccaaaaacccccaaaaaccccccccccccccaaccccccccaaaaaaccccccccccccccaagggggggfccccccccccccca +abaacccccccccccccaccaaaaacaaaaccccccccaaaccccccaaaacccccccccaaaaccaaaaaaaaaaccaacaaaccccccaaaccccccccccccaaaaaacccccaaaaaaacccccccccccccaaaaccggggcccccccccccccaa +abaacccccccccccccccaaacaccaaaacccccaaaaaaaaccccaaaccccccccccccaaccaaaaaaaacccccccaacccccaacaaaaacccccccccaaaaaacccccaaaaaaaaccccccccccccaaaccccccccccccccccaaacaa +abcccccccccccccccccaaccccccccccccccaaaaaaaaccccccccccccccccccccaaaaaaaaaaaccccccccccccccaaaaaaaacccccccccaaaaaacccccaaaaaaaaccccccccccccacaccccccccccccccccaaaaaa +abccccccccccccccccccccccccccccccccccaaaaaacccccccccccccccccccccaaaaaaaaaaaaccccccccccccccaaaaaaccccccccccaaaaaccccccccaaacccccccccccccccccccccccccccccccccccaaaaa diff --git a/2022/input/12/test-1 b/2022/input/12/test-1 new file mode 100644 index 0000000..86e9cac --- /dev/null +++ b/2022/input/12/test-1 @@ -0,0 +1,5 @@ +Sabqponm +abcryxxl +accszExk +acctuvwj +abdefghi diff --git a/2022/src/bin/day12.rs b/2022/src/bin/day12.rs new file mode 100644 index 0000000..ae56175 --- /dev/null +++ b/2022/src/bin/day12.rs @@ -0,0 +1,219 @@ +#![feature(test)] +use core::fmt; +use std::{str::FromStr, cmp::{max, min}}; + +use anyhow::Result; +use aoc::Solver; + +// -- Runners -- +fn main() -> Result<()> { + Day::solve() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn part1_test1() -> Result<()> { + Day::test(Day::part1, "test-1", 31) + } + #[test] + fn part1_solution() -> Result<()> { + Day::test(Day::part1, "input", 481) + } + #[test] + fn part2_test1() -> Result<()> { + Day::test(Day::part2, "test-1", 29) + } + #[test] + fn part2_solution() -> Result<()> { + Day::test(Day::part2, "input", 480) + } + + // Benchmarks + extern crate test; + #[bench] + #[ignore] + fn part1_bench(b: &mut test::Bencher) { + Day::benchmark(Day::part1, b) + } + #[bench] + #[ignore] + fn part2_bench(b: &mut test::Bencher) { + Day::benchmark(Day::part2, b) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct Position { + x: isize, + y: isize, +} + +#[derive(Debug)] +struct Node { + height: u32, + visited: bool, + distance: u32, +} + +#[derive(Debug)] +struct Hill { + nodes: Vec>, + size: (isize, isize), + start: Position, + end: Position, +} + +impl fmt::Display for Hill { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for line in self.nodes.iter() { + for node in line { + if node.distance == u32::MAX { + write!(f, "[--.]")?; + } else { + let mut v = '.'; + if node.visited { + v = 'v'; + } + write!(f, "[{:>2}{}]", node.distance, v)?; + } + } + writeln!(f, "")?; + } + + Ok(()) + } +} + +impl FromStr for Hill { + type Err = anyhow::Error; + + fn from_str(input: &str) -> Result { + + let mut start = Position{x: 0, y: 0}; + let mut end = Position{x: 0, y: 0}; + + let mut xmax = 0; + let mut ymax = 0; + + let nodes = input + .lines() + .enumerate() + .map(|(y, line)| { + ymax = max(ymax, y+1); + line + .chars() + .enumerate() + .map(|(x, mut letter)| { + xmax = max(xmax, x+1); + if letter == 'S' { + start = Position{x: x as isize, y: y as isize}; + letter = 'a'; + } else if letter == 'E' { + end = Position{x: x as isize, y: y as isize}; + letter = 'z'; + } + let height = convert_height(letter); + Node {height, visited: false, distance: u32::MAX} + }).collect() + }).collect(); + + Ok(Self { nodes, size: (xmax as isize, ymax as isize), start, end }) + } +} + +impl Hill { + fn dijkstra bool>(&mut self, f: T) { + let mut unvisited = (0..self.size.1).flat_map(|y| (0..self.size.0).map(move |x| Position{ x, y })).collect::>(); + let mut current = self.start; + self.nodes[current.y as usize][current.x as usize].distance = 0; + loop { + let mut neighbours = vec![ + Position{x: current.x, y: current.y-1}, // Up + Position{x: current.x-1, y: current.y}, // Left + Position{x: current.x, y: current.y+1}, // Down + Position{x: current.x+1, y: current.y}, // Right + ]; + + let height = self.nodes[current.y as usize][current.x as usize].height; + + // We only want to update valid neighbours that have not been visited yet + neighbours.retain(|n| { + n.x >= 0 && n.x < self.size.0 && n.y >= 0 && n.y < self.size.1 && !self.nodes[n.y as usize][n.x as usize].visited && f(height, self.nodes[n.y as usize][n.x as usize].height) + }); + + // Update the distance of all the neighbours + let distance = self.nodes[current.y as usize][current.x as usize].distance; + for n in neighbours.iter() { + let node = &mut self.nodes[n.y as usize][n.x as usize]; + node.distance = min(node.distance, distance+1); + } + + // Mark current node as visited and remove it from the list of unvisited nodes + self.nodes[current.y as usize][current.x as usize].visited = true; + unvisited.retain(|p| *p != current); + + // We have visited all the nodes, so we are done + if unvisited.len() == 0 { + return; + } + + // Get the next position we are going to visit, this will be the node with the lowest + // distance value + current = *unvisited.iter().reduce(|s, p| { + if self.nodes[p.y as usize][p.x as usize].distance < self.nodes[s.y as usize][s.x as usize].distance { + p + } else { + s + } + }).unwrap(); + + // Remaining nodes are unreachable, we are done + if self.nodes[current.y as usize][current.x as usize].distance == u32::MAX { + return; + } + } + + } + + fn step_required(&self, position: Position) -> u32 { + self.nodes[position.y as usize][position.x as usize].distance + } +} + +fn convert_height(letter: char) -> u32 { + (letter as u8 - b'a') as u32 +} + +// -- Solution -- +pub struct Day; +impl aoc::Solver for Day { + type Output1 = u32; + type Output2 = u32; + + fn day() -> u8 { + 12 + } + + fn part1(input: &str) -> Self::Output1 { + let mut hill = Hill::from_str(input).unwrap(); + // We can go down as many as we want, but only one up + hill.dijkstra(|current, neighbour| neighbour <= current+1); + hill.step_required(hill.end) + } + + fn part2(input: &str) -> Self::Output2 { + let mut hill = Hill::from_str(input).unwrap(); + + // We now want to start from the end position + std::mem::swap(&mut hill.start, &mut hill.end); + + // We are now starting from the end, so we need to flip the condition around + // We can go up as many as we want, but we can only go down one + hill.dijkstra(|current, neighbour| neighbour+1 >= current); + + hill.nodes.iter().flatten().filter(|node| node.height == 0).fold(u32::MAX, |acc, node| min(acc, node.distance)) + } +}