From 729308742a123c6781cb2505a4fd55ae74036db4 Mon Sep 17 00:00:00 2001 From: Dory Date: Sun, 17 Mar 2024 16:20:10 -0700 Subject: [PATCH] d12p1 --- day12/src/main.rs | 90 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 19 deletions(-) diff --git a/day12/src/main.rs b/day12/src/main.rs index de79eaa..c04f988 100644 --- a/day12/src/main.rs +++ b/day12/src/main.rs @@ -2,30 +2,82 @@ use std::env; use std::fs::File; use std::io::{self, BufRead}; use std::collections::BinaryHeap; -use std::cmp::Reverse; +use std::cmp::max; -fn find(haystack: &Vec>, needle: T) -> (usize, usize) { - // I just wanna play around with iters; there are better ways... - haystack.iter().enumerate() - .map(|(i, &ref row)| - (i, row.iter().enumerate() - .filter(|(_j, &ref c)| *c == needle) - .map(|(j, _c)| j) - .collect::>())) - .filter(|(_i, row)| !row.is_empty()) - .map(|(i, row)| (i, *row.iter().nth(0).unwrap())) - .nth(0).unwrap() +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 map: Vec> = io::BufReader::new(file).lines().flatten() - .map(|line| line.chars().map(|c| c as u8).collect()) - .collect(); - let (starti, startj) = find(&map, 'S' as u8); - let (endi, endj) = find(&map, 'E' as u8); + let mut map: Vec> = Vec::new(); + let mut queue = BinaryHeap::new(); + let (mut start, mut end) = ((0, 0), (0, 0)); - println!("{:?}", map); - println!("{:?}, {:?} -> {:?}, {:?}", starti, startj, endi, endj); + // 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); }