use std::{collections::{HashMap, HashSet}, cmp}; use super::common::Direction; pub fn part_one(input_lines: Vec) -> String { let mut map: Vec> = Vec::new(); for line in input_lines { let mut row: Vec = Vec::new(); for c in line.chars() { row.push(c.to_digit(10).unwrap() as i32); } map.push(row); } let mut cache: HashMap<(i32, i32), i32> = HashMap::new(); let cost = min( min_cost_path(&map, &mut cache, HashSet::new(), Direction::Right, 0, 0, 0), min_cost_path(&map, &mut cache, HashSet::new(), Direction::Down, 0, 0, 0), i32::MAX, ); cost.to_string() } fn min_cost_path( map: &Vec>, cache: &mut HashMap<(i32, i32), i32>, mut current_path: HashSet<(i32, i32)>, dir: Direction, step_count: i32, i: i32, j: i32) -> i32 { println!("{}: {} {} {:?}", step_count, i, j, dir); if i < 0 || j < 0 || i >= map.len() as i32 || j >= map[0].len() as i32 { return i32::MAX; } if step_count >= 3 { return i32::MAX; } if current_path.contains(&(i,j)) { return i32::MAX; } else { current_path.insert((i,j)); } if i == map.len() as i32 - 1 && j == map[0].len() as i32 - 1 { println!("Final path: {:?}", current_path); return map[i as usize][j as usize]; } if cache.contains_key(&(i,j)) { return *cache.get(&(i,j)).unwrap(); } let mut cost = 0; if i != 0 && j != 0 { cost = map[i as usize][j as usize]; } let res: i32; match dir { Direction::Up => { res = min( min_cost_path(map, cache, current_path.clone(), Direction::Up, step_count + 1, i - 1, j), min_cost_path(map, cache, current_path.clone(), Direction::Left, 0, i, j - 1), min_cost_path(map, cache, current_path.clone(), Direction::Right, 0, i, j + 1) ); }, Direction::Down => { res = min( min_cost_path(map, cache, current_path.clone(), Direction::Down, step_count + 1, i + 1, j), min_cost_path(map, cache, current_path.clone(), Direction::Left, 0, i, j - 1), min_cost_path(map, cache, current_path.clone(), Direction::Right, 0, i, j + 1) ); }, Direction::Left => { res = min( min_cost_path(map, cache, current_path.clone(), Direction::Left, step_count + 1, i, j - 1), min_cost_path(map, cache, current_path.clone(), Direction::Up, 0, i - 1, j), min_cost_path(map, cache, current_path.clone(), Direction::Down, 0, i + 1, j) ); }, Direction::Right => { res = min( min_cost_path(map, cache, current_path.clone(), Direction::Right, step_count + 1, i, j + 1), min_cost_path(map, cache, current_path.clone(), Direction::Up, 0, i - 1, j), min_cost_path(map, cache, current_path.clone(), Direction::Down, 0, i + 1, j) ); }, } current_path.remove(&(i, j)); if let Some(new_cost) = cost.checked_add(res) { cost = new_cost; } else { cost = i32::MAX; } cache.insert((i,j), cost); cost } fn min(a: i32, b: i32 ,c: i32) -> i32 { cmp::min(a, cmp::min(b, c)) }