瀏覽代碼

Cache SectorMap where possible and update when necessary.

DjWarmonger 10 年之前
父節點
當前提交
1e36f3cecd
共有 6 個文件被更改,包括 38 次插入33 次删除
  1. 1 1
      AI/VCAI/AIUtility.cpp
  2. 3 15
      AI/VCAI/Fuzzy.cpp
  3. 1 4
      AI/VCAI/Fuzzy.h
  4. 4 4
      AI/VCAI/Goals.cpp
  5. 24 8
      AI/VCAI/VCAI.cpp
  6. 5 1
      AI/VCAI/VCAI.h

+ 1 - 1
AI/VCAI/AIUtility.cpp

@@ -359,7 +359,7 @@ int3 whereToExplore(HeroPtr h)
 	int radius = h->getSightRadious();
 	int3 hpos = h->visitablePos();
 
-	SectorMap sm(h);
+	SectorMap &sm = ai->getCachedSectorMap(h);
 
 	//look for nearby objs -> visit them if they're close enouh
 	const int DIST_LIMIT = 3;

+ 3 - 15
AI/VCAI/Fuzzy.cpp

@@ -302,7 +302,7 @@ Goals::TSubgoal FuzzyHelper::chooseSolution (Goals::TGoalVec vec)
 	if (vec.empty()) //no possibilities found
 		return sptr(Goals::Invalid());
 
-	cachedSectorMaps.clear();
+	ai->cachedSectorMaps.clear();
 
 	//a trick to switch between heroes less often - calculatePaths is costly
 	auto sortByHeroes = [](const Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool
@@ -482,7 +482,7 @@ float FuzzyHelper::evaluate (Goals::ClearWayTo & g)
 	if (!g.hero.h)
 		throw cannotFulfillGoalException("ClearWayTo called without hero!");
 
-	int3 t = getCachedSectorMap(g.hero).firstTileToGet(g.hero, g.tile);
+	int3 t = ai->getCachedSectorMap(g.hero).firstTileToGet(g.hero, g.tile);
 
 	if (t.valid())
 	{
@@ -530,16 +530,4 @@ float FuzzyHelper::evaluate (Goals::AbstractGoal & g)
 void FuzzyHelper::setPriority (Goals::TSubgoal & g)
 {
 	g->setpriority(g->accept(this)); //this enforces returned value is set
-}
-
-SectorMap& FuzzyHelper::getCachedSectorMap(HeroPtr h)
-{
-	auto it = cachedSectorMaps.find(h);
-	if (it != cachedSectorMaps.end())
-		return it->second;
-	else
-	{
-		cachedSectorMaps.insert (std::make_pair(h, SectorMap(h)));
-		return cachedSectorMaps[h];
-	}
-}
+}

+ 1 - 4
AI/VCAI/Fuzzy.h

@@ -55,7 +55,7 @@ class FuzzyHelper
 		~EvalVisitTile();
 	} vt;
 
-	std::map <HeroPtr, SectorMap> cachedSectorMaps;
+	
 
 public:
 	enum RuleBlocks {BANK_DANGER, TACTICAL_ADVANTAGE, VISIT_TILE};
@@ -84,7 +84,4 @@ public:
 
 	Goals::TSubgoal chooseSolution (Goals::TGoalVec vec);
 	//shared_ptr<AbstractGoal> chooseSolution (std::vector<shared_ptr<AbstractGoal>> & vec);
-
-	//optimization - use one SM for every hero call
-	SectorMap& getCachedSectorMap (HeroPtr h);
 };

+ 4 - 4
AI/VCAI/Goals.cpp

@@ -483,7 +483,7 @@ TGoalVec ClearWayTo::getAllPossibleSubgoals()
 
 		//if our hero is trapped, make sure we request clearing the way from OUR perspective
 
-		SectorMap sm(h);
+		SectorMap &sm = ai->getCachedSectorMap(h);
 
 		int3 tileToHit = sm.firstTileToGet(h, tile);
 		if (!tileToHit.valid())
