1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum SolverUseCase {
35 StaticUnweightedGrid,
37 WeightedGrid,
39 DynamicGridReplanning,
41 AnyAngleGrid,
43 ExactPolygonalScene,
45 RepeatedPolygonalFixedSource,
47 ExactNavmeshRouting,
49 InterpolatedDynamicReplanning,
51}
52
53impl SolverUseCase {
54 #[must_use]
56 pub const fn slug(self) -> &'static str {
57 match self {
58 Self::StaticUnweightedGrid => "static-unweighted-grid",
59 Self::WeightedGrid => "weighted-grid",
60 Self::DynamicGridReplanning => "dynamic-grid-replanning",
61 Self::AnyAngleGrid => "any-angle-grid",
62 Self::ExactPolygonalScene => "exact-polygonal-scene",
63 Self::RepeatedPolygonalFixedSource => "repeated-polygonal-fixed-source",
64 Self::ExactNavmeshRouting => "exact-navmesh-routing",
65 Self::InterpolatedDynamicReplanning => "interpolated-dynamic-replanning",
66 }
67 }
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub enum SolverRecommendationStatus {
73 UseNow,
75 Watch,
77}
78
79impl SolverRecommendationStatus {
80 #[must_use]
82 pub const fn slug(self) -> &'static str {
83 match self {
84 Self::UseNow => "use-now",
85 Self::Watch => "watch",
86 }
87 }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
96pub enum SolverSurface {
97 AStar,
99 Dijkstra,
101 DStarLite,
103 Anya,
105 VisibilityGraph,
107 ContinuousShortestPathMap,
109 TRAStarBuilder,
111 FieldDStar,
113}
114
115impl SolverSurface {
116 #[must_use]
118 pub const fn public_entrypoint(self) -> &'static str {
119 match self {
120 Self::AStar => "AStar",
121 Self::Dijkstra => "Dijkstra",
122 Self::DStarLite => "DStarLite",
123 Self::Anya => "Anya",
124 Self::VisibilityGraph => "VisibilityGraph",
125 Self::ContinuousShortestPathMap => "ContinuousShortestPathMap",
126 Self::TRAStarBuilder => "TRAStarBuilder",
127 Self::FieldDStar => "FieldDStar",
128 }
129 }
130
131 #[must_use]
133 pub const fn integration_surface(self) -> &'static str {
134 match self {
135 Self::AStar | Self::Dijkstra => "Pathfinder",
136 Self::DStarLite => "GridReplanner",
137 Self::Anya => "AnyAnglePathfinder",
138 Self::VisibilityGraph => "PolygonPathfinder",
139 Self::ContinuousShortestPathMap => "preprocess/query map",
140 Self::TRAStarBuilder => "PreparedNavmeshBuilder",
141 Self::FieldDStar => "InterpolatedGridReplanner",
142 }
143 }
144}
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq)]
150pub struct SolverPortfolioRecommendation {
151 use_case: SolverUseCase,
152 solver_surface: SolverSurface,
153 status: SolverRecommendationStatus,
154 rationale: &'static str,
155 next_step: &'static str,
156}
157
158impl SolverPortfolioRecommendation {
159 #[must_use]
161 pub const fn use_case(self) -> SolverUseCase {
162 self.use_case
163 }
164
165 #[must_use]
167 pub const fn solver_surface(self) -> SolverSurface {
168 self.solver_surface
169 }
170
171 #[must_use]
173 pub const fn status(self) -> SolverRecommendationStatus {
174 self.status
175 }
176
177 #[must_use]
179 pub const fn rationale(self) -> &'static str {
180 self.rationale
181 }
182
183 #[must_use]
185 pub const fn next_step(self) -> &'static str {
186 self.next_step
187 }
188
189 #[must_use]
191 pub const fn solver(self) -> &'static str {
192 self.solver_surface.public_entrypoint()
193 }
194
195 #[must_use]
197 pub const fn integration_surface(self) -> &'static str {
198 self.solver_surface.integration_surface()
199 }
200}
201
202const SOLVER_PORTFOLIO_CATALOG: [SolverPortfolioRecommendation; 8] = [
203 SolverPortfolioRecommendation {
204 use_case: SolverUseCase::StaticUnweightedGrid,
205 solver_surface: SolverSurface::AStar,
206 status: SolverRecommendationStatus::UseNow,
207 rationale: "Current README pick for static unweighted grids.",
208 next_step: "Call AStar.search(&grid, request).",
209 },
210 SolverPortfolioRecommendation {
211 use_case: SolverUseCase::WeightedGrid,
212 solver_surface: SolverSurface::Dijkstra,
213 status: SolverRecommendationStatus::UseNow,
214 rationale: "Current README pick for weighted grids.",
215 next_step: "Call Dijkstra.search(&grid, request) on weighted cells.",
216 },
217 SolverPortfolioRecommendation {
218 use_case: SolverUseCase::DynamicGridReplanning,
219 solver_surface: SolverSurface::DStarLite,
220 status: SolverRecommendationStatus::UseNow,
221 rationale: "Current README pick for dynamic grid replanning.",
222 next_step: "Initialize a DStarLite-style replanner and feed grid updates.",
223 },
224 SolverPortfolioRecommendation {
225 use_case: SolverUseCase::AnyAngleGrid,
226 solver_surface: SolverSurface::Anya,
227 status: SolverRecommendationStatus::UseNow,
228 rationale: "Current README pick for any-angle grid paths.",
229 next_step: "Call Anya.search(&grid, request).",
230 },
231 SolverPortfolioRecommendation {
232 use_case: SolverUseCase::ExactPolygonalScene,
233 solver_surface: SolverSurface::VisibilityGraph,
234 status: SolverRecommendationStatus::UseNow,
235 rationale: "Current README pick for exact polygonal scenes.",
236 next_step: "Call VisibilityGraph.search(&scene, request).",
237 },
238 SolverPortfolioRecommendation {
239 use_case: SolverUseCase::RepeatedPolygonalFixedSource,
240 solver_surface: SolverSurface::ContinuousShortestPathMap,
241 status: SolverRecommendationStatus::UseNow,
242 rationale: "Current README pick for repeated polygonal queries from one fixed source.",
243 next_step: "Preprocess once from a fixed source, then query(goal).",
244 },
245 SolverPortfolioRecommendation {
246 use_case: SolverUseCase::ExactNavmeshRouting,
247 solver_surface: SolverSurface::TRAStarBuilder,
248 status: SolverRecommendationStatus::UseNow,
249 rationale: "Current README pick for exact navmesh routing on the prepared TRA* lane.",
250 next_step: "Preprocess the navmesh with TRAStarBuilder, then search(query).",
251 },
252 SolverPortfolioRecommendation {
253 use_case: SolverUseCase::InterpolatedDynamicReplanning,
254 solver_surface: SolverSurface::FieldDStar,
255 status: SolverRecommendationStatus::Watch,
256 rationale: "README marks FieldDStar as the current interpolated replanning surface to watch while that lane is still expanding.",
257 next_step: "Treat FieldDStar as a watch-only lane until that surface settles further.",
258 },
259];
260
261#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
279pub struct SolverPortfolio;
280
281impl SolverPortfolio {
282 #[must_use]
284 pub const fn recommend(use_case: SolverUseCase) -> SolverPortfolioRecommendation {
285 match use_case {
286 SolverUseCase::StaticUnweightedGrid => SOLVER_PORTFOLIO_CATALOG[0],
287 SolverUseCase::WeightedGrid => SOLVER_PORTFOLIO_CATALOG[1],
288 SolverUseCase::DynamicGridReplanning => SOLVER_PORTFOLIO_CATALOG[2],
289 SolverUseCase::AnyAngleGrid => SOLVER_PORTFOLIO_CATALOG[3],
290 SolverUseCase::ExactPolygonalScene => SOLVER_PORTFOLIO_CATALOG[4],
291 SolverUseCase::RepeatedPolygonalFixedSource => SOLVER_PORTFOLIO_CATALOG[5],
292 SolverUseCase::ExactNavmeshRouting => SOLVER_PORTFOLIO_CATALOG[6],
293 SolverUseCase::InterpolatedDynamicReplanning => SOLVER_PORTFOLIO_CATALOG[7],
294 }
295 }
296
297 #[must_use]
308 pub const fn catalog() -> &'static [SolverPortfolioRecommendation] {
309 &SOLVER_PORTFOLIO_CATALOG
310 }
311}