From e1e1063d15a97bf93ec6dd1a082f78b0c3191d1d Mon Sep 17 00:00:00 2001 From: mat Date: Tue, 9 May 2023 22:05:46 -0500 Subject: astar --- azalea/src/pathfinder/astar.rs | 106 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 azalea/src/pathfinder/astar.rs (limited to 'azalea/src/pathfinder/astar.rs') diff --git a/azalea/src/pathfinder/astar.rs b/azalea/src/pathfinder/astar.rs new file mode 100644 index 00000000..858e7720 --- /dev/null +++ b/azalea/src/pathfinder/astar.rs @@ -0,0 +1,106 @@ +use std::{cmp::Reverse, collections::HashMap, fmt::Debug, hash::Hash, ops::Add}; + +use priority_queue::PriorityQueue; + +pub fn a_star( + start: N, + heuristic: HeuristicFn, + successors: SuccessorsFn, + success: SuccessFn, +) -> Option> +where + N: Eq + Hash + Copy + Debug, + W: PartialOrd + Default + Copy + num_traits::Bounded + Debug + Add, + HeuristicFn: Fn(&N) -> W, + SuccessorsFn: Fn(&N) -> Vec>, + SuccessFn: Fn(&N) -> bool, +{ + let mut open_set = PriorityQueue::new(); + open_set.push(start, Reverse(Weight(W::default()))); + let mut nodes: HashMap> = HashMap::new(); + nodes.insert( + start, + Node { + data: start, + came_from: None, + g_score: W::default(), + f_score: W::max_value(), + }, + ); + + while let Some((current_node, _)) = open_set.pop() { + if success(¤t_node) { + return Some(reconstruct_path(&nodes, current_node)); + } + + let current_g_score = nodes + .get(¤t_node) + .map(|n| n.g_score) + .unwrap_or(W::max_value()); + + for neighbor in successors(¤t_node) { + let tentative_g_score = current_g_score + neighbor.cost; + let neighbor_g_score = nodes + .get(&neighbor.target) + .map(|n| n.g_score) + .unwrap_or(W::max_value()); + if tentative_g_score < neighbor_g_score { + let f_score = tentative_g_score + heuristic(&neighbor.target); + nodes.insert( + neighbor.target, + Node { + data: neighbor.target, + came_from: Some(current_node), + g_score: tentative_g_score, + f_score, + }, + ); + open_set.push(neighbor.target, Reverse(Weight(f_score))); + } + } + } + + None +} + +fn reconstruct_path(nodes: &HashMap>, current: N) -> Vec +where + N: Eq + Hash + Copy + Debug, + W: PartialOrd + Default + Copy + num_traits::Bounded + Debug, +{ + let mut path = vec![current]; + let mut current = current; + while let Some(node) = nodes.get(¤t) { + if let Some(came_from) = node.came_from { + path.push(came_from); + current = came_from; + } else { + break; + } + } + path.reverse(); + path +} + +pub struct Node { + pub data: N, + pub came_from: Option, + pub g_score: W, + pub f_score: W, +} + +pub struct Edge { + pub target: N, + pub cost: W, +} + +#[derive(PartialOrd, PartialEq)] +pub struct Weight(W); +impl Ord for Weight { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.0 + .partial_cmp(&other.0) + .unwrap_or(std::cmp::Ordering::Equal) + } +} +impl Eq for Weight {} -- cgit v1.2.3 From 80172e43640d2ec3c761611d2269d12a9abdd424 Mon Sep 17 00:00:00 2001 From: mat Date: Fri, 12 May 2023 18:53:08 +0000 Subject: fix warnings --- azalea-brigadier/src/arguments/bool_argument_type.rs | 2 +- azalea-brigadier/src/arguments/string_argument_type.rs | 2 +- azalea/src/pathfinder/astar.rs | 7 ++++++- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'azalea/src/pathfinder/astar.rs') diff --git a/azalea-brigadier/src/arguments/bool_argument_type.rs b/azalea-brigadier/src/arguments/bool_argument_type.rs index 01828c87..57fa8a03 100644 --- a/azalea-brigadier/src/arguments/bool_argument_type.rs +++ b/azalea-brigadier/src/arguments/bool_argument_type.rs @@ -12,7 +12,7 @@ impl ArgumentType for bool { } } -pub fn get_bool<'a, S>(context: &'a CommandContext, name: &str) -> Option { +pub fn get_bool(context: &CommandContext, name: &str) -> Option { context .argument(name) .unwrap() diff --git a/azalea-brigadier/src/arguments/string_argument_type.rs b/azalea-brigadier/src/arguments/string_argument_type.rs index f23af3ba..27363bd4 100644 --- a/azalea-brigadier/src/arguments/string_argument_type.rs +++ b/azalea-brigadier/src/arguments/string_argument_type.rs @@ -44,7 +44,7 @@ pub fn string() -> impl ArgumentType { pub fn greedy_string() -> impl ArgumentType { StringArgument::GreedyPhrase } -pub fn get_string<'a, S>(context: &'a CommandContext, name: &str) -> Option { +pub fn get_string(context: &CommandContext, name: &str) -> Option { context .argument(name) .unwrap() diff --git a/azalea/src/pathfinder/astar.rs b/azalea/src/pathfinder/astar.rs index 858e7720..65caf337 100644 --- a/azalea/src/pathfinder/astar.rs +++ b/azalea/src/pathfinder/astar.rs @@ -94,7 +94,7 @@ pub struct Edge { pub cost: W, } -#[derive(PartialOrd, PartialEq)] +#[derive(PartialEq)] pub struct Weight(W); impl Ord for Weight { fn cmp(&self, other: &Self) -> std::cmp::Ordering { @@ -104,3 +104,8 @@ impl Ord for Weight { } } impl Eq for Weight {} +impl PartialOrd for Weight { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } +} -- cgit v1.2.3