115 using Shape =
typename World::shape_type;
121 std::is_same_v<typename World::residency_type, AlwaysResident>,
122 "build_weighted_chunk_portal_route_product is dense-only; it needs "
123 "sparse topology and route-cache support from a later slice.");
126 product.request_ = request;
128 if (!contains<Shape>(request.start)) {
129 product.status_ = PathStatus::InvalidStart;
130 return PathResult{product.status_, 0, 0, 0, product.path_};
132 if (!contains<Shape>(request.goal)) {
133 product.status_ = PathStatus::InvalidGoal;
134 return PathResult{product.status_, 0, 0, 0, product.path_};
137 constexpr auto orders = std::array{
138 std::array{detail::Axis::X, detail::Axis::Y, detail::Axis::Z},
139 std::array{detail::Axis::X, detail::Axis::Z, detail::Axis::Y},
140 std::array{detail::Axis::Y, detail::Axis::X, detail::Axis::Z},
141 std::array{detail::Axis::Y, detail::Axis::Z, detail::Axis::X},
142 std::array{detail::Axis::Z, detail::Axis::X, detail::Axis::Y},
143 std::array{detail::Axis::Z, detail::Axis::Y, detail::Axis::X},
146 auto found_route =
false;
147 auto best_score = std::numeric_limits<std::uint32_t>::max();
148 product.best_waypoints_.clear();
149 for (
const auto& order : orders) {
150 const auto candidate =
151 detail::build_chunk_portal_candidate<World, PassableTag>(
152 world, request, order, product.candidate_waypoints_);
153 ++product.route_candidates_;
154 product.portal_scan_tiles_ += candidate.scan_tiles;
155 if (!candidate.found) {
158 if (!found_route || candidate.score < best_score) {
160 best_score = candidate.score;
161 product.best_waypoints_.assign(product.candidate_waypoints_.begin(),
162 product.candidate_waypoints_.end());
166 const auto candidate =
167 detail::build_greedy_chunk_portal_candidate<World, PassableTag>(
168 world, request, product.candidate_waypoints_);
169 ++product.route_candidates_;
170 product.portal_scan_tiles_ += candidate.scan_tiles;
171 if (candidate.found && (!found_route || candidate.score < best_score)) {
173 best_score = candidate.score;
174 product.best_waypoints_.assign(product.candidate_waypoints_.begin(),
175 product.candidate_waypoints_.end());
179 product.status_ = PathStatus::NoPath;
182 product.dependencies_.capture_all(world);
183 return PathResult{product.status_, 0, 0, 0, product.path_};
185 product.waypoints_.assign(product.best_waypoints_.begin(),
186 product.best_waypoints_.end());
188 auto from = request.start;
189 auto total_cost = std::uint32_t{0};
190 auto total_expanded = std::size_t{0};
191 auto total_reached = std::size_t{0};
192 auto append_segment = [&](
PathRequest segment_request) {
193 const auto result = weighted_astar_path<World, PassableTag, CostTag>(
194 world, segment_request, scratch);
195 total_expanded += result.expanded_nodes;
196 total_reached += result.reached_nodes;
197 if (result.status != PathStatus::Found) {
198 product.path_.clear();
199 product.status_ = result.status;
200 product.expanded_nodes_ = total_expanded;
201 product.reached_nodes_ = total_reached;
204 detail::capture_failure_dependencies<Shape>(
205 world, segment_request, result.status, product.dependencies_);
208 total_cost = detail::saturating_add(total_cost, result.cost);
209 product.segment_.assign(result.path.begin(), result.path.end());
210 for (std::size_t i = product.path_.empty() ? 0u : 1u;
211 i < product.segment_.size(); ++i) {
212 product.path_.push_back(product.segment_[i]);
217 for (
const auto waypoint : product.waypoints_) {
218 if (!append_segment(
PathRequest{from, waypoint})) {
219 return PathResult{product.status_, 0, total_expanded, total_reached,
224 if (!append_segment(
PathRequest{from, request.goal})) {
225 return PathResult{product.status_, 0, total_expanded, total_reached,
229 product.status_ = PathStatus::Found;
230 product.cost_ = total_cost;
231 product.expanded_nodes_ = total_expanded;
232 product.reached_nodes_ = total_reached;
233 for (
const auto coord : product.path_) {
234 const auto key = tile_key<Shape>(coord);
235 product.dependencies_.add_chunk(world, chunk_key<Shape>(key));
237 return PathResult{product.status_, product.cost_, product.expanded_nodes_,
238 product.reached_nodes_, product.path_};