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,
start: G::NodeId,
mut reroute: Reroute,
mut edge_cost: F,
mut estimate_cost: H,
strategy: &mut impl AstarStrategy<G, K>,
) -> Option<(K, Vec<G::NodeId>)>
where
G: IntoEdges + Visitable,
Reroute: FnMut(G::NodeId, &PathTracker<G>) -> Option<K>,
G::NodeId: Eq + Hash,
F: FnMut(G::EdgeRef) -> K,
H: FnMut(G::NodeId) -> K,
K: Measure + Copy,
{
let mut visit_next = BinaryHeap::new();
@ -118,10 +124,10 @@ where
let zero_score = K::default();
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() {
match reroute(node, &path_tracker) {
match strategy.reroute(node, &path_tracker) {
None => {
let path = path_tracker.reconstruct_path_to(node);
let cost = scores[&node];
@ -148,7 +154,7 @@ where
for edge in graph.edges(node) {
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) {
Occupied(mut entry) => {
@ -165,7 +171,7 @@ where
}
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));
}
}

View File

@ -2,7 +2,7 @@ use geo::geometry::Point;
use petgraph::visit::{EdgeRef, IntoEdgeReferences};
use spade::InsertionError;
use crate::astar::astar;
use crate::astar::{astar, AstarStrategy, PathTracker};
use crate::bow::Bow;
use crate::draw::{Draw, Head};
use crate::graph::{BendIndex, DotIndex, Ends, SegIndex, TaggedIndex};
@ -11,8 +11,8 @@ use crate::guide::Guide;
use crate::layout::Layout;
use crate::math::Circle;
use crate::mesh::{Mesh, VertexIndex};
use crate::route::Route;
use crate::mesh::{Mesh, MeshEdgeReference, VertexIndex};
use crate::route::{Route, Trace};
use crate::rules::{Conditions, Rules};
use crate::segbend::Segbend;
@ -21,6 +21,45 @@ pub struct Router {
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 {
pub fn new() -> Self {
Router {
@ -37,29 +76,12 @@ impl Router {
mesh.triangulate(&self.layout)?;
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(
&mesh,
mesh.vertex(from),
|node, tracker| {
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,
&mut DefaultAstarStrategy::new(route, trace, mesh.vertex(to)),
)
.unwrap(); // TODO.
Ok(())