mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-25 22:42:04 +02:00
First implementation of random connections
This commit is contained in:
@@ -256,59 +256,59 @@
|
|||||||
},
|
},
|
||||||
"connections" :
|
"connections" :
|
||||||
[
|
[
|
||||||
{ "a" : "1", "b" : "9", "guard" : 6000 },
|
{ "a" : "1", "b" : "9", "guard" : 6000, "road" : "true" },
|
||||||
{ "a" : "1", "b" : "21", "guard" : 3000 },
|
{ "a" : "1", "b" : "21", "guard" : 3000, "road" : "random" },
|
||||||
{ "a" : "1", "b" : "21", "guard" : 3000 },
|
{ "a" : "1", "b" : "21", "guard" : 3000, "road" : "true" },
|
||||||
|
|
||||||
{ "a" : "2", "b" : "10", "guard" : 6000 },
|
{ "a" : "2", "b" : "10", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "2", "b" : "22", "guard" : 3000 },
|
{ "a" : "2", "b" : "22", "guard" : 3000, "road" : "random" },
|
||||||
{ "a" : "2", "b" : "22", "guard" : 3000 },
|
{ "a" : "2", "b" : "22", "guard" : 3000, "road" : "random" },
|
||||||
|
|
||||||
{ "a" : "3", "b" : "21", "guard" : 3000 },
|
{ "a" : "3", "b" : "21", "guard" : 3000, "road" : "true" },
|
||||||
{ "a" : "3", "b" : "23", "guard" : 3000 },
|
{ "a" : "3", "b" : "23", "guard" : 3000, "road" : "false" },
|
||||||
{ "a" : "3", "b" : "24", "guard" : 3000 },
|
{ "a" : "3", "b" : "24", "guard" : 3000, "road" : "random" },
|
||||||
|
|
||||||
{ "a" : "4", "b" : "22", "guard" : 3000 },
|
{ "a" : "4", "b" : "22", "guard" : 3000, "road" : "random" },
|
||||||
{ "a" : "4", "b" : "23", "guard" : 3000 },
|
{ "a" : "4", "b" : "23", "guard" : 3000, "road" : "false" },
|
||||||
{ "a" : "4", "b" : "25", "guard" : 3000 },
|
{ "a" : "4", "b" : "25", "guard" : 3000, "road" : "true" },
|
||||||
|
|
||||||
{ "a" : "5", "b" : "13", "guard" : 6000 },
|
{ "a" : "5", "b" : "13", "guard" : 6000, "road" : "true" },
|
||||||
{ "a" : "5", "b" : "24", "guard" : 3000 },
|
{ "a" : "5", "b" : "24", "guard" : 3000, "road" : "random" },
|
||||||
{ "a" : "5", "b" : "24", "guard" : 3000 },
|
{ "a" : "5", "b" : "24", "guard" : 3000, "road" : "random" },
|
||||||
|
|
||||||
{ "a" : "6", "b" : "14", "guard" : 6000 },
|
{ "a" : "6", "b" : "14", "guard" : 6000 },
|
||||||
{ "a" : "6", "b" : "25", "guard" : 3000 },
|
{ "a" : "6", "b" : "25", "guard" : 3000, "road" : "random" },
|
||||||
{ "a" : "6", "b" : "25", "guard" : 3000 },
|
{ "a" : "6", "b" : "25", "guard" : 3000, "road" : "true" },
|
||||||
|
|
||||||
{ "a" : "7", "b" : "21", "guard" : 6000 },
|
{ "a" : "7", "b" : "21", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "7", "b" : "21", "guard" : 6000 },
|
{ "a" : "7", "b" : "21", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "8", "b" : "22", "guard" : 6000 },
|
{ "a" : "8", "b" : "22", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "8", "b" : "22", "guard" : 6000 },
|
{ "a" : "8", "b" : "22", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "15", "b" : "24", "guard" : 6000 },
|
{ "a" : "15", "b" : "24", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "15", "b" : "24", "guard" : 6000 },
|
{ "a" : "15", "b" : "24", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "16", "b" : "25", "guard" : 6000 },
|
{ "a" : "16", "b" : "25", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "16", "b" : "25", "guard" : 6000 },
|
{ "a" : "16", "b" : "25", "guard" : 6000, "road" : "random" },
|
||||||
|
|
||||||
{ "a" : "9", "b" : "10", "guard" : 6000 },
|
{ "a" : "9", "b" : "10", "guard" : 6000, "road" : "true" },
|
||||||
{ "a" : "9", "b" : "21", "guard" : 6000 },
|
{ "a" : "9", "b" : "21", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "9", "b" : "23", "guard" : 6000 },
|
{ "a" : "9", "b" : "23", "guard" : 6000, "road" : "false" },
|
||||||
{ "a" : "10", "b" : "22", "guard" : 6000 },
|
{ "a" : "10", "b" : "22", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "10", "b" : "23", "guard" : 6000 },
|
{ "a" : "10", "b" : "23", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "13", "b" : "23", "guard" : 6000 },
|
{ "a" : "13", "b" : "23", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "13", "b" : "24", "guard" : 6000 },
|
{ "a" : "13", "b" : "24", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "13", "b" : "14", "guard" : 6000 },
|
{ "a" : "13", "b" : "14", "guard" : 6000, "road" : "true" },
|
||||||
{ "a" : "14", "b" : "23", "guard" : 6000 },
|
{ "a" : "14", "b" : "23", "guard" : 6000, "road" : "false" },
|
||||||
{ "a" : "14", "b" : "25", "guard" : 6000 },
|
{ "a" : "14", "b" : "25", "guard" : 6000, "road" : "random" },
|
||||||
|
|
||||||
{ "a" : "11", "b" : "21", "guard" : 6000 },
|
{ "a" : "11", "b" : "21", "guard" : 6000, "road" : "true" },
|
||||||
{ "a" : "11", "b" : "24", "guard" : 6000 },
|
{ "a" : "11", "b" : "24", "guard" : 6000, "road" : "random" },
|
||||||
{ "a" : "12", "b" : "22", "guard" : 6000 },
|
{ "a" : "12", "b" : "22", "guard" : 6000, "road" : "true" },
|
||||||
{ "a" : "12", "b" : "25", "guard" : 6000 },
|
{ "a" : "12", "b" : "25", "guard" : 6000, "road" : "random" },
|
||||||
|
|
||||||
{ "a" : "17", "b" : "21", "guard" : 9000 },
|
{ "a" : "17", "b" : "21", "guard" : 9000, "road" : "random" },
|
||||||
{ "a" : "18", "b" : "22", "guard" : 9000 },
|
{ "a" : "18", "b" : "22", "guard" : 9000, "road" : "random" },
|
||||||
{ "a" : "19", "b" : "24", "guard" : 9000 },
|
{ "a" : "19", "b" : "24", "guard" : 9000, "road" : "random" },
|
||||||
{ "a" : "20", "b" : "25", "guard" : 9000 },
|
{ "a" : "20", "b" : "25", "guard" : 9000, "road" : "random" },
|
||||||
|
|
||||||
{ "a" : "21", "b" : "22", "type": "wide" },
|
{ "a" : "21", "b" : "22", "type": "wide" },
|
||||||
{ "a" : "24", "b" : "25", "type": "wide" }
|
{ "a" : "24", "b" : "25", "type": "wide" }
|
||||||
|
|||||||
@@ -328,6 +328,7 @@ void CMapGenerator::genZones()
|
|||||||
{
|
{
|
||||||
placer->placeZones(rand.get());
|
placer->placeZones(rand.get());
|
||||||
placer->assignZones(rand.get());
|
placer->assignZones(rand.get());
|
||||||
|
placer->dropRandomRoads(rand.get());
|
||||||
|
|
||||||
logGlobal->info("Zones generated successfully");
|
logGlobal->info("Zones generated successfully");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "../mapping/CMapEditManager.h"
|
#include "../mapping/CMapEditManager.h"
|
||||||
#include "../GameLibrary.h"
|
#include "../GameLibrary.h"
|
||||||
#include "CMapGenOptions.h"
|
#include "CMapGenOptions.h"
|
||||||
|
#include "CRmgTemplate.h"
|
||||||
#include "RmgMap.h"
|
#include "RmgMap.h"
|
||||||
#include "Zone.h"
|
#include "Zone.h"
|
||||||
#include "Functions.h"
|
#include "Functions.h"
|
||||||
@@ -1004,6 +1005,162 @@ void CZonePlacer::assignZones(vstd::RNG * rand)
|
|||||||
logGlobal->info("Finished zone colouring");
|
logGlobal->info("Finished zone colouring");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CZonePlacer::dropRandomRoads(vstd::RNG * rand)
|
||||||
|
{
|
||||||
|
auto zones = map.getZones();
|
||||||
|
|
||||||
|
//First, build a graph of road connections
|
||||||
|
std::map<TRmgTemplateZoneId, std::set<TRmgTemplateZoneId>> roadGraph;
|
||||||
|
std::vector<rmg::ZoneConnection> randomConnections;
|
||||||
|
std::vector<rmg::ZoneConnection> fixedConnections;
|
||||||
|
|
||||||
|
//Collect all road connections and build initial graph
|
||||||
|
for(const auto & zone : zones)
|
||||||
|
{
|
||||||
|
for(const auto & connection : zone.second->getConnections())
|
||||||
|
{
|
||||||
|
if(connection.getRoadOption() == rmg::ERoadOption::ROAD_TRUE)
|
||||||
|
{
|
||||||
|
roadGraph[connection.getZoneA()].insert(connection.getZoneB());
|
||||||
|
roadGraph[connection.getZoneB()].insert(connection.getZoneA());
|
||||||
|
fixedConnections.push_back(connection);
|
||||||
|
}
|
||||||
|
else if(connection.getRoadOption() == rmg::ERoadOption::ROAD_RANDOM)
|
||||||
|
{
|
||||||
|
roadGraph[connection.getZoneA()].insert(connection.getZoneB());
|
||||||
|
roadGraph[connection.getZoneB()].insert(connection.getZoneA());
|
||||||
|
randomConnections.push_back(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Find all connected components in the initial graph
|
||||||
|
std::map<TRmgTemplateZoneId, int> zoneToComponent;
|
||||||
|
int numComponents = 0;
|
||||||
|
|
||||||
|
auto dfsComponent = [&](TRmgTemplateZoneId start, int component)
|
||||||
|
{
|
||||||
|
std::stack<TRmgTemplateZoneId> stack;
|
||||||
|
stack.push(start);
|
||||||
|
|
||||||
|
while(!stack.empty())
|
||||||
|
{
|
||||||
|
auto current = stack.top();
|
||||||
|
stack.pop();
|
||||||
|
|
||||||
|
if(zoneToComponent.find(current) != zoneToComponent.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
zoneToComponent[current] = component;
|
||||||
|
|
||||||
|
for(auto neighbor : roadGraph[current])
|
||||||
|
{
|
||||||
|
if(zoneToComponent.find(neighbor) == zoneToComponent.end())
|
||||||
|
{
|
||||||
|
stack.push(neighbor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Find all components
|
||||||
|
for(const auto & zone : zones)
|
||||||
|
{
|
||||||
|
if(zoneToComponent.find(zone.first) == zoneToComponent.end() && !roadGraph[zone.first].empty())
|
||||||
|
{
|
||||||
|
dfsComponent(zone.first, numComponents++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Process each component separately
|
||||||
|
for(int component = 0; component < numComponents; component++)
|
||||||
|
{
|
||||||
|
//Get random connections for this component
|
||||||
|
std::vector<rmg::ZoneConnection> componentRandomConnections;
|
||||||
|
for(const auto & conn : randomConnections)
|
||||||
|
{
|
||||||
|
if(zoneToComponent[conn.getZoneA()] == component)
|
||||||
|
{
|
||||||
|
componentRandomConnections.push_back(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Shuffle random connections
|
||||||
|
RandomGeneratorUtil::randomShuffle(componentRandomConnections, *rand);
|
||||||
|
|
||||||
|
//Try removing each random connection
|
||||||
|
for(const auto & conn : componentRandomConnections)
|
||||||
|
{
|
||||||
|
//Temporarily remove this connection
|
||||||
|
roadGraph[conn.getZoneA()].erase(conn.getZoneB());
|
||||||
|
roadGraph[conn.getZoneB()].erase(conn.getZoneA());
|
||||||
|
|
||||||
|
//Check if graph remains connected
|
||||||
|
bool canRemove = true;
|
||||||
|
std::set<TRmgTemplateZoneId> visited;
|
||||||
|
|
||||||
|
//Start DFS from any zone in this component
|
||||||
|
auto startZone = conn.getZoneA();
|
||||||
|
std::stack<TRmgTemplateZoneId> stack;
|
||||||
|
stack.push(startZone);
|
||||||
|
|
||||||
|
while(!stack.empty())
|
||||||
|
{
|
||||||
|
auto current = stack.top();
|
||||||
|
stack.pop();
|
||||||
|
|
||||||
|
if(visited.find(current) != visited.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
visited.insert(current);
|
||||||
|
|
||||||
|
for(auto neighbor : roadGraph[current])
|
||||||
|
{
|
||||||
|
if(visited.find(neighbor) == visited.end())
|
||||||
|
{
|
||||||
|
stack.push(neighbor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if all zones in this component are still reachable
|
||||||
|
for(const auto & zone : zones)
|
||||||
|
{
|
||||||
|
if(zoneToComponent[zone.first] == component && !roadGraph[zone.first].empty())
|
||||||
|
{
|
||||||
|
if(visited.find(zone.first) == visited.end())
|
||||||
|
{
|
||||||
|
canRemove = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!canRemove)
|
||||||
|
{
|
||||||
|
//Restore connection if removing it would break connectivity
|
||||||
|
roadGraph[conn.getZoneA()].insert(conn.getZoneB());
|
||||||
|
roadGraph[conn.getZoneB()].insert(conn.getZoneA());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Mark this connection as having no road
|
||||||
|
for(auto & zonePtr : zones)
|
||||||
|
{
|
||||||
|
for(auto & connection : zonePtr.second->getConnections())
|
||||||
|
{
|
||||||
|
if(connection.getId() == conn.getId())
|
||||||
|
{
|
||||||
|
const_cast<rmg::ZoneConnection&>(connection) = conn; //FIXME: avoid const_cast
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const TDistanceMap& CZonePlacer::getDistanceMap()
|
const TDistanceMap& CZonePlacer::getDistanceMap()
|
||||||
{
|
{
|
||||||
return distancesBetweenZones;
|
return distancesBetweenZones;
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public:
|
|||||||
void placeOnGrid(vstd::RNG* rand);
|
void placeOnGrid(vstd::RNG* rand);
|
||||||
float scaleForceBetweenZones(const std::shared_ptr<Zone> zoneA, const std::shared_ptr<Zone> zoneB) const;
|
float scaleForceBetweenZones(const std::shared_ptr<Zone> zoneA, const std::shared_ptr<Zone> zoneB) const;
|
||||||
void assignZones(vstd::RNG * rand);
|
void assignZones(vstd::RNG * rand);
|
||||||
|
void dropRandomRoads(vstd::RNG * rand);
|
||||||
|
|
||||||
const TDistanceMap & getDistanceMap();
|
const TDistanceMap & getDistanceMap();
|
||||||
|
|
||||||
|
|||||||
@@ -477,8 +477,7 @@ void ConnectionsPlacer::collectNeighbourZones()
|
|||||||
|
|
||||||
bool ConnectionsPlacer::shouldGenerateRoad(const rmg::ZoneConnection& connection) const
|
bool ConnectionsPlacer::shouldGenerateRoad(const rmg::ZoneConnection& connection) const
|
||||||
{
|
{
|
||||||
return connection.getRoadOption() == rmg::ERoadOption::ROAD_TRUE ||
|
return connection.getRoadOption() == rmg::ERoadOption::ROAD_TRUE;
|
||||||
(connection.getRoadOption() == rmg::ERoadOption::ROAD_RANDOM && zone.getRand().nextDouble(0, 1) >= 0.5f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionsPlacer::createBorder()
|
void ConnectionsPlacer::createBorder()
|
||||||
|
|||||||
Reference in New Issue
Block a user