1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-29 23:07:48 +02:00

NKAI: reduce double army loss cases

This commit is contained in:
Andrii Danylchenko
2024-07-18 13:37:18 +03:00
parent 73ea0ce7bc
commit 37dc2a38e8
5 changed files with 73 additions and 16 deletions

View File

@@ -26,7 +26,12 @@ ExecuteHeroChain::ExecuteHeroChain(const AIPath & path, const CGObjectInstance *
if(obj) if(obj)
{ {
objid = obj->id.getNum(); objid = obj->id.getNum();
#if NKAI_TRACE_LEVEL >= 1
targetName = obj->getObjectName() + tile.toString();
#else
targetName = obj->typeName + tile.toString(); targetName = obj->typeName + tile.toString();
#endif
} }
else else
{ {
@@ -260,7 +265,11 @@ void ExecuteHeroChain::accept(AIGateway * ai)
std::string ExecuteHeroChain::toString() const std::string ExecuteHeroChain::toString() const
{ {
#if NKAI_TRACE_LEVEL >= 1
return "ExecuteHeroChain " + targetName + " by " + chainPath.toString();
#else
return "ExecuteHeroChain " + targetName + " by " + chainPath.targetHero->getNameTranslated(); return "ExecuteHeroChain " + targetName + " by " + chainPath.targetHero->getNameTranslated();
#endif
} }
bool ExecuteHeroChain::moveHeroToTile(AIGateway * ai, const CGHeroInstance * hero, const int3 & tile) bool ExecuteHeroChain::moveHeroToTile(AIGateway * ai, const CGHeroInstance * hero, const int3 & tile)

View File

@@ -1385,6 +1385,28 @@ void AINodeStorage::calculateChainInfo(std::vector<AIPath> & paths, const int3 &
path.armyLoss = node.armyLoss; path.armyLoss = node.armyLoss;
path.targetObjectDanger = evaluateDanger(pos, path.targetHero, !node.actor->allowBattle); path.targetObjectDanger = evaluateDanger(pos, path.targetHero, !node.actor->allowBattle);
if(path.targetObjectDanger > 0)
{
if(node.theNodeBefore)
{
auto prevNode = getAINode(node.theNodeBefore);
if(node.coord == prevNode->coord && node.actor->hero == prevNode->actor->hero)
{
paths.pop_back();
continue;
}
else
{
path.armyLoss = prevNode->armyLoss;
}
}
else
{
path.armyLoss = 0;
}
}
path.targetObjectArmyLoss = evaluateArmyLoss( path.targetObjectArmyLoss = evaluateArmyLoss(
path.targetHero, path.targetHero,
getHeroArmyStrengthWithCommander(path.targetHero, path.heroArmy), getHeroArmyStrengthWithCommander(path.targetHero, path.heroArmy),

View File

@@ -160,7 +160,7 @@ void GraphPaths::dumpToLog() const
node.previous.coord.toString(), node.previous.coord.toString(),
tile.first.toString(), tile.first.toString(),
node.cost, node.cost,
node.danger); node.linkDanger);
} }
logBuilder.addLine(node.previous.coord, tile.first); logBuilder.addLine(node.previous.coord, tile.first);
@@ -169,14 +169,17 @@ void GraphPaths::dumpToLog() const
}); });
} }
bool GraphPathNode::tryUpdate(const GraphPathNodePointer & pos, const GraphPathNode & prev, const ObjectLink & link) bool GraphPathNode::tryUpdate(
const GraphPathNodePointer & pos,
const GraphPathNode & prev,
const ObjectLink & link)
{ {
auto newCost = prev.cost + link.cost; auto newCost = prev.cost + link.cost;
if(newCost < cost) if(newCost < cost)
{ {
previous = pos; previous = pos;
danger = prev.danger + link.danger; linkDanger = link.danger;
cost = newCost; cost = newCost;
return true; return true;
@@ -199,7 +202,7 @@ void GraphPaths::addChainInfo(std::vector<AIPath> & paths, int3 tile, const CGHe
std::vector<GraphPathNodePointer> tilesToPass; std::vector<GraphPathNodePointer> tilesToPass;
uint64_t danger = node.danger; uint64_t danger = node.linkDanger;
float cost = node.cost; float cost = node.cost;
bool allowBattle = false; bool allowBattle = false;
@@ -212,13 +215,13 @@ void GraphPaths::addChainInfo(std::vector<AIPath> & paths, int3 tile, const CGHe
if(currentTile == pathNodes.end()) if(currentTile == pathNodes.end())
break; break;
auto currentNode = currentTile->second[current.nodeType]; auto & currentNode = currentTile->second[current.nodeType];
if(!currentNode.previous.valid()) if(!currentNode.previous.valid())
break; break;
allowBattle = allowBattle || currentNode.nodeType == GrapthPathNodeType::BATTLE; allowBattle = allowBattle || currentNode.nodeType == GrapthPathNodeType::BATTLE;
vstd::amax(danger, currentNode.danger); vstd::amax(danger, currentNode.linkDanger);
vstd::amax(cost, currentNode.cost); vstd::amax(cost, currentNode.cost);
tilesToPass.push_back(current); tilesToPass.push_back(current);
@@ -239,9 +242,13 @@ void GraphPaths::addChainInfo(std::vector<AIPath> & paths, int3 tile, const CGHe
if(path.targetHero != hero) if(path.targetHero != hero)
continue; continue;
for(auto graphTile = tilesToPass.rbegin(); graphTile != tilesToPass.rend(); graphTile++) uint64_t loss = 0;
uint64_t strength = getHeroArmyStrengthWithCommander(path.targetHero, path.heroArmy);
for(auto graphTile = ++tilesToPass.rbegin(); graphTile != tilesToPass.rend(); graphTile++)
{ {
AIPathNodeInfo n; AIPathNodeInfo n;
auto & node = getNode(*graphTile);
n.coord = graphTile->coord; n.coord = graphTile->coord;
n.cost = cost; n.cost = cost;
@@ -249,7 +256,21 @@ void GraphPaths::addChainInfo(std::vector<AIPath> & paths, int3 tile, const CGHe
n.danger = danger; n.danger = danger;
n.targetHero = hero; n.targetHero = hero;
n.parentIndex = -1; n.parentIndex = -1;
n.specialAction = getNode(*graphTile).specialAction; n.specialAction = node.specialAction;
if(node.linkDanger > 0)
{
auto additionalLoss = ai->pathfinder->getStorage()->evaluateArmyLoss(path.targetHero, strength, node.linkDanger);
loss += additionalLoss;
if(strength > additionalLoss)
strength -= additionalLoss;
else
{
strength = 0;
break;
}
}
if(n.specialAction) if(n.specialAction)
{ {
@@ -264,7 +285,12 @@ void GraphPaths::addChainInfo(std::vector<AIPath> & paths, int3 tile, const CGHe
path.nodes.insert(path.nodes.begin(), n); path.nodes.insert(path.nodes.begin(), n);
} }
path.armyLoss += ai->pathfinder->getStorage()->evaluateArmyLoss(path.targetHero, path.heroArmy->getArmyStrength(), danger); if(strength == 0)
{
continue;
}
path.armyLoss += loss;
path.targetObjectDanger = ai->pathfinder->getStorage()->evaluateDanger(tile, path.targetHero, !allowBattle); path.targetObjectDanger = ai->pathfinder->getStorage()->evaluateDanger(tile, path.targetHero, !allowBattle);
path.targetObjectArmyLoss = ai->pathfinder->getStorage()->evaluateArmyLoss(path.targetHero, path.heroArmy->getArmyStrength(), path.targetObjectDanger); path.targetObjectArmyLoss = ai->pathfinder->getStorage()->evaluateArmyLoss(path.targetHero, path.heroArmy->getArmyStrength(), path.targetObjectDanger);
@@ -287,7 +313,7 @@ void GraphPaths::quickAddChainInfoWithBlocker(std::vector<AIPath> & paths, int3
std::vector<GraphPathNodePointer> tilesToPass; std::vector<GraphPathNodePointer> tilesToPass;
uint64_t danger = targetNode.danger; uint64_t danger = targetNode.linkDanger;
float cost = targetNode.cost; float cost = targetNode.cost;
bool allowBattle = false; bool allowBattle = false;
@@ -303,7 +329,7 @@ void GraphPaths::quickAddChainInfoWithBlocker(std::vector<AIPath> & paths, int3
auto currentNode = currentTile->second[current.nodeType]; auto currentNode = currentTile->second[current.nodeType];
allowBattle = allowBattle || currentNode.nodeType == GrapthPathNodeType::BATTLE; allowBattle = allowBattle || currentNode.nodeType == GrapthPathNodeType::BATTLE;
vstd::amax(danger, currentNode.danger); vstd::amax(danger, currentNode.linkDanger);
vstd::amax(cost, currentNode.cost); vstd::amax(cost, currentNode.cost);
tilesToPass.push_back(current); tilesToPass.push_back(current);
@@ -341,7 +367,7 @@ void GraphPaths::quickAddChainInfoWithBlocker(std::vector<AIPath> & paths, int3
// final node // final node
n.coord = tile; n.coord = tile;
n.cost = targetNode.cost; n.cost = targetNode.cost;
n.danger = targetNode.danger; n.danger = danger;
n.parentIndex = path.nodes.size(); n.parentIndex = path.nodes.size();
path.nodes.push_back(n); path.nodes.push_back(n);
@@ -368,7 +394,7 @@ void GraphPaths::quickAddChainInfoWithBlocker(std::vector<AIPath> & paths, int3
n.coord = graphTile->coord; n.coord = graphTile->coord;
n.cost = node.cost; n.cost = node.cost;
n.turns = static_cast<ui8>(node.cost); n.turns = static_cast<ui8>(node.cost);
n.danger = node.danger; n.danger = danger;
n.specialAction = node.specialAction; n.specialAction = node.specialAction;
n.parentIndex = path.nodes.size(); n.parentIndex = path.nodes.size();

View File

@@ -67,7 +67,7 @@ struct GraphPathNode
GrapthPathNodeType nodeType = GrapthPathNodeType::NORMAL; GrapthPathNodeType nodeType = GrapthPathNodeType::NORMAL;
GraphPathNodePointer previous; GraphPathNodePointer previous;
float cost = BAD_COST; float cost = BAD_COST;
uint64_t danger = 0; uint64_t linkDanger = 0;
const CGObjectInstance * obj = nullptr; const CGObjectInstance * obj = nullptr;
std::shared_ptr<SpecialAction> specialAction; std::shared_ptr<SpecialAction> specialAction;

View File

@@ -89,7 +89,7 @@ void ClientCommandManager::handleGoSoloCommand()
// unlikely it will work but just in case to be consistent // unlikely it will work but just in case to be consistent
for(auto & color : CSH->getAllClientPlayers(CSH->logicConnection->connectionID)) for(auto & color : CSH->getAllClientPlayers(CSH->logicConnection->connectionID))
{ {
if(CSH->client->getStartInfo()->playerInfos.at(color).isControlledByHuman()) if(color.isValidPlayer() && CSH->client->getStartInfo()->playerInfos.at(color).isControlledByHuman())
{ {
CSH->client->installNewPlayerInterface(std::make_shared<CPlayerInterface>(color), color); CSH->client->installNewPlayerInterface(std::make_shared<CPlayerInterface>(color), color);
} }
@@ -102,7 +102,7 @@ void ClientCommandManager::handleGoSoloCommand()
for(auto & color : CSH->getAllClientPlayers(CSH->logicConnection->connectionID)) for(auto & color : CSH->getAllClientPlayers(CSH->logicConnection->connectionID))
{ {
if(CSH->client->getStartInfo()->playerInfos.at(color).isControlledByHuman()) if(color.isValidPlayer() && CSH->client->getStartInfo()->playerInfos.at(color).isControlledByHuman())
{ {
auto AiToGive = CSH->client->aiNameForPlayer(*CSH->client->getPlayerSettings(color), false, false); auto AiToGive = CSH->client->aiNameForPlayer(*CSH->client->getPlayerSettings(color), false, false);
printCommandMessage("Player " + color.toString() + " will be lead by " + AiToGive, ELogLevel::INFO); printCommandMessage("Player " + color.toString() + " will be lead by " + AiToGive, ELogLevel::INFO);