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::>()) .collect::>>(); 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>, 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<(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>, 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>, 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 }