Explorar el Código

AI - improve exploration, cancel deadends

Andrii Danylchenko hace 7 años
padre
commit
2466489e13
Se han modificado 3 ficheros con 41 adiciones y 34 borrados
  1. 23 16
      AI/VCAI/AIUtility.cpp
  2. 2 3
      AI/VCAI/AIUtility.h
  3. 16 15
      AI/VCAI/VCAI.cpp

+ 23 - 16
AI/VCAI/AIUtility.cpp

@@ -18,7 +18,6 @@
 #include "../../lib/mapObjects/CBank.h"
 #include "../../lib/mapObjects/CGTownInstance.h"
 #include "../../lib/mapObjects/CQuest.h"
-#include "../../lib/CPathfinder.h"
 #include "../../lib/mapping/CMapDefines.h"
 
 extern boost::thread_specific_ptr<CCallback> cb;
@@ -431,18 +430,31 @@ bool isBlockVisitObj(const int3 & pos)
 	return false;
 }
 
-int howManyTilesWillBeDiscovered(const int3 & pos, int radious, CCallback * cbp)
+bool hasReachableNeighbor(const int3 &pos, const CPathsInfo* paths, CCallback * cbp)
+{
+	for (crint3 dir : int3::getDirs())
+	{
+		int3 tile = pos + dir;
+		if (cbp->isInTheMap(tile) && paths->getPathInfo(tile)->reachable())
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+int howManyTilesWillBeDiscovered(const int3 & pos, int radious, CCallback * cbp, const CPathsInfo* pathsInfo)
 {
-	//TODO: do not explore dead-end boundaries
 	int ret = 0;
-	for(int x = pos.x - radious; x <= pos.x + radious; x++)
+	for (int x = pos.x - radious; x <= pos.x + radious; x++)
 	{
-		for(int y = pos.y - radious; y <= pos.y + radious; y++)
+		for (int y = pos.y - radious; y <= pos.y + radious; y++)
 		{
 			int3 npos = int3(x, y, pos.z);
-			if(cbp->isInTheMap(npos) && pos.dist2d(npos) - 0.5 < radious && !cbp->isVisible(npos))
+			if (cbp->isInTheMap(npos) && pos.dist2d(npos) - 0.5 < radious && !cbp->isVisible(npos))
 			{
-				if(!boundaryBetweenTwoPoints(pos, npos, cbp))
+				if (hasReachableNeighbor(npos, pathsInfo, cbp))
 					ret++;
 			}
 		}
@@ -458,14 +470,14 @@ bool boundaryBetweenTwoPoints(int3 pos1, int3 pos2, CCallback * cbp) //determine
 	int yMin = std::min(pos1.y, pos2.y);
 	int yMax = std::max(pos1.y, pos2.y);
 
-	for(int x = xMin; x <= xMax; ++x)
+	for (int x = xMin; x <= xMax; ++x)
 	{
-		for(int y = yMin; y <= yMax; ++y)
+		for (int y = yMin; y <= yMax; ++y)
 		{
 			int3 tile = int3(x, y, pos1.z); //use only on same level, ofc
-			if(std::abs(pos1.dist2d(tile) - pos2.dist2d(tile)) < 1.5)
+			if (std::abs(pos1.dist2d(tile) - pos2.dist2d(tile)) < 1.5)
 			{
-				if(!(cbp->isVisible(tile) && cbp->getTile(tile)->blocked)) //if there's invisible or unblocked tile between, it's good
+				if (!(cbp->isVisible(tile) && cbp->getTile(tile)->blocked)) //if there's invisible or unblocked tile between, it's good
 					return false;
 			}
 		}
@@ -473,11 +485,6 @@ bool boundaryBetweenTwoPoints(int3 pos1, int3 pos2, CCallback * cbp) //determine
 	return true; //if all are visible and blocked, we're at dead end
 }
 
-int howManyTilesWillBeDiscovered(int radious, int3 pos, crint3 dir)
-{
-	return howManyTilesWillBeDiscovered(pos + dir, radious, cb.get());
-}
-
 void getVisibleNeighbours(const std::vector<int3> & tiles, std::vector<int3> & out)
 {
 	for(const int3 & tile : tiles)

+ 2 - 3
AI/VCAI/AIUtility.h

@@ -17,6 +17,7 @@
 #include "../../lib/CStopWatch.h"
 #include "../../lib/mapObjects/CObjectHandler.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
+#include "../../lib/CPathfinder.h"
 
 class CCallback;
 
@@ -141,8 +142,7 @@ void foreach_tile_pos(CCallback * cbp, std::function<void(CCallback * cbp, const
 void foreach_neighbour(const int3 & pos, std::function<void(const int3 & pos)> foo);
 void foreach_neighbour(CCallback * cbp, const int3 & pos, std::function<void(CCallback * cbp, const int3 & pos)> foo); // avoid costly retrieval of thread-specific pointer
 
-int howManyTilesWillBeDiscovered(const int3 & pos, int radious, CCallback * cbp);
-int howManyTilesWillBeDiscovered(int radious, int3 pos, crint3 dir);
+int howManyTilesWillBeDiscovered(const int3 & pos, int radious, CCallback * cbp, const CPathsInfo * pathsInfo);
 void getVisibleNeighbours(const std::vector<int3> & tiles, std::vector<int3> & out);
 
 bool canBeEmbarkmentPoint(const TerrainTile * t, bool fromWater);
@@ -155,7 +155,6 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj);
 ui64 evaluateDanger(const CGObjectInstance * obj);
 ui64 evaluateDanger(crint3 tile, const CGHeroInstance * visitor);
 bool isSafeToVisit(HeroPtr h, crint3 tile);
-bool boundaryBetweenTwoPoints(int3 pos1, int3 pos2, CCallback * cbp);
 
 bool compareMovement(HeroPtr lhs, HeroPtr rhs);
 bool compareHeroStrength(HeroPtr h1, HeroPtr h2);

+ 16 - 15
AI/VCAI/VCAI.cpp

@@ -2625,22 +2625,21 @@ void VCAI::buildArmyIn(const CGTownInstance * t)
 
 int3 VCAI::explorationBestNeighbour(int3 hpos, int radius, HeroPtr h)
 {
-	int3 ourPos = h->convertPosition(h->pos, false);
 	std::map<int3, int> dstToRevealedTiles;
-	for(crint3 dir : int3::getDirs())
+	auto pathsInfo = cb->getPathsInfo(h.get());
+
+	for (crint3 dir : int3::getDirs())
 	{
 		int3 tile = hpos + dir;
-		if(cb->isInTheMap(tile))
+		if (cb->isInTheMap(tile))
 		{
-			if(ourPos != dir) //don't stand in place
+			if (isBlockVisitObj(tile))
+				continue;
+
+			if (isSafeToVisit(h, tile) && isAccessibleForHero(tile, h))
 			{
-				if(isSafeToVisit(h, tile) && isAccessibleForHero(tile, h))
-				{
-					if(isBlockVisitObj(tile))
-						continue;
-					else
-						dstToRevealedTiles[tile] = howManyTilesWillBeDiscovered(radius, hpos, dir);
-				}
+				auto distance = hpos.dist2d(tile); // diagonal movement opens more tiles but spends more mp
+				dstToRevealedTiles[tile] = howManyTilesWillBeDiscovered(tile, radius, cb.get(), pathsInfo) / distance;
 			}
 		}
 	}
@@ -2651,7 +2650,7 @@ int3 VCAI::explorationBestNeighbour(int3 hpos, int radius, HeroPtr h)
 	auto best = dstToRevealedTiles.begin();
 	for(auto i = dstToRevealedTiles.begin(); i != dstToRevealedTiles.end(); i++)
 	{
-		const CGPathNode * pn = cb->getPathsInfo(h.get())->getPathInfo(i->first);
+		const CGPathNode * pn = pathsInfo->getPathInfo(i->first);
 		//const TerrainTile *t = cb->getTile(i->first);
 		if(best->second < i->second && pn->reachable() && pn->accessible == CGPathNode::ACCESSIBLE)
 			best = i;
@@ -2668,6 +2667,7 @@ int3 VCAI::explorationNewPoint(HeroPtr h)
 	int radius = h->getSightRadius();
 	CCallback * cbp = cb.get();
 	const CGHeroInstance * hero = h.get();
+	const CPathsInfo * pathsInfo = cbp->getPathsInfo(hero);
 
 	std::vector<std::vector<int3>> tiles; //tiles[distance_to_fow]
 	tiles.resize(radius);
@@ -2695,8 +2695,8 @@ int3 VCAI::explorationNewPoint(HeroPtr h)
 				continue;
 
 			CGPath path;
-			cb->getPathsInfo(hero)->getPath(path, tile);
-			float ourValue = (float)howManyTilesWillBeDiscovered(tile, radius, cbp) / (path.nodes.size() + 1); //+1 prevents erratic jumps
+			pathsInfo->getPath(path, tile);
+			float ourValue = (float)howManyTilesWillBeDiscovered(tile, radius, cbp, pathsInfo) / (path.nodes.size() + 1); //+1 prevents erratic jumps
 
 			if(ourValue > bestValue) //avoid costly checks of tiles that don't reveal much
 			{
@@ -2722,6 +2722,7 @@ int3 VCAI::explorationDesperate(HeroPtr h)
 	tiles.resize(radius);
 
 	CCallback * cbp = cb.get();
+	const CPathsInfo * pathsInfo = cbp->getPathsInfo(h.get());
 
 	foreach_tile_pos([&](const int3 & pos)
 	{
@@ -2741,7 +2742,7 @@ int3 VCAI::explorationDesperate(HeroPtr h)
 		{
 			if(cbp->getTile(tile)->blocked) //does it shorten the time?
 				continue;
-			if(!howManyTilesWillBeDiscovered(tile, radius, cbp)) //avoid costly checks of tiles that don't reveal much
+			if(!howManyTilesWillBeDiscovered(tile, radius, cbp, pathsInfo)) //avoid costly checks of tiles that don't reveal much
 				continue;
 
 			auto t = sm->firstTileToGet(h, tile);