1
0
Fork 0

Compare commits

...

3 Commits

Author SHA1 Message Date
SamuXarick 7bbb9d4b22
Merge 3d8dad2cc6 into baced00e9f 2025-07-13 04:45:23 +00:00
SamuXarick 3d8dad2cc6 Codechange: Optimize FlowRiver
Make all height_tile int to allow comparison between heights generated from TileHeight and heights generated from IsTileFlat.
Make the first check IsWaterTile as that is the first thing that should be checked for FlowRiver recursive calls. Swaps position with height_begin.
Change FlatSet to std::unordered_set which is faster at the contains function.
Change std::list to std::vector to be a queue, but do not pop items from it when advancing the queue. The tiles in it are ordered by insertion which is what's needed for the n-th tile to make lake_centre.
count is not required. It can be extracted from either the unordered set or the vector.
Swap the order of checks for determining the validity of lake_centre tile, making IsTileFlat and DistanceManhattan the last ones to check as I believe are the most computational.
2025-05-08 12:26:39 +01:00
SamuXarick 7ddbd1643e Codechange: Implementation of std::hash for StrongType::Typedef 2025-05-08 10:15:21 +01:00
2 changed files with 47 additions and 24 deletions

View File

@ -158,4 +158,31 @@ namespace StrongType {
};
}
/**
* Implementation of std::hash for StrongType::Typedef.
*
* This specialization of std::hash allows hashing of StrongType::Typedef instances
* by leveraging the hash of the base type.
*
* Example Usage:
* using MyType = StrongType::Typedef<int, struct MyTypeTag>;
* std::unordered_map<MyType, std::string> my_map;
*
* @tparam TBaseType The underlying type of the StrongType::Typedef.
* @tparam TProperties Additional properties for the StrongType::Typedef.
*/
template <typename TBaseType, typename... TProperties>
struct std::hash<StrongType::Typedef<TBaseType, TProperties...>> {
/**
* Computes the hash value for a StrongType::Typedef instance.
*
* @param t The StrongType::Typedef instance to hash.
* @return The hash value of the base type of t.
*/
std::size_t operator()(const StrongType::Typedef<TBaseType, TProperties...> &t) const noexcept
{
return std::hash<TBaseType>()(t.base());
}
};
#endif /* STRONG_TYPEDEF_TYPE_HPP */

View File

@ -27,7 +27,6 @@
#include "effectvehicle_func.h"
#include "landscape_type.h"
#include "animated_tile_func.h"
#include "core/flatset_type.hpp"
#include "core/random_func.hpp"
#include "object_base.h"
#include "company_func.h"
@ -43,6 +42,8 @@
#include "table/strings.h"
#include "table/sprites.h"
#include <unordered_set>
#include "safeguards.h"
extern const TileTypeProcs
@ -1298,28 +1299,26 @@ public:
*/
static std::tuple<bool, bool> FlowRiver(TileIndex spring, TileIndex begin, uint min_river_length)
{
uint height_begin = TileHeight(begin);
if (IsWaterTile(begin)) {
return { DistanceManhattan(spring, begin) > min_river_length, GetTileZ(begin) == 0 };
}
FlatSet<TileIndex> marks;
int height_begin = TileHeight(begin);
std::unordered_set<TileIndex> marks;
marks.insert(begin);
/* Breadth first search for the closest tile we can flow down to. */
std::list<TileIndex> queue;
std::vector<TileIndex> queue;
queue.push_back(begin);
/* Breadth first search for the closest tile we can flow down to. */
bool found = false;
uint count = 0; // Number of tiles considered; to be used for lake location guessing.
TileIndex end;
do {
end = queue.front();
queue.pop_front();
for (size_t i = 0; i != queue.size(); i++) {
end = queue[i];
uint height_end = TileHeight(end);
if (IsTileFlat(end) && (height_end < height_begin || (height_end == height_begin && IsWaterTile(end)))) {
int height_end;
if (IsTileFlat(end, &height_end) && (height_end < height_begin || (height_end == height_begin && IsWaterTile(end)))) {
found = true;
break;
}
@ -1328,31 +1327,29 @@ static std::tuple<bool, bool> FlowRiver(TileIndex spring, TileIndex begin, uint
TileIndex t = end + TileOffsByDiagDir(d);
if (IsValidTile(t) && !marks.contains(t) && FlowsDown(end, t)) {
marks.insert(t);
count++;
queue.push_back(t);
}
}
} while (!queue.empty());
}
bool main_river = false;
if (found) {
/* Flow further down hill. */
std::tie(found, main_river) = FlowRiver(spring, end, min_river_length);
} else if (count > 32) {
} else if (queue.size() > 32) {
/* Maybe we can make a lake. Find the Nth of the considered tiles. */
auto cit = marks.cbegin();
std::advance(cit, RandomRange(count - 1));
TileIndex lake_centre = *cit;
TileIndex lake_centre = queue[RandomRange(static_cast<uint32_t>(queue.size()))];
int height_lake;
if (IsValidTile(lake_centre) &&
/* A river, or lake, can only be built on flat slopes. */
IsTileFlat(lake_centre) &&
/* We want the lake to be built at the height of the river. */
TileHeight(begin) == TileHeight(lake_centre) &&
/* We don't want the lake at the entry of the valley. */
lake_centre != begin &&
/* We don't want lakes in the desert. */
(_settings_game.game_creation.landscape != LandscapeType::Tropic || GetTropicZone(lake_centre) != TROPICZONE_DESERT) &&
/* A river, or lake, can only be built on flat slopes. */
IsTileFlat(lake_centre, &height_lake) &&
/* We want the lake to be built at the height of the river. */
height_lake == height_begin &&
/* We only want a lake if the river is long enough. */
DistanceManhattan(spring, lake_centre) > min_river_length) {
end = lake_centre;
@ -1362,7 +1359,7 @@ static std::tuple<bool, bool> FlowRiver(TileIndex spring, TileIndex begin, uint
/* Run the loop twice, so artefacts from going circular in one direction get (mostly) hidden. */
for (uint loops = 0; loops < 2; ++loops) {
for (auto tile : SpiralTileSequence(lake_centre, diameter)) {
MakeLake(tile, height_begin);
MakeLake(tile, height_lake);
}
}
@ -1370,7 +1367,6 @@ static std::tuple<bool, bool> FlowRiver(TileIndex spring, TileIndex begin, uint
}
}
marks.clear();
if (found) RiverBuilder::Exec(begin, end, spring, main_river);
return { found, main_river };
}