use std::collections::VecDeque; use itertools::Itertools; pub type Coord = (usize, usize); #[derive(Debug)] pub struct Heightmap { pub map: Vec>, pub rows: usize, pub cols: usize, pub start: Coord, pub target: Coord, } pub fn parse_heightmap(input: &String) -> Heightmap { let mut start = (usize::MAX, usize::MAX); let mut target = (usize::MAX, usize::MAX); let map = input .lines() .enumerate() .map(|(row, l)| { l.as_bytes() .iter() .enumerate() .map(|(col, c)| { if *c == ('S' as u8) { start = (row, col); 0 } else if *c == ('E' as u8) { target = (row, col); 25 } else { (c - ('a' as u8)) as usize } }) .collect_vec() }) .collect_vec(); assert_ne!(start.0, usize::MAX); assert_ne!(target.0, usize::MAX); let rows = map.len(); let cols; if let itertools::MinMaxResult::MinMax(min, max) = map.iter().map(|r| r.len()).minmax() { cols = min; assert_eq!(min, max); } else { panic!("<2 rows?"); } Heightmap { map, cols, rows, start, target, } } pub fn path_steps(map: &Heightmap) -> Option { let mut dist = vec![vec![usize::MAX; map.cols]; map.rows]; dist[map.start.0][map.start.1] = 0; let mut next = VecDeque::new(); next.push_back(map.start); let moves: Vec<(isize, isize)> = vec![(1, 0), (-1, 0), (0, 1), (0, -1)]; while let Some(coord) = next.pop_front() { if coord == map.target { break; } let curr_height = map.map[coord.0][coord.1]; let curr_dist = dist[coord.0][coord.1]; for move_ in &moves { let y = (coord.0 as isize) + move_.0; if y < 0 || y >= map.rows as isize { continue; } let x = (coord.1 as isize) + move_.1; if x < 0 || x >= map.cols as isize { continue; } let y = y as usize; let x = x as usize; if map.map[y][x] <= curr_height + 1 && dist[y][x] > curr_dist + 1 { dist[y][x] = curr_dist + 1; next.push_back((y, x)); } } } let d = dist[map.target.0][map.target.1]; if d < usize::MAX { Some(d) } else { None } }