Rust Day 12

This commit is contained in:
Tobias Berger 2022-12-12 16:46:32 +01:00
parent e7a06642aa
commit 2f1282652a
Signed by: toby
GPG key ID: 2D05EFAB764D6A88
7 changed files with 272 additions and 2 deletions

2
rust/Cargo.lock generated
View file

@ -4,4 +4,4 @@ version = 3
[[package]]
name = "advent-of-code"
version = "22.11.2"
version = "22.12.2"

View file

@ -1,6 +1,6 @@
[package]
name = "advent-of-code"
version = "22.11.2"
version = "22.12.2"
edition = "2021"
resolver = "2"
@ -67,6 +67,10 @@ path = "src/day10/main.rs"
name = "day11"
path = "src/day11/main.rs"
[[bin]]
name = "day12"
path = "src/day12/main.rs"
[dependencies]
# Required for one of the day06 solutions (commented out)
# phf = { version = "0.11.1", features = ["macros"] }

41
rust/src/day12/input.txt Normal file
View file

@ -0,0 +1,41 @@
abcccccccccccccccccaaaaaaaaccccccacccaaccccccccccccccccccaaaaaaaaaacccccccccccccccccccccccccccccccaaaaaaccccccccccccccccccccccccccccccccccaaaaa
abccccccccccccccccccaaaaacccccccaaaaaaacccccccccccaaccaaaaaaaaaaaaaccccccccccccccccccccccccccccccccaaaaacccccccccccccccccccccccccccccccccaaaaaa
abccccccccccccaaccccaaaaaacccccccaaaaaaaaccccccacaaaccaaaaaaaaaaaaaaaccccccccccccccccccaaacccccccaaaaaaaccccccccccccccccaaaccccccccccccccaaaaaa
abccccccccacccaaccccaaaaaacccccccaaaaaaaaaccccaaaaaaaaacaaaaaaaaaaaaacccccccccccccccccccaacccccccaaaaaaaacccccccccccccccaaaccccccccccccccaccaaa
abaacccccaaaaaaaccccaaaccacccccccaaaaaaaaaccccaaaaaaaaccccaaaaaaaaaaaccccccccccccccccaacaaaaaccccaaaaaaaacccccccccccccccaaacccccccccccccccccaaa
abaaccccccaaaaaaaacccccccccccccccaaaaaaaaccccccaaaaaacccccaaaacaaaaccccccccccccccccccaaaaaaaaccccccaaacaccccccccccccccccaaakccaaaccccccccccccaa
abaaacccccaaaaaaaaaccccccccccccccaaaaaaacccccccaaaaaccccccaaaccaaaaccccccccccccaacacccaaaaaccccccccaaacccccccccccccacacckkkkkkkaacccccccccccccc
abaaacccccaaaaaaaaaccccccccccccccaccaaaaaccccccaaaaaacccccaaacaaaccccccccccccccaaaaccccaaaaacccccccccccccccccccccccaaaakkkkkkkkkacccaaaccaccccc
abacacccccaaaaaaaccccccccccccccccccccaaaaaaaccccccaaccccccaaaaaaaaccccccccccccaaaaacccaaacaacccccccccccccccccccccccaajkkkkppkkkkccccaaaaaaccccc
abacccccccaaaaaaacccccccccccccccccccaaaaaaaaccccccccccccccccaaaaaaccccccccccccaaaaaacccaacccccccccccccccccccccccccccjjkkooppppkllccccaaaaaccccc
abccccccccaccaaaccccccccccccccccccccaaaaaaaacccccccccccccccccaaaaaccccccccccccacaaaacccccccccccccccccccccccccccccjjjjjjoooppppklllcacaaaaaccccc
abcccaacccccccaaacccccccccccccccccccaaaaaaacccccccccccccccccaaaaacccccccccccccccaacaccccccccccccccccccccccccccjjjjjjjjoooopuppplllcccccaaaacccc
abcccaacccccccccccccccccaaacccccccccccaaaaaaccccccaaaaacccccaaaaaccccccccccccaaacaaacccccaaaccccccccccccccccijjjjjjjjooouuuuuppllllcccccaaacccc
abaaaaaaaaccccccccccccccaaaaccccccccccaacaaaccccccaaaaaccccccccccccccccccccccaaaaaaacccccaaacacccccccccccccciijjoooooooouuuuuppplllllccccaccccc
abaaaaaaaaccccccccccccccaaaaccccccccccaacccccccccaaaaaacccccccccccccccccccccccaaaaaacccaaaaaaaacccccccccccciiiqqooooooouuuxuuuppplllllccccccccc
abccaaaaccccccccccccccccaaaccccccccccccccccccccccaaaaaacccccccccccccccccccccccaaaaaaaccaaaaaaaacccccccccccciiiqqqqtttuuuuxxxuupppqqllllmccccccc
abcaaaaacccaaaccccccccccccccccccccccccaccccccccccaaaaaacccccccccccccccccccccaaaaaaaaaaccaaaaaaccccccccccccciiiqqqtttttuuuxxxuuvpqqqqmmmmccccccc
abcaacaaaccaaacaaccccccccccccccccccccaaaacaaaccccccaacccaaaaacccccccccccccccaaaaaaaaaacccaaaaacccaaaccccccciiiqqttttxxxxxxxyuvvvvqqqqmmmmcccccc
abcacccaaccaaaaaaccccccccccccccccccccaaaaaaaacccccccccccaaaaacccccccccccccccaaacaaacccccaaaaaaccaaaacccccaaiiiqqtttxxxxxxxxyyvvvvvvqqqmmmdddccc
abcccccccaaaaaaaccccccccccccccccccccccaaaaaaaaacccccccccaaaaaaccccccccccccccccccaaaccccccaacccccaaaacccaaaaiiiqqqttxxxxxxxyyyyyyvvvqqqmmmdddccc
SbccccccccaaaaaccccccccaacaaccccccccaaaaaaaaaaccccccccccaaaaaaccccccccccccaaacccaaccccccccccccccaaaacccaaaaaiiiqqtttxxxxEzzyyyyvvvvqqqmmmdddccc
abaccccccccaaaaacccccccaaaaacccccccaaaaaaaaaaaccccccccccaaaaaaccccccccccaaaaaacccccccccccccccccccccccccaaaaaiiiqqqtttxxxyyyyyyvvvvqqqmmmdddcccc
abaacccccccaacaaaccccccaaaaaacccccccaaaaaaaaaaccccccccccccaaacccccccccccaaaaaaccccccccccccccccccccccccccaaaahhhqqqqttxxyyyyyyvvvvqqqmmmddddcccc
abaccccccccaaccccccccccaaaaaacccaacaaccaaaaaaaaaccccccccccccccccccccccccaaaaaaccccccccccccccccccccccccccaaaachhhqqtttxwyyyyyywvrqqqmmmmdddccccc
abaaaccccccccccccccccccaaaaaacccaaaaaccaaaaacaaaccccccccccccccccccccccccaaaaaccccaaaaccccaaaccccccccccccccccchhhppttwwwywwyyywwrrrnmmmdddcccccc
abaaaccccccccccccccccccccaaaccccaaaaaacaaaaaaaaaccccccccaaacccccccccccccaaaaaccccaaaaccccaaaccccccccccccccccchhpppsswwwwwwwwywwrrrnnndddccccccc
abaaacccccccccccccccccccccccccccaaaaaacccaaaaaacccccccccaaaaacccccaacccccccccccccaaaacaaaaaaaaccccccccccccccchhpppsswwwwsswwwwwrrrnneeddccccccc
abaccccccccaaaacccccccccccccccccaaaaaaccccaaaaaaaacccccaaaaaaccaacaaacccccccccccccaaccaaaaaaaaccccccccccccccchhpppssssssssrwwwwrrrnneeecaaccccc
abaccccccccaaaacccccccccccccccccccaaaccccaaaaaaaaacccccaaaaaaccaaaaaccccccccccccccccccccaaaaacccccccccccccccchhpppssssssssrrrwrrrnnneeeaaaccccc
abcccccccccaaaacccccccccccccccccccccccccaaaaaaaaaaccccccaaaaacccaaaaaacccccccccccccccccaaaaaacccccccccccccccchhpppppsssooorrrrrrrnnneeeaaaccccc
abcccccccccaaaccccccccccccccccccccccccccaaacaaacccccccccaacaacaaaaaaaacccccccccccccccccaaaaaacaaccccccccccccchhhppppppoooooorrrrnnneeeaaaaacccc
abccccccccccccccccccccccccccccccccccccccccccaaaccaaaacccccccccaaaaacaaccccaacccccccccacaaaaaacaaccccccccccccchhhgpppppoooooooonnnnneeeaaaaacccc
abcccccccaacccccccccccccccccccccccccccccccccaaacaaaaaccccccccccacaaaccccccaacccccccccaacaaaaaaaaaaacccccaaccccgggggggggggfooooonnneeeeaaaaacccc
abcccccccaaacaaccccccccccccaacccccccccccccccccccaaaaaaccccaacccccaaacccaaaaaaaaccccccaaaaacaaaaaaaaccccaaacccccggggggggggfffooonneeeecaaacccccc
abcccccccaaaaaaccccaacccccaaacccccccccccccccccccaaaaaaccccaaaccccccccccaaaaaaaacccccccaaaaaccaaaaccccaaaaaaaacccggggggggfffffffffeeeecaaccccccc
abcccccaaaaaaaccaaaaacaaaaaaacccccccccccccccccccaaaaacccccaaaacccaaccccccaaaacccccccaaaaaaaacaaaaacccaaaaaaaaccccccccccaaaffffffffecccccccccccc
abcaaacaaaaaaacccaaaaaaaaaaaaaaaccccccccccccccccccaaacccccaaaacaaaacaacccaaaaaccccccaaaaaaaaaaaaaaccccaaaaaacccccccccccaaacaafffffccccccccccaaa
abaaaacccaaaaaaccaaaaacaaaaaaaaaccccccccccccaaacccccccccccaaaaaaaaacaaccaaacaacccccccccaacccaaccaaccccaaaaaaccccccccccaaaaccaaacccccccccccccaaa
abaaaacccaacaaacaaaaacccaaaaaaacccccccccccccaaaacccccccccaaaaaaaaaaaaaccaacccacccccccccaacccccccccccccaaaaaaccccccccccaaacccccccccccccccccccaaa
abcaaacccaacccccccaaaccaaaaaacccccccccccccccaaaaccccccaaaaaaaaaaaaaaaaaaccccccccccccccccccccccccccccccaaccaaccccccccccaaaccccccccccccccccaaaaaa
abcccccccccccccccccccccaaaaaaaccccccccccccccaaacccccccaaaaaaaaaaaaaaaaaacccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaaaaaa

