Add general function for checking size of contiguous tile area

pull/326/head
Jonathan G Rennison 3 years ago
parent 8b5b96af77
commit 55620ff162

@ -16,6 +16,7 @@
#include "tunnelbridge_map.h"
#include "3rdparty/cpp-btree/btree_map.h"
#include <array>
#include <deque>
#include "safeguards.h"
@ -370,6 +371,58 @@ bool CircularTileSearch(TileIndex *tile, uint radius, uint w, uint h, TestTileOn
return false;
}
/**
* Generalized contiguous matching tile area size threshold function.
* Contiguous means directly adjacent by DiagDirection directions.
*
* @param tile to start the search from.
* @param threshold minimum number of matching tiles for success, searching is halted when this is reached.
* @param proc callback testing function pointer.
* @param user_data to be passed to the callback function. Depends on the implementation
* @return whether the contiguous tile area size is >= threshold
* @pre proc != nullptr
*/
bool EnoughContiguousTilesMatchingCondition(TileIndex tile, uint threshold, TestTileOnSearchProc proc, void *user_data)
{
assert(proc != nullptr);
if (threshold == 0) return true;
static_assert(MAX_MAP_TILES_BITS <= 30);
btree::btree_set<uint32> processed_tiles;
std::deque<uint32> candidates;
uint matching_count = 0;
auto process_tile = [&](TileIndex t, DiagDirection exclude_onward_dir) {
auto iter = processed_tiles.lower_bound(t);
if (iter != processed_tiles.end() && *iter == t) {
/* done this tile already */
} else {
if (proc(t, user_data)) {
matching_count++;
for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
if (dir == exclude_onward_dir) continue;
TileIndex neighbour_tile = AddTileIndexDiffCWrap(t, TileIndexDiffCByDiagDir(dir));
if (IsValidTile(neighbour_tile)) {
candidates.push_back(neighbour_tile | (ReverseDiagDir(dir) << 30));
}
}
}
processed_tiles.insert(iter, t);
}
};
process_tile(tile, INVALID_DIAGDIR);
while (matching_count < threshold && !candidates.empty()) {
uint32 next = candidates.front();
candidates.pop_front();
TileIndex t = GB(next, 0, 30);
DiagDirection exclude_onward_dir = (DiagDirection)GB(next, 30, 2);
process_tile(t, exclude_onward_dir);
}
return matching_count >= threshold;
}
/**
* Finds the distance for the closest tile with water/land given a tile
* @param tile the tile to find the distance too

@ -438,6 +438,8 @@ typedef bool TestTileOnSearchProc(TileIndex tile, void *user_data);
bool CircularTileSearch(TileIndex *tile, uint size, TestTileOnSearchProc proc, void *user_data);
bool CircularTileSearch(TileIndex *tile, uint radius, uint w, uint h, TestTileOnSearchProc proc, void *user_data);
bool EnoughContiguousTilesMatchingCondition(TileIndex tile, uint threshold, TestTileOnSearchProc proc, void *user_data);
/**
* Get a random tile out of a given seed.
* @param r the random 'seed'

Loading…
Cancel
Save