You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
2.9 KiB
Rust
113 lines
2.9 KiB
Rust
use std::collections::HashMap;
|
|
use std::collections::HashSet;
|
|
use std::collections::VecDeque;
|
|
|
|
fn main() {
|
|
let contents = std::fs::read_to_string("data.txt").expect("Failed to read file");
|
|
let map = contents
|
|
.lines()
|
|
.map(|x| x.chars().collect::<Vec<char>>())
|
|
.collect::<Vec<Vec<char>>>();
|
|
|
|
let start = find(&map, 'S').unwrap();
|
|
let mut visited: HashSet<(usize, usize)> = HashSet::new();
|
|
|
|
// Part 1
|
|
let distance = explore(&map, start, &mut visited);
|
|
println!("Part 1 distance: {distance}");
|
|
|
|
// Part 2
|
|
let distance = find_all(&map, 'a').into_iter().map(|s| {
|
|
let mut v: HashSet<(usize, usize)> = HashSet::new();
|
|
explore(&map, s, &mut v)
|
|
}).filter(|&d| d != 0).reduce(usize::min).unwrap();
|
|
println!("Part 2 distance {:?}", distance);
|
|
}
|
|
|
|
fn explore(
|
|
map: &Vec<Vec<char>>,
|
|
start: (usize, usize),
|
|
visited: &mut HashSet<(usize, usize)>,
|
|
) -> usize {
|
|
let mut queue = VecDeque::new();
|
|
let mut steps: HashMap<(usize, usize), usize> = HashMap::new();
|
|
|
|
visited.insert(start);
|
|
queue.push_back(start);
|
|
steps.insert(start, 0);
|
|
|
|
while queue.len() > 0 {
|
|
let coord = queue.pop_front().unwrap();
|
|
let mut val = map[coord.0][coord.1];
|
|
if val == 'S' {
|
|
val = 'a';
|
|
}
|
|
|
|
for n in neighbors(&coord, &map) {
|
|
let n_val = map[n.0][n.1];
|
|
let n_val = if n_val == 'E' { 'z' } else { n_val };
|
|
let can_travel = (val <= n_val && n_val as u8 - val as u8 <= 1) || val as u8 > n_val as u8;
|
|
if !visited.contains(&n) && can_travel {
|
|
visited.insert(n);
|
|
queue.push_back(n);
|
|
let distance = steps.get(&coord).unwrap() + 1;
|
|
steps.insert(n, distance);
|
|
|
|
if map[n.0][n.1] == 'E' {
|
|
queue.clear();
|
|
return distance;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
0
|
|
}
|
|
|
|
fn neighbors(coord: &(usize, usize), map: &Vec<Vec<char>>) -> Vec<(usize, usize)> {
|
|
let mut coords = vec![];
|
|
|
|
if coord.0 > 0 {
|
|
coords.push((coord.0 - 1, coord.1));
|
|
}
|
|
if coord.1 > 0 {
|
|
coords.push((coord.0, coord.1 - 1));
|
|
}
|
|
if coord.0 < map.len() - 1 {
|
|
coords.push((coord.0 + 1, coord.1));
|
|
}
|
|
if coord.1 < map[0].len() - 1 {
|
|
coords.push((coord.0, coord.1 + 1));
|
|
}
|
|
|
|
coords
|
|
}
|
|
|
|
fn find(map: &Vec<Vec<char>>, val: char) -> Option<(usize, usize)> {
|
|
for i in 0..map.len() {
|
|
let line = &map[i];
|
|
for j in 0..line.len() {
|
|
if map[i][j] == val {
|
|
return Some((i, j));
|
|
}
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
fn find_all(map: &Vec<Vec<char>>, val: char) -> Vec<(usize, usize)> {
|
|
let mut coords = vec![];
|
|
|
|
for i in 0..map.len() {
|
|
let line = &map[i];
|
|
for j in 0..line.len() {
|
|
if map[i][j] == val {
|
|
coords.push((i, j));
|
|
}
|
|
}
|
|
}
|
|
|
|
coords
|
|
}
|