148
rust/src/day12/main.rs Normal file
View file

@ -0,0 +1,148 @@
const INPUT: &str = include_str!("input.txt");
mod part_1;
use std::collections::{HashMap, HashSet};
use part_1::part_1;
mod part_2;
use part_2::part_2;
#[derive(Clone, Debug)]
pub(crate) struct ParsedInput {
pub(crate) grid: HashMap<(usize, usize), u8>,
pub(crate) start_position: (usize, usize),
pub(crate) end_position: (usize, usize),
}
fn get_front(frontier: &HashMap<(usize, usize), usize>) -> (usize, usize) {
let mut items = frontier.iter().collect::<Vec<_>>();
items.sort_unstable_by(|left, right| left.1.cmp(right.1));
*items[0].0
}
fn neighbors(
position: (usize, usize),
grid: &HashMap<(usize, usize), u8>,
) -> HashSet<(usize, usize)> {
let (x, y) = position;
let height = grid[&position];
[
(x + 1, y),
(x.saturating_sub(1), y),
(x, y + 1),
(x, y.saturating_sub(1)),
]
.iter()
.filter_map(|neighbor_position| {
if *neighbor_position == position {
None
} else {
grid.get(neighbor_position).and_then(|&neighbor_height| {
(neighbor_height <= height + 1).then_some(*neighbor_position)
})
}
})
.collect()
}
fn reconstruct_path(
end_position: (usize, usize),
start_position: (usize, usize),
came_from: &HashMap<(usize, usize), Option<(usize, usize)>>,
) -> Option<Vec<(usize, usize)>> {
let mut current_position = end_position;
let mut path = vec![];
while current_position != start_position {
path.push(current_position);
if let Some(next) = came_from.get(&current_position) {
current_position = next.unwrap();
} else {
return None;
}
}
Some(path)
}
pub(crate) fn dijkstra(
grid: &HashMap<(usize, usize), u8>,
start_position: (usize, usize),
end_position: (usize, usize),
) -> Option<Vec<(usize, usize)>> {
let mut frontier = HashMap::new();
frontier.insert(start_position, 0);
let mut came_from = HashMap::<(_, _), _>::new();
let mut cost_so_far = HashMap::<(_, _), _>::new();
came_from.insert(start_position, None);
cost_so_far.insert(start_position, 0);
// let mut step = 0;
while !frontier.is_empty() {
let current_position = get_front(&frontier);
// step += 1;
// println!("Step {step}: {current_position:?}");
frontier.remove(&current_position);
if current_position == end_position {
// println!("Found path after {step} steps");
break;
}
let neighbors = neighbors(current_position, grid);
// println!("Step {step}: neighbors = {neighbors:?}");
for neighbor in neighbors {
let new_cost = cost_so_far[&current_position] + 1;
let old_cost = cost_so_far.get(&neighbor);
if old_cost.is_none() || new_cost < *old_cost.unwrap() {
cost_so_far.insert(neighbor, new_cost);
frontier.insert(neighbor, new_cost);
came_from.insert(neighbor, Some(current_position));
}
}
}
reconstruct_path(end_position, start_position, &came_from)
}
fn parse_input(input: &'static str) -> ParsedInput {
let mut start_position = (0, 0);
let mut end_position = (0, 0);
let matrix = input
.lines()
.enumerate()
.flat_map(|(y, line)| {
line.bytes()
.enumerate()
.map(|(x, byte)| match byte {
b'S' => {
start_position = (x, y);
((x, y), 0)
}
b'E' => {
end_position = (x, y);
((x, y), b'z' - b'a')
}
_ => ((x, y), byte - b'a'),
})
.collect::<Vec<_>>()
})
.collect();
ParsedInput {
grid: matrix,
start_position,
end_position,
}
}
pub fn main() {
let input = parse_input(INPUT);
part_1(&input);
part_2(&input);
}

