Skip to content

Commit

Permalink
refactor: make is_end as function argument instead of struct property
Browse files Browse the repository at this point in the history
  • Loading branch information
manhunto committed Dec 23, 2024
1 parent 0754988 commit f41ddb1
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 46 deletions.
4 changes: 2 additions & 2 deletions src/solutions/year2023/day17.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ impl Day17 {
let cost = move |_, next: Node| {
*grid_clone.get_for_point(&next.vector.position()).unwrap() as usize
};
let dijkstra: Dijkstra<Node> = Dijkstra::new(adjacency, Box::new(cost), Box::new(is_end));
let dijkstra: Dijkstra<Node> = Dijkstra::new(adjacency, Box::new(cost));

let starts = vec![
Node::new(start_point, Direction::East),
Node::new(start_point, Direction::South),
];

dijkstra.cost(starts).unwrap().to_string()
dijkstra.cost(starts, &is_end).unwrap().to_string()
}

fn filter_out_outside_grid(vec: Vec<Node>, grid: &Grid<u8>) -> Vec<Node> {
Expand Down
15 changes: 8 additions & 7 deletions src/solutions/year2024/day16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,19 @@ pub struct Day16;
impl Solution for Day16 {
fn part_one(&self, input: &str) -> String {
let (grid, start, end) = Self::setup_grid(input);
let dijkstra = Self::create_dijkstra(grid, end);
let dijkstra = Self::create_dijkstra(grid);
let is_end = Self::is_end_closure(end);

dijkstra.cost(vec![start]).unwrap().to_string()
dijkstra.cost(vec![start], &is_end).unwrap().to_string()
}

fn part_two(&self, input: &str) -> String {
let (grid, start, end) = Self::setup_grid(input);
let dijkstra = Self::create_dijkstra(grid, end);
let dijkstra = Self::create_dijkstra(grid);
let is_end = Self::is_end_closure(end);

dijkstra
.all_paths(vec![start])
.all_paths(vec![start], &is_end)
.iter()
.flat_map(|path| path.iter().map(|p| p.position()))
.unique()
Expand All @@ -40,12 +42,11 @@ impl Day16 {
(grid, start, end)
}

fn create_dijkstra(grid: Grid<char>, end: Point) -> Dijkstra<Vector> {
fn create_dijkstra(grid: Grid<char>) -> Dijkstra<Vector> {
let adjacency = Self::adjacency_closure(grid);
let cost = Self::cost_closure();
let is_end = Self::is_end_closure(end);

Dijkstra::new(adjacency, cost, is_end)
Dijkstra::new(adjacency, cost)
}

fn adjacency_closure(grid: Grid<char>) -> Box<dyn Fn(Vector) -> Vec<Vector>> {
Expand Down
36 changes: 16 additions & 20 deletions src/solutions/year2024/day21.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::solutions::year2024::day21::Key::{Activate, Dir};
use crate::solutions::Solution;
use crate::utils::direction::Direction;
use crate::utils::graphs::a_star::AStarBuilder;
use crate::utils::graphs::dijkstra::Dijkstra;
use crate::utils::grid::Grid;
use crate::utils::point::Point;
use itertools::Itertools;
Expand Down Expand Up @@ -53,38 +53,38 @@ impl Day21 {
let path = self.path_for_str(&current, pad);

current = path.iter().map(|key| key.to_string()).collect::<String>();

// println!("{}", current);
}

current.chars().count()
}

fn path_for_str(&self, code: &str, pad: &Pad) -> Vec<Key> {
let code = "A".to_owned() + code;
let adjacent = pad.adjacent.clone();

let neighbours = |p: Point| pad.adjacent(&p);
let distance = |_, _| 1;
let neighbours = Box::new(move |p: Point| adjacent.get(&p).unwrap().to_vec());
let distance = Box::new(|_, _| 1);

let a_star = AStarBuilder::init(&neighbours, &distance).build();
let dijkstra = Dijkstra::new(neighbours, distance);

code.chars()
.tuple_windows()
.flat_map(|(from, to)| {
let path = a_star
.path(
pad.position(from as u8).unwrap(),
pad.position(to as u8).unwrap(),
)
.unwrap();
let mut directions: Vec<Key> = path
let start = pad.position(from as u8).unwrap();
let end = pad.position(to as u8).unwrap();

let is_end = |p: Point| p == end;
let path = dijkstra.all_paths(vec![start], &is_end);

let min_path = path.iter().min_by_key(|p| p.len()).unwrap();
let mut directions: Vec<Key> = min_path
.iter()
.collect_vec()
.windows(2)
.map(|pair| Dir(pair[0].direction(&pair[1]).unwrap()))
.map(|pair| Dir(pair[0].direction(pair[1]).unwrap()))
.collect();
directions.push(Activate);

// println!("{from} {to} -> {:?}", directions.iter().map(|d| d.to_string()).collect::<String>());

directions.into_iter()
})
.collect()
Expand Down Expand Up @@ -171,10 +171,6 @@ impl Pad {
fn position(&self, element: u8) -> Option<Point> {
self.positions.get(&element).copied()
}

fn adjacent(&self, position: &Point) -> Vec<Point> {
self.adjacent.get(position).unwrap().to_vec()
}
}

#[cfg(test)]
Expand Down
25 changes: 8 additions & 17 deletions src/utils/graphs/dijkstra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,14 @@ use std::hash::Hash;
pub struct Dijkstra<T> {
neighbours: Box<dyn Fn(T) -> Vec<T>>,
cost: Box<dyn Fn(T, T) -> usize>,
is_end: Box<dyn Fn(T) -> bool>,
}

impl<T> Dijkstra<T> {
pub fn new(
neighbours: Box<dyn Fn(T) -> Vec<T>>,
cost: Box<dyn Fn(T, T) -> usize>,
is_end: Box<dyn Fn(T) -> bool>,
) -> Self {
Self {
neighbours,
cost,
is_end,
}
pub fn new(neighbours: Box<dyn Fn(T) -> Vec<T>>, cost: Box<dyn Fn(T, T) -> usize>) -> Self {
Self { neighbours, cost }
}

pub fn cost(&self, starts: Vec<T>) -> Option<usize>
pub fn cost(&self, starts: Vec<T>, is_end: &dyn Fn(T) -> bool) -> Option<usize>
where
T: Hash + Eq + PartialEq + Ord + Copy + Debug,
{
Expand All @@ -36,7 +27,7 @@ impl<T> Dijkstra<T> {
}

while let Some(State { cost, node }) = heap.pop() {
if (self.is_end)(node) {
if is_end(node) {
return Some(cost);
}

Expand All @@ -56,7 +47,7 @@ impl<T> Dijkstra<T> {

/// It returns every possible visited node
/// Even if there is a many possible ways to reach end
pub fn all_paths(&self, starts: Vec<T>) -> Vec<VecDeque<T>>
pub fn all_paths(&self, starts: Vec<T>, is_end: &dyn Fn(T) -> bool) -> Vec<VecDeque<T>>
where
T: Hash + Eq + PartialEq + Ord + Debug + Copy,
{
Expand All @@ -74,7 +65,7 @@ impl<T> Dijkstra<T> {
let mut end_nodes: Vec<T> = Vec::new();

while let Some(State { cost, node }) = heap.pop() {
if (self.is_end)(node) {
if is_end(node) {
lowest = Some(cost);
end_nodes.push(node);

Expand Down Expand Up @@ -171,10 +162,10 @@ mod test {
_ => unreachable!("Invalid node"),
}),
Box::new(|_: char, _: char| 1),
Box::new(|node: char| node == '<'),
);
let is_end = |node: char| node == '<';

let paths = dijkstra.all_paths(vec!['A']);
let paths = dijkstra.all_paths(vec!['A'], &is_end);

assert_eq!(paths.len(), 2);
assert!(paths.contains(&VecDeque::from(vec!['A', '^', 'v', '<'])));
Expand Down

0 comments on commit f41ddb1

Please sign in to comment.