1
0
Fork 0

Change: Find nearest depot to entry edge in intermediate region

When using an intermediate region, find the depot closest to the edge where it entered the region from.
pull/10544/head
SamuXarick 2024-10-03 18:37:48 +01:00
parent 0b44deedd0
commit 7df9426000
4 changed files with 70 additions and 10 deletions

View File

@ -433,12 +433,12 @@ void PrintWaterRegionDebugInfo(TileIndex tile)
/**
* Tests the provided callback function on all tiles of the water patch of the region
* and returns the first tile that passes the callback test.
* and returns true on the first tile that passes the callback test.
* @param callback The test function that will be called for the water patch.
* @param water_region_patch Water patch within the water region to test the callback.
* @return the first tile which passed the callback test, or INVALID_TILE if the callback failed.
* @return true if it passes the callback test, or false if the callback failed.
*/
TileIndex GetTileInWaterRegionPatch(const WaterRegionPatchDesc &water_region_patch, TestTileIndexCallBack &callback)
bool TestTileInWaterRegionPatch(const WaterRegionPatchDesc &water_region_patch, TestTileIndexCallBack &callback)
{
const WaterRegion region = GetUpdatedWaterRegion(water_region_patch.x, water_region_patch.y);
@ -446,8 +446,67 @@ TileIndex GetTileInWaterRegionPatch(const WaterRegionPatchDesc &water_region_pat
for (const TileIndex tile : region) {
if (region.GetLabel(tile) != water_region_patch.label || !callback(tile)) continue;
return tile;
return true;
}
return INVALID_TILE;
return false;
}
/**
* Tests the provided callback function on all tiles of the current water patch of the region, collects the
* tiles which passed the callback and returns the tile closest to the edge from where the region is entered from.
* @param high_level_path A span containing at least current and parent water patches.
* @param callback The test function that will be called for each tile in the water patch.
* @return The tile closest to the edge from where it came from that passed the callback test, or INVALID_TILE if no tile passed.
*/
TileIndex FindClosestEnteringTile(const std::span<WaterRegionPatchDesc> high_level_path, TestTileIndexCallBack &callback)
{
assert(high_level_path.size() > 1);
const WaterRegionPatchDesc &current_water_region_patch = high_level_path.back();
const WaterRegion current_region = GetUpdatedWaterRegion(current_water_region_patch.x, current_water_region_patch.y);
/* Check if the current region has a tile which passes the callback test. */
std::vector<TileIndex> tile_list;
for (const TileIndex tile : current_region) {
if (current_region.GetLabel(tile) != current_water_region_patch.label || !callback(tile)) continue;
/* We collect the tiles when we know which region we came from for further evaluation. */
tile_list.push_back(tile);
}
/* If there aren't any tiles that passed the callback, return with an invalid tile. */
if (tile_list.empty()) return INVALID_TILE;
/* If there's only one, just return it. */
if (tile_list.size() == 1) return tile_list.front();
const TileIndex top_tile = current_region.begin();
const TileIndex bot_tile = TileAddXY(top_tile, WATER_REGION_EDGE_LENGTH - 1, WATER_REGION_EDGE_LENGTH - 1);
/* Get the side from which the current region is entered from. */
const WaterRegionPatchDesc &parent_water_region_patch = high_level_path[high_level_path.size() - 2];
const WaterRegion parent_region = GetUpdatedWaterRegion(parent_water_region_patch.x, parent_water_region_patch.y);
const DiagDirection side = DiagdirBetweenTiles(top_tile, parent_region.begin());
/* Depending on the side, determine which corner tile to use to extract their x or y coordinates. */
const bool is_at_top = side == DIAGDIR_NE || side == DIAGDIR_NW;
const TileIndex edge_tile = is_at_top ? top_tile : bot_tile;
const bool is_axis_x = DiagDirToAxis(side) == AXIS_X;
const int x_or_y_edge = is_axis_x ? TileX(edge_tile) : TileY(edge_tile);
/* With more than one tile passing the callback, calculate the tile that is closest to the edge from whence it came. */
TileIndex best_tile = INVALID_TILE;
int best_dist = WATER_REGION_EDGE_LENGTH;
for (const TileIndex &tile : tile_list) {
const int x_or_y_tile = is_axis_x ? TileX(tile) : TileY(tile);
const int dist_to_edge = std::abs(x_or_y_tile - x_or_y_edge);
assert(dist_to_edge < WATER_REGION_EDGE_LENGTH);
if (dist_to_edge >= best_dist) continue;
best_dist = dist_to_edge;
best_tile = tile;
}
return best_tile;
}

View File

@ -65,6 +65,7 @@ void AllocateWaterRegions();
void PrintWaterRegionDebugInfo(TileIndex tile);
using TestTileIndexCallBack = std::function<bool(const TileIndex)>;
TileIndex GetTileInWaterRegionPatch(const WaterRegionPatchDesc &water_region_patch, TestTileIndexCallBack &callback);
bool TestTileInWaterRegionPatch(const WaterRegionPatchDesc &water_region_patch, TestTileIndexCallBack &callback);
TileIndex FindClosestEnteringTile(const std::span<WaterRegionPatchDesc> high_level_path, TestTileIndexCallBack &callback);
#endif /* WATER_REGIONS_H */

View File

@ -101,9 +101,9 @@ public:
return tile == this->dest_tile && ((this->dest_trackdirs & TrackdirToTrackdirBits(trackdir)) != TRACKDIR_BIT_NONE);
}
inline TileIndex GetShipDepotDestination(const WaterRegionPatchDesc &water_region_patch)
inline TileIndex GetShipDepotDestination(const std::span<WaterRegionPatchDesc> high_level_path)
{
return GetTileInWaterRegionPatch(water_region_patch, this->detect_ship_depot);
return FindClosestEnteringTile(high_level_path, this->detect_ship_depot);
}
/**
@ -283,7 +283,7 @@ public:
/* Return early when only searching for the closest depot tile. */
if (find_closest_depot) {
tile = is_intermediate_destination ? pf.GetShipDepotDestination(high_level_path.back()) : node->GetTile();
tile = is_intermediate_destination ? pf.GetShipDepotDestination(high_level_path) : node->GetTile();
return INVALID_TRACKDIR;
}

View File

@ -144,7 +144,7 @@ public:
inline bool PfDetectDestination(Node &n)
{
if (this->any_ship_depot) {
return GetTileInWaterRegionPatch(n.key.water_region_patch, this->detect_ship_depot) != INVALID_TILE;
return TestTileInWaterRegionPatch(n.key.water_region_patch, this->detect_ship_depot);
}
return n.key == this->dest;