Implement `AstarStrategy` trait to not borrow A* context multiple times

This commit is contained in:
Mikolaj Wielgus 2023-09-02 01:43:27 +02:00
parent b5f9a5957a
commit bea6d84878
2 changed files with 61 additions and 33 deletions

View File

@ -96,19 +96,25 @@ where
} }
} }
pub fn astar<G, F, H, K, Reroute>( pub trait AstarStrategy<G, K>
where
G: IntoEdges + Visitable,
K: Measure + Copy,
G::NodeId: Eq + Hash,
{
fn reroute(&mut self, node: G::NodeId, tracker: &PathTracker<G>) -> Option<K>;
fn edge_cost(&mut self, edge: G::EdgeRef) -> K;
fn estimate_cost(&mut self, node: G::NodeId) -> K;
}
pub fn astar<G, K>(
graph: G, graph: G,
start: G::NodeId, start: G::NodeId,
mut reroute: Reroute, strategy: &mut impl AstarStrategy<G, K>,
mut edge_cost: F,
mut estimate_cost: H,
) -> Option<(K, Vec<G::NodeId>)> ) -> Option<(K, Vec<G::NodeId>)>
where where
G: IntoEdges + Visitable, G: IntoEdges + Visitable,
Reroute: FnMut(G::NodeId, &PathTracker<G>) -> Option<K>,
G::NodeId: Eq + Hash, G::NodeId: Eq + Hash,
F: FnMut(G::EdgeRef) -> K,
H: FnMut(G::NodeId) -> K,
K: Measure + Copy, K: Measure + Copy,
{ {
let mut visit_next = BinaryHeap::new(); let mut visit_next = BinaryHeap::new();
@ -118,10 +124,10 @@ where
let zero_score = K::default(); let zero_score = K::default();
scores.insert(start, zero_score); scores.insert(start, zero_score);
visit_next.push(MinScored(estimate_cost(start), start)); visit_next.push(MinScored(strategy.estimate_cost(start), start));
while let Some(MinScored(estimate_score, node)) = visit_next.pop() { while let Some(MinScored(estimate_score, node)) = visit_next.pop() {
match reroute(node, &path_tracker) { match strategy.reroute(node, &path_tracker) {
None => { None => {
let path = path_tracker.reconstruct_path_to(node); let path = path_tracker.reconstruct_path_to(node);
let cost = scores[&node]; let cost = scores[&node];
@ -148,7 +154,7 @@ where
for edge in graph.edges(node) { for edge in graph.edges(node) {
let next = edge.target(); let next = edge.target();
let next_score = node_score + route_cost + edge_cost(edge); let next_score = node_score + route_cost + strategy.edge_cost(edge);
match scores.entry(next) { match scores.entry(next) {
Occupied(mut entry) => { Occupied(mut entry) => {
@ -165,7 +171,7 @@ where
} }
path_tracker.set_predecessor(next, node); path_tracker.set_predecessor(next, node);
let next_estimate_score = next_score + estimate_cost(next); let next_estimate_score = next_score + strategy.estimate_cost(next);
visit_next.push(MinScored(next_estimate_score, next)); visit_next.push(MinScored(next_estimate_score, next));
} }
} }

View File

@ -2,7 +2,7 @@ use geo::geometry::Point;
use petgraph::visit::{EdgeRef, IntoEdgeReferences}; use petgraph::visit::{EdgeRef, IntoEdgeReferences};
use spade::InsertionError; use spade::InsertionError;
use crate::astar::astar; use crate::astar::{astar, AstarStrategy, PathTracker};
use crate::bow::Bow; use crate::bow::Bow;
use crate::draw::{Draw, Head}; use crate::draw::{Draw, Head};
use crate::graph::{BendIndex, DotIndex, Ends, SegIndex, TaggedIndex}; use crate::graph::{BendIndex, DotIndex, Ends, SegIndex, TaggedIndex};
@ -11,8 +11,8 @@ use crate::guide::Guide;
use crate::layout::Layout; use crate::layout::Layout;
use crate::math::Circle; use crate::math::Circle;
use crate::mesh::{Mesh, VertexIndex}; use crate::mesh::{Mesh, MeshEdgeReference, VertexIndex};
use crate::route::Route; use crate::route::{Route, Trace};
use crate::rules::{Conditions, Rules}; use crate::rules::{Conditions, Rules};
use crate::segbend::Segbend; use crate::segbend::Segbend;
@ -21,6 +21,45 @@ pub struct Router {
rules: Rules, rules: Rules,
} }
pub struct DefaultAstarStrategy<'a> {
route: Route<'a>,
trace: Trace,
to: VertexIndex,
}
impl<'a> DefaultAstarStrategy<'a> {
pub fn new(route: Route<'a>, trace: Trace, to: VertexIndex) -> Self {
Self { route, trace, to }
}
}
impl<'a> AstarStrategy<&Mesh, u64> for DefaultAstarStrategy<'a> {
fn reroute(&mut self, vertex: VertexIndex, tracker: &PathTracker<&Mesh>) -> Option<u64> {
let new_path = tracker.reconstruct_path_to(vertex);
if vertex == self.to {
self.route
.rework_path(&mut self.trace, &new_path[..new_path.len() - 1], 5.0)
.ok();
self.route
.finish(&mut self.trace, new_path[new_path.len() - 1], 5.0)
.ok();
None
} else {
self.route.rework_path(&mut self.trace, &new_path, 5.0).ok();
Some(0)
}
}
fn edge_cost(&mut self, edge: MeshEdgeReference) -> u64 {
1
}
fn estimate_cost(&mut self, vertex: VertexIndex) -> u64 {
0
}
}
impl Router { impl Router {
pub fn new() -> Self { pub fn new() -> Self {
Router { Router {
@ -37,29 +76,12 @@ impl Router {
mesh.triangulate(&self.layout)?; mesh.triangulate(&self.layout)?;
let mut route = self.route(&mesh); let mut route = self.route(&mesh);
let mut trace = route.start(mesh.vertex(from)); let trace = route.start(mesh.vertex(from));
let (_cost, path) = astar( let (_cost, path) = astar(
&mesh, &mesh,
mesh.vertex(from), mesh.vertex(from),
|node, tracker| { &mut DefaultAstarStrategy::new(route, trace, mesh.vertex(to)),
let new_path = tracker.reconstruct_path_to(node);
if node == mesh.vertex(to) {
route
.rework_path(&mut trace, &new_path[..new_path.len() - 1], 5.0)
.ok();
route
.finish(&mut trace, new_path[new_path.len() - 1], 5.0)
.ok();
None
} else {
route.rework_path(&mut trace, &new_path, 5.0).ok();
Some(0)
}
},
|_edge| 1,
|_| 0,
) )
.unwrap(); // TODO. .unwrap(); // TODO.
Ok(()) Ok(())