30
rust/src/day12/part_1.rs Normal file
View file

@ -0,0 +1,30 @@
use crate::{dijkstra, ParsedInput};
pub(crate) fn part_1(input: &ParsedInput) -> usize {
let ParsedInput {
start_position,
end_position,
grid,
} = input;
let path_length = dijkstra(grid, *start_position, *end_position).expect("All inputs should be solvable").len();
// The first step doesn't count, ig?
println!("Part 1: {}", path_length);
path_length
}
#[cfg(test)]
mod tests {
const SAMPLE_INPUT: &str = include_str!("sample_input.txt");
#[test]
fn test_with_solution() {
assert_eq!(super::part_1(&crate::parse_input(crate::INPUT)), 462);
}
#[test]
fn test_with_sample_solution() {
assert_eq!(super::part_1(&crate::parse_input(SAMPLE_INPUT)), 31);
}
}

42
rust/src/day12/part_2.rs Normal file
View file

@ -0,0 +1,42 @@
use crate::{dijkstra, ParsedInput};
pub(crate) fn part_2(input: &ParsedInput) -> usize {
let ParsedInput {
start_position: _,
end_position,
grid,
} = input;
let mut idx = 0;
let shortest_path_length = grid
.iter()
.filter_map(|(position, height)| {
println!("{idx}");
idx += 1;
if *height != 0 {
None
} else {
dijkstra(grid, *position, *end_position)
}
})
.fold(usize::MAX, |accumulator, path| accumulator.min(path.len()));
// The first step doesn't count, ig?
println!("Part 2: {}", shortest_path_length);
shortest_path_length
}
#[cfg(test)]
mod tests {
const SAMPLE_INPUT: &str = include_str!("sample_input.txt");
#[test]
fn test_with_solution() {
assert_eq!(super::part_2(&crate::parse_input(crate::INPUT)), 451);
}
#[test]
fn test_with_sample_solution() {
assert_eq!(super::part_2(&crate::parse_input(SAMPLE_INPUT)), 29);
}
}

View file

@ -0,0 +1,5 @@
Sabqponm
abcryxxl
accszExk
acctuvwj
abdefghi