Day 12 part 2
This commit is contained in:
parent
4cb8102d64
commit
3bd3646290
|
@ -3,11 +3,100 @@ use std::collections::HashSet;
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
type Input = (Vec<Vec<u8>>, (usize, usize), (usize, usize));
|
struct Input {
|
||||||
|
map: Vec<Vec<u8>>,
|
||||||
|
start: (usize, usize),
|
||||||
|
end: (usize, usize),
|
||||||
|
}
|
||||||
|
|
||||||
type Answer = usize;
|
type Answer = usize;
|
||||||
|
|
||||||
|
impl Input {
|
||||||
|
fn shortest_path_length(&self, s: Option<(usize, usize)>) -> usize {
|
||||||
|
let s = s.unwrap_or(self.start);
|
||||||
|
let mut open_set = HashSet::<(usize, usize)>::from([s]);
|
||||||
|
let mut came_from = HashMap::<(usize, usize), (usize, usize)>::new();
|
||||||
|
let mut cheapest_for = HashMap::<(usize, usize), i64>::from([(s, 0)]);
|
||||||
|
let mut guess_score = HashMap::<(usize, usize), i64>::from([(s, 0)]);
|
||||||
|
|
||||||
|
let h = self.map.len();
|
||||||
|
let w = self.map[0].len();
|
||||||
|
|
||||||
|
// guess_score.get(&(y, x)).unwrap_or(&i64::MAX).clone()
|
||||||
|
while open_set.len() > 0 {
|
||||||
|
let (mut y, mut x) = open_set
|
||||||
|
.iter()
|
||||||
|
.min_by(|(y1, x1), (y2, x2)| {
|
||||||
|
guess_score
|
||||||
|
.get(&(*y1, *x1))
|
||||||
|
.unwrap_or(&i64::MAX)
|
||||||
|
.cmp(&guess_score.get(&(*y2, *x2)).unwrap_or(&i64::MAX))
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if (y, x) == self.end {
|
||||||
|
let mut n = 0;
|
||||||
|
while let Some((ny, nx)) = came_from.get(&(y, x)) {
|
||||||
|
y = *ny;
|
||||||
|
x = *nx;
|
||||||
|
n += 1;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
open_set.remove(&(y, x));
|
||||||
|
let c = self.map[y][x];
|
||||||
|
let mut potential_neighbors = vec![];
|
||||||
|
if y > 0 {
|
||||||
|
potential_neighbors.push((y - 1, x));
|
||||||
|
}
|
||||||
|
if y < h - 1 {
|
||||||
|
potential_neighbors.push((y + 1, x));
|
||||||
|
}
|
||||||
|
if x > 0 {
|
||||||
|
potential_neighbors.push((y, x - 1));
|
||||||
|
}
|
||||||
|
if x < w - 1 {
|
||||||
|
potential_neighbors.push((y, x + 1));
|
||||||
|
}
|
||||||
|
for (ny, nx) in potential_neighbors
|
||||||
|
.iter()
|
||||||
|
.filter(|(y, x)| (self.map[*y][*x] as i32) - (c as i32) <= 1)
|
||||||
|
{
|
||||||
|
let ny = ny.clone();
|
||||||
|
let nx = nx.clone();
|
||||||
|
let score = guess_score.get(&(y, x)).unwrap_or(&i64::MAX).clone() + 1;
|
||||||
|
let ns = guess_score.get(&(ny, nx)).unwrap_or(&i64::MAX).clone();
|
||||||
|
if score < ns {
|
||||||
|
came_from.insert((ny, nx), (y, x));
|
||||||
|
guess_score.insert((ny, nx), score);
|
||||||
|
cheapest_for.insert((ny, nx), score + 1);
|
||||||
|
open_set.insert((ny, nx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut distances: Vec<Vec<usize>> = vec![];
|
||||||
|
let mut previous_bests: Vec<Vec<Option<(usize, usize)>>> = vec![];
|
||||||
|
for y in 0..self.map.len() {
|
||||||
|
let mut row_distances = vec![];
|
||||||
|
let mut row_previous_bests = vec![];
|
||||||
|
for _ in 0..self.map[y].len() {
|
||||||
|
row_distances.push(std::usize::MAX);
|
||||||
|
row_previous_bests.push(None);
|
||||||
|
}
|
||||||
|
distances.push(row_distances);
|
||||||
|
previous_bests.push(row_previous_bests);
|
||||||
|
}
|
||||||
|
distances[s.0][s.1] = 0;
|
||||||
|
|
||||||
|
// no path found
|
||||||
|
usize::MAX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn processed_input(input: &str) -> Input {
|
fn processed_input(input: &str) -> Input {
|
||||||
let mut result = vec![];
|
let mut map = vec![];
|
||||||
let mut start = (0, 0);
|
let mut start = (0, 0);
|
||||||
let mut end = (0, 0);
|
let mut end = (0, 0);
|
||||||
let lines = input
|
let lines = input
|
||||||
|
@ -30,110 +119,37 @@ fn processed_input(input: &str) -> Input {
|
||||||
c => row.push(c as u8 - 'a' as u8),
|
c => row.push(c as u8 - 'a' as u8),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.push(row)
|
map.push(row)
|
||||||
}
|
}
|
||||||
return (result, start, end);
|
return Input { map, start, end };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part1(input: &Input) -> Answer {
|
fn part1(input: &Input) -> Answer {
|
||||||
let mut open_set = HashSet::<(usize, usize)>::from([input.1]);
|
input.shortest_path_length(None)
|
||||||
let mut came_from = HashMap::<(usize, usize), (usize, usize)>::new();
|
|
||||||
let mut cheapest_for = HashMap::<(usize, usize), i64>::from([(input.1, 0)]);
|
|
||||||
let mut guess_score = HashMap::<(usize, usize), i64>::from([(input.1, 0)]);
|
|
||||||
|
|
||||||
let h = input.0.len();
|
|
||||||
let w = input.0[0].len();
|
|
||||||
|
|
||||||
// guess_score.get(&(y, x)).unwrap_or(&i64::MAX).clone()
|
|
||||||
while open_set.len() > 0 {
|
|
||||||
let (mut y, mut x) = open_set
|
|
||||||
.iter()
|
|
||||||
.min_by(|(y1, x1), (y2, x2)| {
|
|
||||||
guess_score
|
|
||||||
.get(&(*y1, *x1))
|
|
||||||
.unwrap_or(&i64::MAX)
|
|
||||||
.cmp(&guess_score.get(&(*y2, *x2)).unwrap_or(&i64::MAX))
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if (y, x) == input.2 {
|
|
||||||
let mut n = 0;
|
|
||||||
while let Some((ny, nx)) = came_from.get(&(y, x)) {
|
|
||||||
y = *ny;
|
|
||||||
x = *nx;
|
|
||||||
n += 1;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
open_set.remove(&(y, x));
|
|
||||||
let c = input.0[y][x];
|
|
||||||
let mut potential_neighbors = vec![];
|
|
||||||
if y > 0 {
|
|
||||||
potential_neighbors.push((y - 1, x));
|
|
||||||
}
|
|
||||||
if y < h - 1 {
|
|
||||||
potential_neighbors.push((y + 1, x));
|
|
||||||
}
|
|
||||||
if x > 0 {
|
|
||||||
potential_neighbors.push((y, x - 1));
|
|
||||||
}
|
|
||||||
if x < w - 1 {
|
|
||||||
potential_neighbors.push((y, x + 1));
|
|
||||||
}
|
|
||||||
for (ny, nx) in potential_neighbors
|
|
||||||
.iter()
|
|
||||||
.filter(|(y, x)| (input.0[*y][*x] as i32) - (c as i32) <= 1)
|
|
||||||
{
|
|
||||||
let ny = ny.clone();
|
|
||||||
let nx = nx.clone();
|
|
||||||
let score = guess_score.get(&(y, x)).unwrap_or(&i64::MAX).clone() + 1;
|
|
||||||
let ns = guess_score.get(&(ny, nx)).unwrap_or(&i64::MAX).clone();
|
|
||||||
if score < ns {
|
|
||||||
came_from.insert((ny, nx), (y, x));
|
|
||||||
guess_score.insert((ny, nx), score);
|
|
||||||
cheapest_for.insert((ny, nx), score + 1);
|
|
||||||
open_set.insert((ny, nx));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut distances: Vec<Vec<usize>> = vec![];
|
|
||||||
let mut previous_bests: Vec<Vec<Option<(usize, usize)>>> = vec![];
|
|
||||||
for y in 0..input.0.len() {
|
|
||||||
let mut row_distances = vec![];
|
|
||||||
let mut row_previous_bests = vec![];
|
|
||||||
for _ in 0..input.0[y].len() {
|
|
||||||
row_distances.push(std::usize::MAX);
|
|
||||||
row_previous_bests.push(None);
|
|
||||||
}
|
|
||||||
distances.push(row_distances);
|
|
||||||
previous_bests.push(row_previous_bests);
|
|
||||||
}
|
|
||||||
distances[input.1 .0][input.1 .1] = 0;
|
|
||||||
|
|
||||||
// no path found
|
|
||||||
usize::MAX
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part2(input: &Input) -> Answer {
|
fn part2(input: Input) -> Answer {
|
||||||
let mut possible_starts = HashSet::<(usize, usize)>::from([input.1]);
|
let mut possible_starts = HashSet::<(usize, usize)>::from([input.start]);
|
||||||
for y in 0..input.0.len() {
|
for y in 0..input.map.len() {
|
||||||
for x in 0..input.0[y].len() {
|
for x in 0..input.map[y].len() {
|
||||||
if input.0[y][x] == 0 {
|
if input.map[y][x] == 0 {
|
||||||
possible_starts.insert((y, x));
|
possible_starts.insert((y, x));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
possible_starts.iter().map(|s| part1((input.0, s, input.2))
|
|
||||||
}
|
possible_starts
|
||||||
|
.iter()
|
||||||
|
.map(|s| input.shortest_path_length(Some(*s)))
|
||||||
|
.min()
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let input_text = common::day_input(12);
|
let input_text = common::day_input(12);
|
||||||
eprintln!("{}\n\nAbove is your input file.\n\n", input_text);
|
eprintln!("{}\n\nAbove is your input file.\n\n", input_text);
|
||||||
let input = processed_input(&input_text);
|
let input = processed_input(&input_text);
|
||||||
common::show_answers(&part1(&input), &part2(&input))
|
common::show_answers(&part1(&input), &part2(input))
|
||||||
// common::show_both_answers(&both_parts(&input))
|
// common::show_both_answers(&both_parts(&input))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +171,7 @@ abdefghi";
|
||||||
fn test() {
|
fn test() {
|
||||||
let input = processed_input(TEST_INPUT);
|
let input = processed_input(TEST_INPUT);
|
||||||
assert_eq!(part1(&input), 31);
|
assert_eq!(part1(&input), 31);
|
||||||
assert_eq!(part2(&input), 0);
|
assert_eq!(part2(input), 29);
|
||||||
// assert_eq!(both_parts(&input), (0, 0));
|
// assert_eq!(both_parts(&input), (0, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue