mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-06 09:09:40 +02:00
AI: replace SectorMap with new PathfinderManager
This commit is contained in:
234
AI/VCAI/Pathfinding/AINodeStorage.cpp
Normal file
234
AI/VCAI/Pathfinding/AINodeStorage.cpp
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* AIhelper.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "AINodeStorage.h"
|
||||
|
||||
|
||||
AINodeStorage::AINodeStorage(const int3 & Sizes)
|
||||
: sizes(Sizes)
|
||||
{
|
||||
nodes.resize(boost::extents[sizes.x][sizes.y][sizes.z][EPathfindingLayer::NUM_LAYERS][NUM_CHAINS]);
|
||||
}
|
||||
|
||||
AINodeStorage::~AINodeStorage()
|
||||
{
|
||||
}
|
||||
|
||||
AIPathNode * AINodeStorage::getAINode(CPathNodeInfo & nodeInfo) const
|
||||
{
|
||||
return static_cast<AIPathNode *>(nodeInfo.node);
|
||||
}
|
||||
|
||||
AIPathNode * AINodeStorage::getAINode(CGPathNode * node) const
|
||||
{
|
||||
return static_cast<AIPathNode *>(node);
|
||||
}
|
||||
|
||||
bool AINodeStorage::isBattleNode(CGPathNode * node) const
|
||||
{
|
||||
return getAINode(node)->chainMask & BATTLE_CHAIN > 0;
|
||||
}
|
||||
|
||||
AIPathNode * AINodeStorage::getNode(const int3 & coord, const EPathfindingLayer layer, int chainNumber)
|
||||
{
|
||||
return &nodes[coord.x][coord.y][coord.z][layer][chainNumber];
|
||||
}
|
||||
|
||||
CGPathNode * AINodeStorage::getInitialNode()
|
||||
{
|
||||
auto hpos = hero->getPosition(false);
|
||||
auto initialNode = getNode(hpos, hero->boat ? EPathfindingLayer::SAIL : EPathfindingLayer::LAND, 0);
|
||||
|
||||
initialNode->turns = 0;
|
||||
initialNode->moveRemains = hero->movement;
|
||||
initialNode->danger = 0;
|
||||
|
||||
return initialNode;
|
||||
}
|
||||
|
||||
void AINodeStorage::resetTile(const int3 & coord, EPathfindingLayer layer, CGPathNode::EAccessibility accessibility)
|
||||
{
|
||||
for(int i = 0; i < NUM_CHAINS; i++)
|
||||
{
|
||||
AIPathNode & heroNode = nodes[coord.x][coord.y][coord.z][layer][i];
|
||||
|
||||
heroNode.chainMask = i;
|
||||
heroNode.update(coord, layer, accessibility);
|
||||
}
|
||||
}
|
||||
|
||||
void AINodeStorage::commit(CDestinationNodeInfo & destination, CPathNodeInfo & source)
|
||||
{
|
||||
auto dstNode = getAINode(destination);
|
||||
auto srcNode = getAINode(source);
|
||||
|
||||
dstNode->moveRemains = destination.movementLeft;
|
||||
dstNode->turns = destination.turn;
|
||||
dstNode->danger = srcNode->danger;
|
||||
dstNode->action = destination.action;
|
||||
dstNode->theNodeBefore = srcNode->theNodeBefore;
|
||||
}
|
||||
|
||||
std::vector<CGPathNode *> AINodeStorage::calculateNeighbours(
|
||||
CPathNodeInfo & source,
|
||||
CPathfinderConfig * pathfinderConfig,
|
||||
CPathfinderHelper * pathfinderHelper)
|
||||
{
|
||||
std::vector<CGPathNode *> neighbours;
|
||||
auto srcNode = getAINode(source);
|
||||
auto accessibleNeighbourTiles = pathfinderHelper->getNeighbourTiles(source);
|
||||
|
||||
for(auto & neighbour : accessibleNeighbourTiles)
|
||||
{
|
||||
for(EPathfindingLayer i = EPathfindingLayer::LAND; i <= EPathfindingLayer::AIR; i.advance(1))
|
||||
{
|
||||
auto nextNode = getNode(neighbour, i, srcNode->chainMask);
|
||||
|
||||
if(nextNode->accessible == CGPathNode::NOT_SET)
|
||||
continue;
|
||||
|
||||
neighbours.push_back(nextNode);
|
||||
}
|
||||
}
|
||||
|
||||
return neighbours;
|
||||
}
|
||||
|
||||
std::vector<CGPathNode *> AINodeStorage::calculateTeleportations(
|
||||
CPathNodeInfo & source,
|
||||
CPathfinderConfig * pathfinderConfig,
|
||||
CPathfinderHelper * pathfinderHelper)
|
||||
{
|
||||
std::vector<CGPathNode *> neighbours;
|
||||
auto accessibleExits = pathfinderHelper->getTeleportExits(source);
|
||||
auto srcNode = getAINode(source);
|
||||
|
||||
for(auto & neighbour : accessibleExits)
|
||||
{
|
||||
auto node = getNode(neighbour, source.node->layer, srcNode->chainMask);
|
||||
|
||||
neighbours.push_back(node);
|
||||
}
|
||||
|
||||
return neighbours;
|
||||
}
|
||||
|
||||
bool AINodeStorage::hasBetterChain(CPathNodeInfo & source, CDestinationNodeInfo & destination) const
|
||||
{
|
||||
auto pos = destination.coord;
|
||||
auto chains = nodes[pos.x][pos.y][pos.z][EPathfindingLayer::LAND];
|
||||
auto destinationNode = getAINode(destination);
|
||||
|
||||
for(const AIPathNode & node : chains)
|
||||
{
|
||||
auto sameNode = node.chainMask == destinationNode->chainMask;
|
||||
if(sameNode || node.action == CGPathNode::ENodeAction::UNKNOWN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(node.danger <= destinationNode->danger && destinationNode->chainMask == 1 && node.chainMask == 0)
|
||||
{
|
||||
if(node.turns < destinationNode->turns
|
||||
|| node.turns == destinationNode->turns && node.moveRemains >= destinationNode->moveRemains)
|
||||
{
|
||||
logAi->trace(
|
||||
"Block ineficient move %s:->%s, mask=%i, mp diff: %i",
|
||||
source.coord.toString(),
|
||||
destination.coord.toString(),
|
||||
destinationNode->chainMask,
|
||||
node.moveRemains - destinationNode->moveRemains);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<AIPath> AINodeStorage::getChainInfo(int3 pos)
|
||||
{
|
||||
std::vector<AIPath> paths;
|
||||
auto chains = nodes[pos.x][pos.y][pos.z][EPathfindingLayer::LAND];
|
||||
|
||||
for(const AIPathNode & node : chains)
|
||||
{
|
||||
if(node.action == CGPathNode::ENodeAction::UNKNOWN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AIPath path;
|
||||
const AIPathNode * current = &node;
|
||||
|
||||
while(current != nullptr)
|
||||
{
|
||||
AIPathNodeInfo pathNode;
|
||||
|
||||
pathNode.movementPointsLeft = current->moveRemains;
|
||||
pathNode.movementPointsUsed = (int)(current->turns * hero->maxMovePoints(true) + hero->movement) - (int)current->moveRemains;
|
||||
pathNode.turns = current->turns;
|
||||
pathNode.danger = current->danger;
|
||||
pathNode.coord = current->coord;
|
||||
|
||||
path.nodes.push_back(pathNode);
|
||||
current = getAINode(current->theNodeBefore);
|
||||
}
|
||||
paths.push_back(path);
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
AIPath::AIPath()
|
||||
: nodes({})
|
||||
{
|
||||
}
|
||||
|
||||
int3 AIPath::firstTileToGet() const
|
||||
{
|
||||
if(nodes.size())
|
||||
{
|
||||
return nodes.back().coord;
|
||||
}
|
||||
|
||||
return int3(-1, -1, -1);
|
||||
}
|
||||
|
||||
uint64_t AIPath::getPathDanger() const
|
||||
{
|
||||
if(nodes.size())
|
||||
{
|
||||
return nodes.front().danger;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t AIPath::movementCost() const
|
||||
{
|
||||
if(nodes.size())
|
||||
{
|
||||
return nodes.front().movementPointsUsed;
|
||||
}
|
||||
|
||||
// TODO: boost:optional?
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t AIPath::getTotalDanger(HeroPtr hero) const
|
||||
{
|
||||
uint64_t pathDanger = getPathDanger();
|
||||
uint64_t objDanger = evaluateDanger(nodes.front().coord, hero.get()); // bank danger is not checked by pathfinder
|
||||
uint64_t danger = pathDanger > objDanger ? pathDanger : objDanger;
|
||||
|
||||
return danger;
|
||||
}
|
||||
Reference in New Issue
Block a user