1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-06 09:09:40 +02:00

- Check full object area for minimum distance requirement

- Add option to optimize both for max distance and custom weight
This commit is contained in:
Tomasz Zieliński
2023-12-12 07:40:54 +01:00
parent 3cf22f0395
commit e5f60f063c
3 changed files with 64 additions and 56 deletions

View File

@@ -238,15 +238,14 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg
RecursiveLock lock(externalAccessMutex); RecursiveLock lock(externalAccessMutex);
return placeAndConnectObject(searchArea, obj, [this, min_dist, &obj](const int3 & tile) return placeAndConnectObject(searchArea, obj, [this, min_dist, &obj](const int3 & tile)
{ {
auto ti = map.getTileInfo(tile); float bestDistance = 10e9;
float dist = ti.getNearestObjectDistance();
if(dist < min_dist)
return -1.f;
for(const auto & t : obj.getArea().getTilesVector()) for(const auto & t : obj.getArea().getTilesVector())
{ {
if(map.getTileInfo(t).getNearestObjectDistance() < min_dist) float distance = map.getTileInfo(t).getNearestObjectDistance();
if(distance < min_dist)
return -1.f; return -1.f;
else
vstd::amin(bestDistance, distance);
} }
rmg::Area perimeter; rmg::Area perimeter;
@@ -298,7 +297,7 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg
} }
} }
return dist; return bestDistance;
}, isGuarded, onlyStraight, optimizer); }, isGuarded, onlyStraight, optimizer);
} }
@@ -513,6 +512,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
if(map.isOnMap(i) && map.isPossible(i)) if(map.isOnMap(i) && map.isPossible(i))
map.setOccupied(i, ETileType::BLOCKED); map.setOccupied(i, ETileType::BLOCKED);
} }
lock.unlock();
if (updateDistance) if (updateDistance)
{ {
@@ -535,6 +535,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
auto manager = map.getZones().at(id)->getModificator<ObjectManager>(); auto manager = map.getZones().at(id)->getModificator<ObjectManager>();
if (manager) if (manager)
{ {
// TODO: Update distances for perimeter of guarded object, not just treasures
manager->updateDistances(object); manager->updateDistances(object);
} }
} }

View File

@@ -48,7 +48,8 @@ public:
{ {
NONE = 0x00000000, NONE = 0x00000000,
WEIGHT = 0x00000001, WEIGHT = 0x00000001,
DISTANCE = 0x00000010 DISTANCE = 0x00000010,
BOTH = 0x00000011
}; };
public: public:

View File

@@ -837,7 +837,7 @@ void TreasurePlacer::createTreasures(ObjectManager& manager)
int value = std::accumulate(treasurePileInfos.begin(), treasurePileInfos.end(), 0, [](int v, const ObjectInfo* oi) {return v + oi->value; }); int value = std::accumulate(treasurePileInfos.begin(), treasurePileInfos.end(), 0, [](int v, const ObjectInfo* oi) {return v + oi->value; });
const ui32 maxPileGenerationAttemps = 2; const ui32 maxPileGenerationAttemps = 2;
for (ui32 attempt = 0; attempt <= maxPileGenerationAttemps; attempt++) for (ui32 attempt = 0; attempt < maxPileGenerationAttemps; attempt++)
{ {
auto rmgObject = constructTreasurePile(treasurePileInfos, attempt == maxAttempts); auto rmgObject = constructTreasurePile(treasurePileInfos, attempt == maxAttempts);
@@ -865,40 +865,52 @@ void TreasurePlacer::createTreasures(ObjectManager& manager)
{ {
const bool guarded = rmgObject.isGuarded(); const bool guarded = rmgObject.isGuarded();
for (int attempt = 0; attempt <= maxAttempts;)
{
auto path = rmg::Path::invalid(); auto path = rmg::Path::invalid();
Zone::Lock lock(zone.areaMutex); //We are going to subtract this area Zone::Lock lock(zone.areaMutex); //We are going to subtract this area
auto possibleArea = zone.areaPossible(); auto possibleArea = zone.areaPossible();
possibleArea.erase_if([this, &minDistance](const int3& tile) -> bool
{
auto ti = map.getTileInfo(tile);
return (ti.getNearestObjectDistance() < minDistance);
});
if (guarded) if (guarded)
{ {
path = manager.placeAndConnectObject(possibleArea, rmgObject, [this, &rmgObject, &minDistance, &manager](const int3& tile) path = manager.placeAndConnectObject(possibleArea, rmgObject, [this, &rmgObject, &minDistance, &manager](const int3& tile)
{ {
auto ti = map.getTileInfo(tile); float bestDistance = 10e9;
if (ti.getNearestObjectDistance() < minDistance)
return -1.f;
for (const auto& t : rmgObject.getArea().getTilesVector()) for (const auto& t : rmgObject.getArea().getTilesVector())
{ {
if (map.getTileInfo(t).getNearestObjectDistance() < minDistance) float distance = map.getTileInfo(t).getNearestObjectDistance();
if (distance < minDistance)
return -1.f; return -1.f;
else
vstd::amin(bestDistance, distance);
} }
auto guardedArea = rmgObject.instances().back()->getAccessibleArea(); auto guardedArea = rmgObject.instances().back()->getAccessibleArea();
auto areaToBlock = rmgObject.getAccessibleArea(true); auto areaToBlock = rmgObject.getAccessibleArea(true);
areaToBlock.subtract(guardedArea); areaToBlock.subtract(guardedArea);
// TODO: Does it help?
areaToBlock.erase_if([this](const int3& tile) -> bool
{
//Don't block tiles outside the map
return (!map.isOnMap(tile));
});
if (areaToBlock.overlap(zone.freePaths()) || areaToBlock.overlap(manager.getVisitableArea())) if (areaToBlock.overlap(zone.freePaths()) || areaToBlock.overlap(manager.getVisitableArea()))
return -1.f; return -1.f;
return ti.getNearestObjectDistance(); return bestDistance;
}, guarded, false, ObjectManager::OptimizeType::DISTANCE); }, guarded, false, ObjectManager::OptimizeType::BOTH);
} }
else else
{ {
path = manager.placeAndConnectObject(possibleArea, rmgObject, minDistance, guarded, false, ObjectManager::OptimizeType::DISTANCE); path = manager.placeAndConnectObject(possibleArea, rmgObject, minDistance, guarded, false, ObjectManager::OptimizeType::DISTANCE);
} }
lock.unlock();
if (path.valid()) if (path.valid())
{ {
@@ -914,12 +926,6 @@ void TreasurePlacer::createTreasures(ObjectManager& manager)
} }
zone.connectPath(path); zone.connectPath(path);
manager.placeObject(rmgObject, guarded, true); manager.placeObject(rmgObject, guarded, true);
break;
}
else
{
++attempt;
}
} }
} }
} }