111 lines
3.3 KiB
Rust
111 lines
3.3 KiB
Rust
use std::{collections::{HashMap, HashSet}, cmp};
|
|
|
|
use super::common::Direction;
|
|
|
|
pub fn part_one(input_lines: Vec<String>) -> String {
|
|
|
|
let mut map: Vec<Vec<i32>> = Vec::new();
|
|
for line in input_lines {
|
|
let mut row: Vec<i32> = 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<Vec<i32>>,
|
|
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))
|
|
} |