#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SolverUseCase {
StaticUnweightedGrid,
WeightedGrid,
DynamicGridReplanning,
AnyAngleGrid,
ExactPolygonalScene,
RepeatedPolygonalFixedSource,
ExactNavmeshRouting,
InterpolatedDynamicReplanning,
}
impl SolverUseCase {
#[must_use]
pub const fn slug(self) -> &'static str {
match self {
Self::StaticUnweightedGrid => "static-unweighted-grid",
Self::WeightedGrid => "weighted-grid",
Self::DynamicGridReplanning => "dynamic-grid-replanning",
Self::AnyAngleGrid => "any-angle-grid",
Self::ExactPolygonalScene => "exact-polygonal-scene",
Self::RepeatedPolygonalFixedSource => "repeated-polygonal-fixed-source",
Self::ExactNavmeshRouting => "exact-navmesh-routing",
Self::InterpolatedDynamicReplanning => "interpolated-dynamic-replanning",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SolverRecommendationStatus {
UseNow,
Watch,
}
impl SolverRecommendationStatus {
#[must_use]
pub const fn slug(self) -> &'static str {
match self {
Self::UseNow => "use-now",
Self::Watch => "watch",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SolverSurface {
AStar,
Dijkstra,
DStarLite,
Anya,
VisibilityGraph,
ContinuousShortestPathMap,
TRAStarBuilder,
FieldDStar,
}
impl SolverSurface {
#[must_use]
pub const fn public_entrypoint(self) -> &'static str {
match self {
Self::AStar => "AStar",
Self::Dijkstra => "Dijkstra",
Self::DStarLite => "DStarLite",
Self::Anya => "Anya",
Self::VisibilityGraph => "VisibilityGraph",
Self::ContinuousShortestPathMap => "ContinuousShortestPathMap",
Self::TRAStarBuilder => "TRAStarBuilder",
Self::FieldDStar => "FieldDStar",
}
}
#[must_use]
pub const fn integration_surface(self) -> &'static str {
match self {
Self::AStar | Self::Dijkstra => "Pathfinder",
Self::DStarLite => "GridReplanner",
Self::Anya => "AnyAnglePathfinder",
Self::VisibilityGraph => "PolygonPathfinder",
Self::ContinuousShortestPathMap => "preprocess/query map",
Self::TRAStarBuilder => "PreparedNavmeshBuilder",
Self::FieldDStar => "InterpolatedGridReplanner",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SolverPortfolioRecommendation {
use_case: SolverUseCase,
solver_surface: SolverSurface,
status: SolverRecommendationStatus,
rationale: &'static str,
next_step: &'static str,
}
impl SolverPortfolioRecommendation {
#[must_use]
pub const fn use_case(self) -> SolverUseCase {
self.use_case
}
#[must_use]
pub const fn solver_surface(self) -> SolverSurface {
self.solver_surface
}
#[must_use]
pub const fn status(self) -> SolverRecommendationStatus {
self.status
}
#[must_use]
pub const fn rationale(self) -> &'static str {
self.rationale
}
#[must_use]
pub const fn next_step(self) -> &'static str {
self.next_step
}
#[must_use]
pub const fn solver(self) -> &'static str {
self.solver_surface.public_entrypoint()
}
#[must_use]
pub const fn integration_surface(self) -> &'static str {
self.solver_surface.integration_surface()
}
}
const SOLVER_PORTFOLIO_CATALOG: [SolverPortfolioRecommendation; 8] = [
SolverPortfolioRecommendation {
use_case: SolverUseCase::StaticUnweightedGrid,
solver_surface: SolverSurface::AStar,
status: SolverRecommendationStatus::UseNow,
rationale: "Current README pick for static unweighted grids.",
next_step: "Call AStar.search(&grid, request).",
},
SolverPortfolioRecommendation {
use_case: SolverUseCase::WeightedGrid,
solver_surface: SolverSurface::Dijkstra,
status: SolverRecommendationStatus::UseNow,
rationale: "Current README pick for weighted grids.",
next_step: "Call Dijkstra.search(&grid, request) on weighted cells.",
},
SolverPortfolioRecommendation {
use_case: SolverUseCase::DynamicGridReplanning,
solver_surface: SolverSurface::DStarLite,
status: SolverRecommendationStatus::UseNow,
rationale: "Current README pick for dynamic grid replanning.",
next_step: "Initialize a DStarLite-style replanner and feed grid updates.",
},
SolverPortfolioRecommendation {
use_case: SolverUseCase::AnyAngleGrid,
solver_surface: SolverSurface::Anya,
status: SolverRecommendationStatus::UseNow,
rationale: "Current README pick for any-angle grid paths.",
next_step: "Call Anya.search(&grid, request).",
},
SolverPortfolioRecommendation {
use_case: SolverUseCase::ExactPolygonalScene,
solver_surface: SolverSurface::VisibilityGraph,
status: SolverRecommendationStatus::UseNow,
rationale: "Current README pick for exact polygonal scenes.",
next_step: "Call VisibilityGraph.search(&scene, request).",
},
SolverPortfolioRecommendation {
use_case: SolverUseCase::RepeatedPolygonalFixedSource,
solver_surface: SolverSurface::ContinuousShortestPathMap,
status: SolverRecommendationStatus::UseNow,
rationale: "Current README pick for repeated polygonal queries from one fixed source.",
next_step: "Preprocess once from a fixed source, then query(goal).",
},
SolverPortfolioRecommendation {
use_case: SolverUseCase::ExactNavmeshRouting,
solver_surface: SolverSurface::TRAStarBuilder,
status: SolverRecommendationStatus::UseNow,
rationale: "Current README pick for exact navmesh routing on the prepared TRA* lane.",
next_step: "Preprocess the navmesh with TRAStarBuilder, then search(query).",
},
SolverPortfolioRecommendation {
use_case: SolverUseCase::InterpolatedDynamicReplanning,
solver_surface: SolverSurface::FieldDStar,
status: SolverRecommendationStatus::Watch,
rationale: "README marks FieldDStar as the current interpolated replanning surface to watch while that lane is still expanding.",
next_step: "Treat FieldDStar as a watch-only lane until that surface settles further.",
},
];
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct SolverPortfolio;
impl SolverPortfolio {
#[must_use]
pub const fn recommend(use_case: SolverUseCase) -> SolverPortfolioRecommendation {
match use_case {
SolverUseCase::StaticUnweightedGrid => SOLVER_PORTFOLIO_CATALOG[0],
SolverUseCase::WeightedGrid => SOLVER_PORTFOLIO_CATALOG[1],
SolverUseCase::DynamicGridReplanning => SOLVER_PORTFOLIO_CATALOG[2],
SolverUseCase::AnyAngleGrid => SOLVER_PORTFOLIO_CATALOG[3],
SolverUseCase::ExactPolygonalScene => SOLVER_PORTFOLIO_CATALOG[4],
SolverUseCase::RepeatedPolygonalFixedSource => SOLVER_PORTFOLIO_CATALOG[5],
SolverUseCase::ExactNavmeshRouting => SOLVER_PORTFOLIO_CATALOG[6],
SolverUseCase::InterpolatedDynamicReplanning => SOLVER_PORTFOLIO_CATALOG[7],
}
}
#[must_use]
pub const fn catalog() -> &'static [SolverPortfolioRecommendation] {
&SOLVER_PORTFOLIO_CATALOG
}
}