@@ -633,7 +633,7 @@ TGoalVec Explore::getAllPossibleSubgoals()
 
 	for (auto h : heroes)
 	{
-		SectorMap sm(h);
+		SectorMap &sm = ai->getCachedSectorMap(h);
 
 		for (auto obj : objs) //double loop, performance risk?
 		{
@@ -963,7 +963,7 @@ TGoalVec Conquer::getAllPossibleSubgoals()
 
 	for (auto h : cb->getHeroesInfo())
 	{
-		SectorMap sm(h);
+		SectorMap &sm = ai->getCachedSectorMap(h);
 		std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects
 
 		for (auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero
@@ -1093,7 +1093,7 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
 	}
 	for(auto h : cb->getHeroesInfo())
 	{
-		SectorMap sm(h);
+		SectorMap &sm = ai->getCachedSectorMap(h);
 		for (auto obj : objs)
 		{ //find safe dwelling
 			auto pos = obj->visitablePos();

+ 24 - 8
AI/VCAI/VCAI.cpp

@@ -115,6 +115,7 @@ void VCAI::heroMoved(const TryMoveHero & details)
 	NET_EVENT_HANDLER;
 
 	validateObject(details.id); //enemy hero may have left visible area
+	cachedSectorMaps.clear();
 
 	if(details.result == TryMoveHero::TELEPORTATION)
 	{
@@ -296,7 +297,7 @@ void VCAI::tileRevealed(const std::unordered_set<int3, ShashInt3> &pos)
 		for(const CGObjectInstance *obj : myCb->getVisitableObjs(tile))
 			addVisitableObj(obj);
 
-	clearHeroesUnableToExplore();
+	clearPathsInfo();
 }
 
 void VCAI::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query)
@@ -382,7 +383,7 @@ void VCAI::newObject(const CGObjectInstance * obj)
 	if(obj->isVisitable())
 		addVisitableObj(obj);
 
-	clearHeroesUnableToExplore();
+	cachedSectorMaps.clear();
 }
 
 void VCAI::objectRemoved(const CGObjectInstance *obj)
@@ -396,6 +397,8 @@ void VCAI::objectRemoved(const CGObjectInstance *obj)
 	for (auto h : cb->getHeroesInfo())
 		unreserveObject(h, obj);
 
+	cachedSectorMaps.clear(); //invalidate all paths
+
 	//TODO
 	//there are other places where CGObjectinstance ptrs are stored...
 	//
@@ -840,7 +843,7 @@ void VCAI::makeTurnInternal()
 bool VCAI::goVisitObj(const CGObjectInstance * obj, HeroPtr h)
 {
 	int3 dst = obj->visitablePos();
-	SectorMap sm(h);
+	SectorMap &sm = getCachedSectorMap(h);
 	logAi->debugStream() << boost::format("%s will try to visit %s at (%s)") % h->name % obj->getObjectName() % strFromInt3(dst);
 	int3 pos = sm.firstTileToGet(h, dst);
 	if (!pos.valid()) //rare case when we are already standing on one of potential objects
@@ -1378,7 +1381,7 @@ std::vector<const CGObjectInstance *> VCAI::getPossibleDestinations(HeroPtr h)
 {
 	validateVisitableObjs();
 	std::vector<const CGObjectInstance *> possibleDestinations;
-	SectorMap sm(h);
+	SectorMap &sm = getCachedSectorMap(h);
 	for(const CGObjectInstance *obj : visitableObjs)
 	{
 		if (isGoodForVisit(obj, h, sm))
@@ -1436,7 +1439,7 @@ void VCAI::wander(HeroPtr h)
 		validateVisitableObjs();
 		std::vector <ObjectIdRef> dests, tmp;
 
-		SectorMap sm(h);
+		SectorMap &sm = getCachedSectorMap(h);
 
 		range::copy(reservedHeroesMap[h], std::back_inserter(tmp)); //also visit our reserved objects - but they are not prioritized to avoid running back and forth
 		for (auto obj : tmp)
@@ -1649,9 +1652,10 @@ bool VCAI::isAbleToExplore (HeroPtr h)
 {
 	return !vstd::contains (heroesUnableToExplore, h);
 }
-void VCAI::clearHeroesUnableToExplore()
+void VCAI::clearPathsInfo()
 {
 	heroesUnableToExplore.clear();
+	cachedSectorMaps.clear();
 }
 
 void VCAI::validateVisitableObjs()
@@ -2533,8 +2537,7 @@ int3 VCAI::explorationNewPoint(HeroPtr h)
 
 int3 VCAI::explorationDesperate(HeroPtr h)
 {
-    //logAi->debugStream() << "Looking for an another place for exploration...";
-	SectorMap sm(h);
+	SectorMap &sm = getCachedSectorMap(h);
 	int radius = h->getSightRadious();
 	
 	std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
@@ -2691,6 +2694,7 @@ void VCAI::lostHero(HeroPtr h)
 		erase_if_present(reservedObjs, obj); //unreserve all objects for that hero
 	}
 	erase_if_present(reservedHeroesMap, h);
+	erase_if_present(cachedSectorMaps, h);
 }
 
 void VCAI::answerQuery(QueryID queryID, int selection)
@@ -2751,6 +2755,18 @@ TResources VCAI::freeResources() const
 	return myRes;
 }
 
+SectorMap& VCAI::getCachedSectorMap(HeroPtr h)
+{
+	auto it = cachedSectorMaps.find(h);
+	if (it != cachedSectorMaps.end())
+		return it->second;
+	else
+	{
+		cachedSectorMaps.insert(std::make_pair(h, SectorMap(h)));
+		return cachedSectorMaps[h];
+	}
+}
+
 AIStatus::AIStatus()
 {
 	battle = NO_BATTLE;

+ 5 - 1
AI/VCAI/VCAI.h

@@ -161,6 +161,8 @@ public:
 	std::set<const CGObjectInstance *> alreadyVisited;
 	std::set<const CGObjectInstance *> reservedObjs; //to be visited by specific hero
 
+	std::map <HeroPtr, SectorMap> cachedSectorMaps; //TODO: serialize? not necessary
+
 	TResources saving;
 
 	AIStatus status;
@@ -296,7 +298,7 @@ public:
 	void markHeroUnableToExplore (HeroPtr h);
 	void markHeroAbleToExplore (HeroPtr h);
 	bool isAbleToExplore (HeroPtr h);
-	void clearHeroesUnableToExplore();
+	void clearPathsInfo();
 
 	void validateObject(const CGObjectInstance *obj); //checks if object is still visible and if not, removes references to it
 	void validateObject(ObjectIdRef obj); //checks if object is still visible and if not, removes references to it
@@ -311,6 +313,8 @@ public:
 
 	const CGObjectInstance *getUnvisitedObj(const std::function<bool(const CGObjectInstance *)> &predicate);
 	bool isAccessibleForHero(const int3 & pos, HeroPtr h, bool includeAllies = false) const;
+	//optimization - use one SM for every hero call
+	SectorMap& getCachedSectorMap(HeroPtr h);
 
 	const CGTownInstance *findTownWithTavern() const;
 	bool canRecruitAnyHero(const CGTownInstance * t = NULL) const;