Rust Day 12
This commit is contained in:
parent
e7a06642aa
commit
2f1282652a
7 changed files with 272 additions and 2 deletions
2
rust/Cargo.lock
generated
2
rust/Cargo.lock
generated
|
@ -4,4 +4,4 @@ version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "advent-of-code"
|
name = "advent-of-code"
|
||||||
version = "22.11.2"
|
version = "22.12.2"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "advent-of-code"
|
name = "advent-of-code"
|
||||||
version = "22.11.2"
|
version = "22.12.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
|
@ -67,6 +67,10 @@ path = "src/day10/main.rs"
|
||||||
name = "day11"
|
name = "day11"
|
||||||
path = "src/day11/main.rs"
|
path = "src/day11/main.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "day12"
|
||||||
|
path = "src/day12/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Required for one of the day06 solutions (commented out)
|
# Required for one of the day06 solutions (commented out)
|
||||||
# phf = { version = "0.11.1", features = ["macros"] }
|
# phf = { version = "0.11.1", features = ["macros"] }
|
41
rust/src/day12/input.txt
Normal file
41
rust/src/day12/input.txt
Normal 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
148
rust/src/day12/main.rs
Normal 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(¤t_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(¤t_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[¤t_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
30
rust/src/day12/part_1.rs
Normal 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
42
rust/src/day12/part_2.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
5
rust/src/day12/sample_input.txt
Normal file
5
rust/src/day12/sample_input.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Sabqponm
|
||||||
|
abcryxxl
|
||||||
|
accszExk
|
||||||
|
acctuvwj
|
||||||
|
abdefghi
|
Loading…
Reference in a new issue