aoc22/src/day12/main.rs

120 lines
3.3 KiB
Rust
Raw Normal View History

2022-12-12 11:10:18 +01:00
use std::collections::{HashMap, VecDeque};
use base::read_file;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
struct Pos(usize, usize);
impl Pos {
fn left(&self) -> Self { Pos(self.0 - 1, self.1) }
fn right(&self) -> Self { Pos(self.0 + 1, self.1) }
fn up(&self) -> Self { Pos(self.0, self.1 - 1) }
fn down(&self) -> Self { Pos(self.0, self.1 + 1) }
fn getHeight(&self, tiles: &Vec<Vec<u8>>) -> u8 {
return tiles[self.1][self.0];
}
}
fn get_positions(tiles: &Vec<Vec<u8>>, pos: Pos, width: usize, height: usize) -> Vec<Pos> {
let current_height = pos.getHeight(&tiles);
let mut positions = vec![];
if pos.0 > 0 {
positions.push(pos.left())
}
if pos.1 > 0 {
positions.push(pos.up());
}
if pos.0 < width - 1 {
positions.push(pos.right());
}
if pos.1 < height - 1 {
positions.push(pos.down());
}
let mut i = 0;
while i < positions.len() {
if positions[i].getHeight(&tiles) > current_height + 1 {
let _ = positions.remove(i);
} else {
i += 1;
}
}
positions
}
fn pathfinding_dijkstra(start: Pos, end: Pos, tiles: &Vec<Vec<u8>>) -> Option<u32> {
let height = tiles.len();
let width = tiles[0].len();
let mut discovered = HashMap::<Pos, Option<Pos>>::new();
discovered.insert(start, None);
let mut to_search = VecDeque::new();
to_search.push_front(start);
while !to_search.is_empty() {
if let Some(u) = to_search.pop_back() {
for position in get_positions(tiles, u, width, height) {
if let None = discovered.get(&position) {
discovered.insert(position, Some(u));
to_search.push_front(position);
}
}
}
}
let mut position = end;
let mut counter = 0;
loop {
if let Some(pre) = discovered.get(&position) {
if let Some(pos) = pre {
position = *pos;
counter += 1;
} else {
break;
}
} else {
return None;
}
}
Some(counter)
}
fn main() {
let lines = read_file("day12.txt");
let mut start = None;
let mut end = None;
let mut tiles = vec![];
let mut zero_height_tiles = vec![];
for (y, line) in lines.iter().enumerate() {
tiles.push(vec![]);
for (x, c) in line.bytes().enumerate() {
match c {
83 => {
let pos = Pos(x, y);
start = Some(pos);
zero_height_tiles.push(pos);
tiles[y].push(0);
}
69 => {
end = Some(Pos(x, y));
tiles[y].push(25);
}
_ => {
let height = c - 'a' as u8;
tiles[y].push(height);
if height == 0 {
zero_height_tiles.push(Pos(x, y));
}
}
}
}
}
println!("Task 1: {}", pathfinding_dijkstra(start.unwrap(), end.unwrap(), &tiles).unwrap());
let task2 = zero_height_tiles.iter().filter_map(|start| pathfinding_dijkstra(*start, end.unwrap(), &tiles)).min().unwrap();
println!("Task 2: {}", task2);
}