use std::env; use std::fs::File; use std::io::{self, BufRead}; use std::collections::BinaryHeap; use std::cmp::max; fn get(map: &Vec>, coord: (usize, usize)) -> i64 { map[coord.0 as usize][coord.1 as usize] } fn main() { let file = File::open(&env::args().nth(1).unwrap()).unwrap(); let mut map: Vec> = Vec::new(); let mut queue = BinaryHeap::new(); let (mut start, mut end) = ((0, 0), (0, 0)); // parse input for (i, line) in io::BufReader::new(file).lines().flatten().enumerate() { let mut row: Vec = Vec::new(); for (j, c) in line.chars().enumerate() { match c { 'S' => { start = (i, j); row.push('a' as i64); }, 'E' => { end = (i, j); row.push('z' as i64); }, c => row.push(c as i64), } } map.push(row); } let (height, width) = (map.len(), map[0].len()); let mut costs = vec![vec![i64::MAX; width]; height]; let heur: Vec> = (0..height) .map(|i| (0..width) .map(|j| max((i.abs_diff(end.0) + j.abs_diff(end.1)) as i64, get(&map, end) - get(&map, (i, j)))) .collect()) .collect(); queue.push((-heur[start.0][start.1], start)); costs[start.0][start.1] = 0; // A* let answer = loop { // no route if queue.is_empty() { break None; } let (_, (i, j)) = queue.pop().unwrap(); let cost = get(&costs, (i, j)); // found destination if (i, j) == end { break Some(cost); } // handle neighbors let neighbors = [ (i as i64, (j as i64) - 1), (i as i64, (j as i64) + 1), ((i as i64) - 1, j as i64), ((i as i64) + 1, j as i64)]; for (nexti, nextj) in neighbors { if nexti < 0 || nextj < 0 || nexti >= height as i64 || nextj >= width as i64 || map[nexti as usize][nextj as usize] > map[i][j] + 1 { continue; } let nexti: usize = nexti as usize; let nextj: usize = nextj as usize; let new_cost = cost + 1; if new_cost < costs[nexti][nextj] { costs[nexti][nextj] = new_cost; queue.retain(|(_, (ri, rj))| *ri != nexti || *rj != nextj); queue.push((-new_cost - heur[nexti][nextj], (nexti, nextj))); } } }; println!("= {:?}", answer); }