mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-15 01:24:45 +02:00
AI: refactor explore further
This commit is contained in:
@ -143,6 +143,11 @@ std::vector<AIPath> AIhelper::getPathsToTile(HeroPtr hero, int3 tile)
|
|||||||
return pathfindingManager->getPathsToTile(hero, tile);
|
return pathfindingManager->getPathsToTile(hero, tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AIhelper::isTileAccessible(HeroPtr hero, int3 tile)
|
||||||
|
{
|
||||||
|
return pathfindingManager->isTileAccessible(hero, tile);
|
||||||
|
}
|
||||||
|
|
||||||
void AIhelper::resetPaths()
|
void AIhelper::resetPaths()
|
||||||
{
|
{
|
||||||
pathfindingManager->resetPaths();
|
pathfindingManager->resetPaths();
|
||||||
|
@ -59,6 +59,7 @@ public:
|
|||||||
Goals::TGoalVec howToVisitTile(int3 tile) override;
|
Goals::TGoalVec howToVisitTile(int3 tile) override;
|
||||||
Goals::TGoalVec howToVisitObj(ObjectIdRef obj) override;
|
Goals::TGoalVec howToVisitObj(ObjectIdRef obj) override;
|
||||||
std::vector<AIPath> getPathsToTile(HeroPtr hero, int3 tile) override;
|
std::vector<AIPath> getPathsToTile(HeroPtr hero, int3 tile) override;
|
||||||
|
bool isTileAccessible(HeroPtr hero, int3 tile) override;
|
||||||
void resetPaths() override;
|
void resetPaths() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "../../../lib/mapping/CMap.h" //for victory conditions
|
#include "../../../lib/mapping/CMap.h" //for victory conditions
|
||||||
#include "../../../lib/CPathfinder.h"
|
#include "../../../lib/CPathfinder.h"
|
||||||
#include "../../../lib/StringConstants.h"
|
#include "../../../lib/StringConstants.h"
|
||||||
|
#include "../../../lib/CPlayerState.h"
|
||||||
|
|
||||||
extern boost::thread_specific_ptr<CCallback> cb;
|
extern boost::thread_specific_ptr<CCallback> cb;
|
||||||
extern boost::thread_specific_ptr<VCAI> ai;
|
extern boost::thread_specific_ptr<VCAI> ai;
|
||||||
@ -175,9 +176,10 @@ bool Explore::hasReachableNeighbor(const int3 &pos, HeroPtr hero, CCallback * cb
|
|||||||
int3 tile = pos + dir;
|
int3 tile = pos + dir;
|
||||||
if(cbp->isInTheMap(tile))
|
if(cbp->isInTheMap(tile))
|
||||||
{
|
{
|
||||||
auto paths = vcai->ah->getPathsToTile(hero, tile);
|
auto isAccessible = vcai->ah->isTileAccessible(hero, tile);
|
||||||
|
|
||||||
return paths.size();
|
if(isAccessible)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,8 +190,9 @@ int Explore::howManyTilesWillBeDiscovered(
|
|||||||
const int3 & pos,
|
const int3 & pos,
|
||||||
int radious,
|
int radious,
|
||||||
CCallback * cbp,
|
CCallback * cbp,
|
||||||
HeroPtr hero,
|
const TeamState * ts,
|
||||||
std::function<bool (const int3 &)> filter) const
|
VCAI * aip,
|
||||||
|
HeroPtr h) const
|
||||||
{
|
{
|
||||||
int ret = 0;
|
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++)
|
||||||
@ -199,8 +202,8 @@ int Explore::howManyTilesWillBeDiscovered(
|
|||||||
int3 npos = int3(x, y, pos.z);
|
int3 npos = int3(x, y, pos.z);
|
||||||
if(cbp->isInTheMap(npos)
|
if(cbp->isInTheMap(npos)
|
||||||
&& pos.dist2d(npos) - 0.5 < radious
|
&& pos.dist2d(npos) - 0.5 < radious
|
||||||
&& !cbp->isVisible(npos)
|
&& !ts->fogOfWarMap[npos.x][npos.y][npos.z]
|
||||||
&& filter(npos))
|
&& hasReachableNeighbor(npos, h, cbp, aip))
|
||||||
{
|
{
|
||||||
ret++;
|
ret++;
|
||||||
}
|
}
|
||||||
@ -215,6 +218,7 @@ TSubgoal Explore::explorationBestNeighbour(int3 hpos, int radius, HeroPtr h) con
|
|||||||
std::map<int3, int> dstToRevealedTiles;
|
std::map<int3, int> dstToRevealedTiles;
|
||||||
VCAI * aip = ai.get();
|
VCAI * aip = ai.get();
|
||||||
CCallback * cbp = cb.get();
|
CCallback * cbp = cb.get();
|
||||||
|
const TeamState * ts = cbp->getPlayerTeam(ai->playerID);
|
||||||
|
|
||||||
for(crint3 dir : int3::getDirs())
|
for(crint3 dir : int3::getDirs())
|
||||||
{
|
{
|
||||||
@ -227,9 +231,7 @@ TSubgoal Explore::explorationBestNeighbour(int3 hpos, int radius, HeroPtr h) con
|
|||||||
if(isSafeToVisit(h, tile) && ai->isAccessibleForHero(tile, h))
|
if(isSafeToVisit(h, tile) && ai->isAccessibleForHero(tile, h))
|
||||||
{
|
{
|
||||||
auto distance = hpos.dist2d(tile); // diagonal movement opens more tiles but spends more mp
|
auto distance = hpos.dist2d(tile); // diagonal movement opens more tiles but spends more mp
|
||||||
int tilesDiscovered = howManyTilesWillBeDiscovered(tile, radius, cbp, h, [&](int3 neighbor) -> bool {
|
int tilesDiscovered = howManyTilesWillBeDiscovered(tile, radius, cbp, ts, aip, h);
|
||||||
return hasReachableNeighbor(neighbor, h, cbp, aip);
|
|
||||||
});
|
|
||||||
|
|
||||||
dstToRevealedTiles[tile] = tilesDiscovered / distance;
|
dstToRevealedTiles[tile] = tilesDiscovered / distance;
|
||||||
}
|
}
|
||||||
@ -259,6 +261,7 @@ TSubgoal Explore::explorationNewPoint(HeroPtr h) const
|
|||||||
int radius = h->getSightRadius();
|
int radius = h->getSightRadius();
|
||||||
CCallback * cbp = cb.get();
|
CCallback * cbp = cb.get();
|
||||||
VCAI *aip = ai.get();
|
VCAI *aip = ai.get();
|
||||||
|
const TeamState * ts = cbp->getPlayerTeam(aip->playerID);
|
||||||
|
|
||||||
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);
|
||||||
@ -275,7 +278,7 @@ TSubgoal Explore::explorationNewPoint(HeroPtr h) const
|
|||||||
|
|
||||||
for(int i = 1; i < radius; i++)
|
for(int i = 1; i < radius; i++)
|
||||||
{
|
{
|
||||||
getVisibleNeighbours(tiles[i - 1], tiles[i], cbp);
|
getVisibleNeighbours(tiles[i - 1], tiles[i], cbp, ts);
|
||||||
vstd::removeDuplicates(tiles[i]);
|
vstd::removeDuplicates(tiles[i]);
|
||||||
|
|
||||||
for(const int3 & tile : tiles[i])
|
for(const int3 & tile : tiles[i])
|
||||||
@ -289,7 +292,7 @@ TSubgoal Explore::explorationNewPoint(HeroPtr h) const
|
|||||||
if(goal->evaluationContext.movementCost == 0) // should not happen
|
if(goal->evaluationContext.movementCost == 0) // should not happen
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int tilesDiscovered = howManyTilesWillBeDiscovered(tile, radius, cbp, h, [](int3 neighbor) -> bool { return true; });
|
int tilesDiscovered = howManyTilesWillBeDiscovered(tile, radius, cbp, ts, aip, h);
|
||||||
float ourValue = (float) tilesDiscovered / goal->evaluationContext.movementCost; //+1 prevents erratic jumps
|
float ourValue = (float) tilesDiscovered / goal->evaluationContext.movementCost; //+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
|
||||||
@ -368,17 +371,17 @@ TSubgoal Explore::howToExplore(HeroPtr h) const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Explore::getVisibleNeighbours(const std::vector<int3> & tiles, std::vector<int3> & out, CCallback * cbp) const
|
void Explore::getVisibleNeighbours(const std::vector<int3> & tiles, std::vector<int3> & out, CCallback * cbp, const TeamState * ts) const
|
||||||
{
|
{
|
||||||
for(const int3 & tile : tiles)
|
for(const int3 & tile : tiles)
|
||||||
{
|
{
|
||||||
foreach_neighbour(tile, [&](int3 neighbour)
|
foreach_neighbour(cbp, tile, [&](CCallback * cbp, int3 neighbour)
|
||||||
{
|
{
|
||||||
if(cbp->isVisible(neighbour))
|
if(ts->fogOfWarMap[neighbour.x][neighbour.y][neighbour.z])
|
||||||
{
|
{
|
||||||
auto tile = cbp->getTile(neighbour);
|
//auto tile = cbp->getTile(neighbour);
|
||||||
|
|
||||||
if(tile && !tile->blocked)
|
//if(tile && !tile->blocked)
|
||||||
out.push_back(neighbour);
|
out.push_back(neighbour);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -42,12 +42,19 @@ namespace Goals
|
|||||||
TSubgoal explorationNewPoint(HeroPtr h) const;
|
TSubgoal explorationNewPoint(HeroPtr h) const;
|
||||||
TSubgoal explorationBestNeighbour(int3 hpos, int radius, HeroPtr h) const;
|
TSubgoal explorationBestNeighbour(int3 hpos, int radius, HeroPtr h) const;
|
||||||
bool hasReachableNeighbor(const int3 &pos, HeroPtr hero, CCallback * cbp, VCAI * vcai) const;
|
bool hasReachableNeighbor(const int3 &pos, HeroPtr hero, CCallback * cbp, VCAI * vcai) const;
|
||||||
void getVisibleNeighbours(const std::vector<int3> & tiles, std::vector<int3> & out, CCallback * cbp) const;
|
|
||||||
|
void getVisibleNeighbours(
|
||||||
|
const std::vector<int3> & tiles,
|
||||||
|
std::vector<int3> & out,
|
||||||
|
CCallback * cbp,
|
||||||
|
const TeamState * ts) const;
|
||||||
|
|
||||||
int howManyTilesWillBeDiscovered(
|
int howManyTilesWillBeDiscovered(
|
||||||
const int3 & pos,
|
const int3 & pos,
|
||||||
int radious,
|
int radious,
|
||||||
CCallback * cbp,
|
CCallback * cbp,
|
||||||
HeroPtr hero,
|
const TeamState * ts,
|
||||||
std::function<bool(const int3 &)> filter) const;
|
VCAI * aip,
|
||||||
|
HeroPtr h) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -189,6 +189,23 @@ bool AINodeStorage::hasBetterChain(const PathNodeInfo & source, CDestinationNode
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AINodeStorage::isTileAccessible(int3 pos, const EPathfindingLayer layer) const
|
||||||
|
{
|
||||||
|
std::vector<AIPath> paths;
|
||||||
|
auto chains = nodes[pos.x][pos.y][pos.z][layer];
|
||||||
|
auto initialPos = hero->visitablePos();
|
||||||
|
|
||||||
|
for(const AIPathNode & node : chains)
|
||||||
|
{
|
||||||
|
if(node.action != CGPathNode::ENodeAction::UNKNOWN)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<AIPath> AINodeStorage::getChainInfo(int3 pos, bool isOnLand) const
|
std::vector<AIPath> AINodeStorage::getChainInfo(int3 pos, bool isOnLand) const
|
||||||
{
|
{
|
||||||
std::vector<AIPath> paths;
|
std::vector<AIPath> paths;
|
||||||
|
@ -111,6 +111,7 @@ public:
|
|||||||
bool hasBetterChain(const PathNodeInfo & source, CDestinationNodeInfo & destination) const;
|
bool hasBetterChain(const PathNodeInfo & source, CDestinationNodeInfo & destination) const;
|
||||||
boost::optional<AIPathNode *> getOrCreateNode(const int3 & coord, const EPathfindingLayer layer, int chainNumber);
|
boost::optional<AIPathNode *> getOrCreateNode(const int3 & coord, const EPathfindingLayer layer, int chainNumber);
|
||||||
std::vector<AIPath> getChainInfo(int3 pos, bool isOnLand) const;
|
std::vector<AIPath> getChainInfo(int3 pos, bool isOnLand) const;
|
||||||
|
bool isTileAccessible(int3 pos, const EPathfindingLayer layer) const;
|
||||||
|
|
||||||
void setHero(HeroPtr heroPtr)
|
void setHero(HeroPtr heroPtr)
|
||||||
{
|
{
|
||||||
|
@ -28,9 +28,33 @@ void AIPathfinder::clear()
|
|||||||
storageMap.clear();
|
storageMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AIPathfinder::isTileAccessible(HeroPtr hero, int3 tile)
|
||||||
|
{
|
||||||
|
boost::unique_lock<boost::mutex> storageLock(storageMutex);
|
||||||
|
|
||||||
|
std::shared_ptr<AINodeStorage> nodeStorage = getOrCreateStorage(hero);
|
||||||
|
|
||||||
|
return nodeStorage->isTileAccessible(tile, EPathfindingLayer::LAND)
|
||||||
|
|| nodeStorage->isTileAccessible(tile, EPathfindingLayer::SAIL);
|
||||||
|
}
|
||||||
std::vector<AIPath> AIPathfinder::getPathInfo(HeroPtr hero, int3 tile)
|
std::vector<AIPath> AIPathfinder::getPathInfo(HeroPtr hero, int3 tile)
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::mutex> storageLock(storageMutex);
|
boost::unique_lock<boost::mutex> storageLock(storageMutex);
|
||||||
|
|
||||||
|
std::shared_ptr<AINodeStorage> nodeStorage = getOrCreateStorage(hero);
|
||||||
|
|
||||||
|
const TerrainTile * tileInfo = cb->getTile(tile, false);
|
||||||
|
|
||||||
|
if(!tileInfo)
|
||||||
|
{
|
||||||
|
return std::vector<AIPath>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeStorage->getChainInfo(tile, !tileInfo->isWater());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<AINodeStorage> AIPathfinder::getOrCreateStorage(HeroPtr hero)
|
||||||
|
{
|
||||||
std::shared_ptr<AINodeStorage> nodeStorage;
|
std::shared_ptr<AINodeStorage> nodeStorage;
|
||||||
|
|
||||||
if(!vstd::contains(storageMap, hero))
|
if(!vstd::contains(storageMap, hero))
|
||||||
@ -59,12 +83,6 @@ std::vector<AIPath> AIPathfinder::getPathInfo(HeroPtr hero, int3 tile)
|
|||||||
nodeStorage = storageMap.at(hero);
|
nodeStorage = storageMap.at(hero);
|
||||||
}
|
}
|
||||||
|
|
||||||
const TerrainTile * tileInfo = cb->getTile(tile, false);
|
return nodeStorage;
|
||||||
|
|
||||||
if(!tileInfo)
|
|
||||||
{
|
|
||||||
return std::vector<AIPath>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return nodeStorage->getChainInfo(tile, !tileInfo->isWater());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,5 +26,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
AIPathfinder(CPlayerSpecificInfoCallback * cb, VCAI * ai);
|
AIPathfinder(CPlayerSpecificInfoCallback * cb, VCAI * ai);
|
||||||
std::vector<AIPath> getPathInfo(HeroPtr hero, int3 tile);
|
std::vector<AIPath> getPathInfo(HeroPtr hero, int3 tile);
|
||||||
|
bool isTileAccessible(HeroPtr hero, int3 tile);
|
||||||
|
std::shared_ptr<AINodeStorage> getOrCreateStorage(HeroPtr hero);
|
||||||
void clear();
|
void clear();
|
||||||
};
|
};
|
||||||
|
@ -104,6 +104,11 @@ std::vector<AIPath> PathfindingManager::getPathsToTile(HeroPtr hero, int3 tile)
|
|||||||
return pathfinder->getPathInfo(hero, tile);
|
return pathfinder->getPathInfo(hero, tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PathfindingManager::isTileAccessible(HeroPtr hero, int3 tile)
|
||||||
|
{
|
||||||
|
return pathfinder->isTileAccessible(hero, tile);
|
||||||
|
}
|
||||||
|
|
||||||
Goals::TGoalVec PathfindingManager::findPath(
|
Goals::TGoalVec PathfindingManager::findPath(
|
||||||
HeroPtr hero,
|
HeroPtr hero,
|
||||||
crint3 dest,
|
crint3 dest,
|
||||||
|
@ -26,6 +26,7 @@ public:
|
|||||||
virtual Goals::TGoalVec howToVisitTile(int3 tile) = 0;
|
virtual Goals::TGoalVec howToVisitTile(int3 tile) = 0;
|
||||||
virtual Goals::TGoalVec howToVisitObj(ObjectIdRef obj) = 0;
|
virtual Goals::TGoalVec howToVisitObj(ObjectIdRef obj) = 0;
|
||||||
virtual std::vector<AIPath> getPathsToTile(HeroPtr hero, int3 tile) = 0;
|
virtual std::vector<AIPath> getPathsToTile(HeroPtr hero, int3 tile) = 0;
|
||||||
|
virtual bool isTileAccessible(HeroPtr hero, int3 tile) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PathfindingManager : public IPathfindingManager
|
class PathfindingManager : public IPathfindingManager
|
||||||
@ -46,6 +47,7 @@ public:
|
|||||||
Goals::TGoalVec howToVisitTile(int3 tile) override;
|
Goals::TGoalVec howToVisitTile(int3 tile) override;
|
||||||
Goals::TGoalVec howToVisitObj(ObjectIdRef obj) override;
|
Goals::TGoalVec howToVisitObj(ObjectIdRef obj) override;
|
||||||
std::vector<AIPath> getPathsToTile(HeroPtr hero, int3 tile) override;
|
std::vector<AIPath> getPathsToTile(HeroPtr hero, int3 tile) override;
|
||||||
|
bool isTileAccessible(HeroPtr hero, int3 tile) override;
|
||||||
void resetPaths() override;
|
void resetPaths() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Reference in New Issue
Block a user