1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-14 02:33:51 +02:00

AI - improve exploration, cancel deadends

This commit is contained in:
Andrii Danylchenko 2018-06-16 14:56:49 +03:00
parent 8798e6e52b
commit 2466489e13
3 changed files with 42 additions and 35 deletions

View File

@ -18,7 +18,6 @@
#include "../../lib/mapObjects/CBank.h" #include "../../lib/mapObjects/CBank.h"
#include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/mapObjects/CGTownInstance.h"
#include "../../lib/mapObjects/CQuest.h" #include "../../lib/mapObjects/CQuest.h"
#include "../../lib/CPathfinder.h"
#include "../../lib/mapping/CMapDefines.h" #include "../../lib/mapping/CMapDefines.h"
extern boost::thread_specific_ptr<CCallback> cb; extern boost::thread_specific_ptr<CCallback> cb;
@ -431,18 +430,31 @@ bool isBlockVisitObj(const int3 & pos)
return false; return false;
} }
int howManyTilesWillBeDiscovered(const int3 & pos, int radious, CCallback * cbp) bool hasReachableNeighbor(const int3 &pos, const CPathsInfo* paths, CCallback * cbp)
{ {
//TODO: do not explore dead-end boundaries for (crint3 dir : int3::getDirs())
int ret = 0;
for(int x = pos.x - radious; x <= pos.x + radious; x++)
{ {
for(int y = pos.y - radious; y <= pos.y + radious; y++) 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)
{
int ret = 0;
for (int x = pos.x - radious; x <= pos.x + radious; x++)
{
for (int y = pos.y - radious; y <= pos.y + radious; y++)
{ {
int3 npos = int3(x, y, pos.z); 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++; ret++;
} }
} }
@ -458,14 +470,14 @@ bool boundaryBetweenTwoPoints(int3 pos1, int3 pos2, CCallback * cbp) //determine
int yMin = std::min(pos1.y, pos2.y); int yMin = std::min(pos1.y, pos2.y);
int yMax = std::max(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 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; 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 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) void getVisibleNeighbours(const std::vector<int3> & tiles, std::vector<int3> & out)
{ {
for(const int3 & tile : tiles) for(const int3 & tile : tiles)

View File

@ -17,6 +17,7 @@
#include "../../lib/CStopWatch.h" #include "../../lib/CStopWatch.h"
#include "../../lib/mapObjects/CObjectHandler.h" #include "../../lib/mapObjects/CObjectHandler.h"
#include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGHeroInstance.h"
#include "../../lib/CPathfinder.h"
class CCallback; 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(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 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(const int3 & pos, int radious, CCallback * cbp, const CPathsInfo * pathsInfo);
int howManyTilesWillBeDiscovered(int radious, int3 pos, crint3 dir);
void getVisibleNeighbours(const std::vector<int3> & tiles, std::vector<int3> & out); void getVisibleNeighbours(const std::vector<int3> & tiles, std::vector<int3> & out);
bool canBeEmbarkmentPoint(const TerrainTile * t, bool fromWater); 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(const CGObjectInstance * obj);
ui64 evaluateDanger(crint3 tile, const CGHeroInstance * visitor); ui64 evaluateDanger(crint3 tile, const CGHeroInstance * visitor);
bool isSafeToVisit(HeroPtr h, crint3 tile); bool isSafeToVisit(HeroPtr h, crint3 tile);
bool boundaryBetweenTwoPoints(int3 pos1, int3 pos2, CCallback * cbp);
bool compareMovement(HeroPtr lhs, HeroPtr rhs); bool compareMovement(HeroPtr lhs, HeroPtr rhs);
bool compareHeroStrength(HeroPtr h1, HeroPtr h2); bool compareHeroStrength(HeroPtr h1, HeroPtr h2);

View File

@ -2625,22 +2625,21 @@ void VCAI::buildArmyIn(const CGTownInstance * t)
int3 VCAI::explorationBestNeighbour(int3 hpos, int radius, HeroPtr h) int3 VCAI::explorationBestNeighbour(int3 hpos, int radius, HeroPtr h)
{ {
int3 ourPos = h->convertPosition(h->pos, false);
std::map<int3, int> dstToRevealedTiles; 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; int3 tile = hpos + dir;
if(cb->isInTheMap(tile)) if (cb->isInTheMap(tile))
{ {
if(ourPos != dir) //don't stand in place if (isBlockVisitObj(tile))
{
if(isSafeToVisit(h, tile) && isAccessibleForHero(tile, h))
{
if(isBlockVisitObj(tile))
continue; continue;
else
dstToRevealedTiles[tile] = howManyTilesWillBeDiscovered(radius, hpos, dir); if (isSafeToVisit(h, tile) && isAccessibleForHero(tile, h))
} {
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(); auto best = dstToRevealedTiles.begin();
for(auto i = dstToRevealedTiles.begin(); i != dstToRevealedTiles.end(); i++) 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); //const TerrainTile *t = cb->getTile(i->first);
if(best->second < i->second && pn->reachable() && pn->accessible == CGPathNode::ACCESSIBLE) if(best->second < i->second && pn->reachable() && pn->accessible == CGPathNode::ACCESSIBLE)
best = i; best = i;
@ -2668,6 +2667,7 @@ int3 VCAI::explorationNewPoint(HeroPtr h)
int radius = h->getSightRadius(); int radius = h->getSightRadius();
CCallback * cbp = cb.get(); CCallback * cbp = cb.get();
const CGHeroInstance * hero = h.get(); const CGHeroInstance * hero = h.get();
const CPathsInfo * pathsInfo = cbp->getPathsInfo(hero);
std::vector<std::vector<int3>> tiles; //tiles[distance_to_fow] std::vector<std::vector<int3>> tiles; //tiles[distance_to_fow]
tiles.resize(radius); tiles.resize(radius);
@ -2695,8 +2695,8 @@ int3 VCAI::explorationNewPoint(HeroPtr h)
continue; continue;
CGPath path; CGPath path;
cb->getPathsInfo(hero)->getPath(path, tile); pathsInfo->getPath(path, tile);
float ourValue = (float)howManyTilesWillBeDiscovered(tile, radius, cbp) / (path.nodes.size() + 1); //+1 prevents erratic jumps 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 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); tiles.resize(radius);
CCallback * cbp = cb.get(); CCallback * cbp = cb.get();
const CPathsInfo * pathsInfo = cbp->getPathsInfo(h.get());
foreach_tile_pos([&](const int3 & pos) 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? if(cbp->getTile(tile)->blocked) //does it shorten the time?
continue; 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; continue;
auto t = sm->firstTileToGet(h, tile); auto t = sm->firstTileToGet(h, tile);