120 lines
3.3 KiB
Rust
120 lines
3.3 KiB
Rust
|
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);
|
||
|
}
|