Day 11, Part 1!
Dijkstra's algorithm. Copied heavily from the Rust docs for its BinaryHeap.
This commit is contained in:
parent
7bceb932c6
commit
d38ba1dd25
2 changed files with 172 additions and 2 deletions
7
2022/day12/Cargo.lock
generated
Normal file
7
2022/day12/Cargo.lock
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "day12"
|
||||
version = "0.1.0"
|
|
@ -1,3 +1,166 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BinaryHeap;
|
||||
use std::{env, fs};
|
||||
|
||||
trait Elevation {
|
||||
fn elevation(&self) -> Option<u32>;
|
||||
}
|
||||
|
||||
impl Elevation for char {
|
||||
fn elevation(&self) -> Option<u32> {
|
||||
let value = match self {
|
||||
'S' => 'a',
|
||||
'E' => 'z',
|
||||
_ => *self
|
||||
};
|
||||
|
||||
Some((value as u32) - 'a' as u32)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Square {
|
||||
symbol: char,
|
||||
up: Option<usize>,
|
||||
down: Option<usize>,
|
||||
left: Option<usize>,
|
||||
right: Option<usize>,
|
||||
}
|
||||
|
||||
impl Square {
|
||||
fn new(symbol: char) -> Square {
|
||||
Square { symbol, up: None, down: None, left: None, right: None }
|
||||
}
|
||||
|
||||
fn elevation(&self) -> u32 {
|
||||
self.symbol.elevation().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
struct State {
|
||||
node: usize,
|
||||
cost: u32,
|
||||
}
|
||||
|
||||
impl Ord for State {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
other.cost.cmp(&self.cost).then_with(|| self.node.cmp(&other.node))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for State {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
/// An implemetation of Dijkstra's algorithm to find the shortest path from start to end and return
|
||||
/// its length.
|
||||
fn find_length_of_shortest_path(squares: &Vec<Square>, start: usize, end: usize) -> u32 {
|
||||
let mut distances: Vec<_> = (0..squares.len()).map(|_| u32::MAX).collect();
|
||||
let mut heap = BinaryHeap::new();
|
||||
|
||||
// Initial state
|
||||
distances[start] = 0;
|
||||
heap.push(State { node: start, cost: 0 });
|
||||
|
||||
while let Some(State { node, cost }) = heap.pop() {
|
||||
if node == end {
|
||||
return cost;
|
||||
}
|
||||
|
||||
if cost > distances[node] {
|
||||
continue;
|
||||
}
|
||||
|
||||
let square = &squares[node];
|
||||
for edge in &[square.up, square.right, square.down, square.left] {
|
||||
if edge.is_none() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let edge = edge.unwrap();
|
||||
|
||||
let next_cost = cost + 1;
|
||||
let next = State { node: edge, cost: next_cost };
|
||||
if next.cost < distances[edge] {
|
||||
heap.push(next);
|
||||
distances[edge] = next_cost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
||||
let filename = args.get(1).expect("Missing filename argument");
|
||||
|
||||
let file_contents = fs::read_to_string(&filename).expect("Unable to read file");
|
||||
let character_grid = file_contents.lines().map(|l| l.chars().collect::<Vec<char>>()).collect::<Vec<Vec<char>>>();
|
||||
|
||||
// Assume a square grid
|
||||
let width = character_grid[0].len();
|
||||
let height = character_grid.len();
|
||||
|
||||
let index_into_squares_array = |x: usize, y: usize| -> usize {
|
||||
y * width + x
|
||||
};
|
||||
|
||||
let mut start: usize = 0;
|
||||
let mut end: usize = 0;
|
||||
let mut squares: Vec<Square> = Vec::new();
|
||||
|
||||
for y in 0..height {
|
||||
for x in 0..width {
|
||||
let symbol = character_grid[y][x];
|
||||
|
||||
match symbol {
|
||||
'S' => start = index_into_squares_array(x, y),
|
||||
'E' => end = index_into_squares_array(x, y),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
let elevation = symbol.elevation().unwrap();
|
||||
let mut square = Square::new(symbol);
|
||||
|
||||
if y > 0 {
|
||||
let up_elevation = character_grid[y-1][x].elevation().unwrap();
|
||||
if up_elevation <= elevation + 1 {
|
||||
square.up = Some(index_into_squares_array(x, y - 1));
|
||||
}
|
||||
}
|
||||
|
||||
if y < height - 1 {
|
||||
let down_elevation = character_grid[y + 1][x].elevation().unwrap();
|
||||
if down_elevation <= elevation + 1 {
|
||||
square.down = Some(index_into_squares_array(x, y + 1));
|
||||
}
|
||||
}
|
||||
|
||||
if x > 0 {
|
||||
let left_elevation = character_grid[y][x - 1].elevation().unwrap();
|
||||
if left_elevation <= elevation + 1 {
|
||||
square.left = Some(index_into_squares_array(x - 1, y));
|
||||
}
|
||||
}
|
||||
|
||||
if x < width - 1 {
|
||||
let right_elevation = character_grid[y][x + 1].elevation().unwrap();
|
||||
if right_elevation <= elevation + 1 {
|
||||
square.right = Some(index_into_squares_array(x + 1, y));
|
||||
}
|
||||
}
|
||||
|
||||
squares.push(square);
|
||||
}
|
||||
}
|
||||
|
||||
dbg!(&squares);
|
||||
|
||||
let length_of_shortest_path = find_length_of_shortest_path(&squares, start, end);
|
||||
println!("Part 1: length of shortest path to location with best signal: {length_of_shortest_path}");
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue