Files
AOC/2023/day-23/src/part2.rs
Dylan Thies 05951ebc8a clean ups
2023-12-29 13:34:59 -05:00

122 lines
3.2 KiB
Rust

#![warn(clippy::all, clippy::pedantic)]
use std::collections::HashMap;
use glam::IVec2;
use petgraph::{algo, prelude::*};
#[derive(Debug, Copy, Clone)]
enum PointType {
Any,
OnlyDown,
OnlyLeft,
OnlyRight,
OnlyUp,
}
/// day 23 part 2 of aoc 2023
///
/// # Arguments
/// - input the input for today's puzzle
///
/// # Panics
/// panics whne it cannot parse the input OR when ever the number of game numbers is greater than
#[must_use]
pub fn part2(input: &str) -> String {
let maze = parse_input(input);
//get the start position (assuming there is only one)
let start = *maze.keys().find(|pos| pos.y == 0).unwrap();
let end = maze.keys().fold(IVec2::splat(0), |max, current| {
if max.y.max(current.y) == current.y {
*current
} else {
max
}
});
let mut maze_graph = DiGraph::<&PointType, u32>::new();
let node_map = maze
.iter()
.map(|(pos, point_type)| (pos, maze_graph.add_node(point_type)))
.collect::<HashMap<_, _>>();
maze.iter()
.flat_map(|(pos, _point_type)| {
[IVec2::X, IVec2::Y, IVec2::NEG_X, IVec2::NEG_Y]
.iter()
.copied()
.filter_map(|dir| {
let next_pos = dir + *pos;
node_map
.get(&next_pos)
.is_some()
.then(|| (node_map[pos], node_map[&next_pos], 1))
})
.collect::<Vec<_>>()
})
.for_each(|(a, b, weight)| {
maze_graph.add_edge(a, b, weight);
});
(algo::all_simple_paths::<Vec<_>, _>(&maze_graph, node_map[&start], node_map[&end], 0, None)
.max_by(|a, b| a.len().cmp(&b.len()))
.unwrap()
.len()
- 1)
.to_string()
}
fn parse_input(input: &str) -> HashMap<IVec2, PointType> {
input
.lines()
.enumerate()
.flat_map(|(y, row)| {
row.chars().enumerate().filter_map(move |(x, c)| {
let pos = IVec2::new(i32::try_from(x).unwrap(), i32::try_from(y).unwrap());
match c {
'.' => Some((pos, PointType::Any)),
'>' => Some((pos, PointType::OnlyRight)),
'v' => Some((pos, PointType::OnlyDown)),
'^' => Some((pos, PointType::OnlyUp)),
'<' => Some((pos, PointType::OnlyLeft)),
_ => None,
}
})
})
.collect()
}
#[cfg(test)]
mod test {
use super::*;
const INPUT: &str = "#.#####################
#.......#########...###
#######.#########.#.###
###.....#.>.>.###.#.###
###v#####.#v#.###.#.###
###.>...#.#.#.....#...#
###v###.#.#.#########.#
###...#.#.#.......#...#
#####.#.#.#######.#.###
#.....#.#.#.......#...#
#.#####.#.#.#########v#
#.#...#...#...###...>.#
#.#.#v#######v###.###v#
#...#.>.#...>.>.#.###.#
#####v#.#.###v#.#.###.#
#.....#...#...#.#.#...#
#.#########.###.#.#.###
#...###...#...#...#.###
###.###.#.###v#####v###
#...#...#.#.>.>.#.>.###
#.###.###.#.###.#.#v###
#.....###...###...#...#
#####################.#";
#[test]
fn part2_works() {
let result = part2(INPUT);
assert_eq!(result, "154".to_string());
}
}