mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
- Significantly improved exploration algorithm
- Workaround to make AI gather army when exploration is not possible anymore - Possibly fixed issue with AI not capturing guarded objects
This commit is contained in:
parent
a9b10c8099
commit
d17b3a14bd
@ -471,6 +471,13 @@ float FuzzyHelper::evaluate (Goals::VisitHero & g)
|
|||||||
g.setpriority(Goals::VisitTile(obj->visitablePos()).sethero(g.hero).setisAbstract(g.isAbstract).accept(this));
|
g.setpriority(Goals::VisitTile(obj->visitablePos()).sethero(g.hero).setisAbstract(g.isAbstract).accept(this));
|
||||||
return g.priority;
|
return g.priority;
|
||||||
}
|
}
|
||||||
|
float FuzzyHelper::evaluate (Goals::GatherArmy & g)
|
||||||
|
{
|
||||||
|
//the more army we need, the more important goal
|
||||||
|
//the more army we lack, the less important goal
|
||||||
|
float army = g.hero->getArmyStrength();
|
||||||
|
return g.value / std::min(g.value - army, 1000.0f);
|
||||||
|
}
|
||||||
float FuzzyHelper::evaluate (Goals::BuildThis & g)
|
float FuzzyHelper::evaluate (Goals::BuildThis & g)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -66,6 +66,7 @@ public:
|
|||||||
float evaluate (Goals::DigAtTile & g);
|
float evaluate (Goals::DigAtTile & g);
|
||||||
float evaluate (Goals::CollectRes & g);
|
float evaluate (Goals::CollectRes & g);
|
||||||
float evaluate (Goals::Build & g);
|
float evaluate (Goals::Build & g);
|
||||||
|
float evaluate (Goals::GatherArmy & g);
|
||||||
float evaluate (Goals::Invalid & g);
|
float evaluate (Goals::Invalid & g);
|
||||||
float evaluate (Goals::AbstractGoal & g);
|
float evaluate (Goals::AbstractGoal & g);
|
||||||
void setPriority (Goals::TSubgoal & g);
|
void setPriority (Goals::TSubgoal & g);
|
||||||
|
@ -522,15 +522,26 @@ TGoalVec Explore::getAllPossibleSubgoals()
|
|||||||
if ((!hero || ret.empty()) && ai->canRecruitAnyHero())
|
if ((!hero || ret.empty()) && ai->canRecruitAnyHero())
|
||||||
ret.push_back (sptr(Goals::RecruitHero()));
|
ret.push_back (sptr(Goals::RecruitHero()));
|
||||||
|
|
||||||
if (!hero && ret.empty())
|
if (ret.empty())
|
||||||
{
|
{
|
||||||
auto h = ai->primaryHero(); //we may need to gather big army to break!
|
HeroPtr h;
|
||||||
|
if (hero) //there is some hero set and it's us
|
||||||
|
{
|
||||||
|
if (hero == ai->primaryHero())
|
||||||
|
h = hero;
|
||||||
|
}
|
||||||
|
else //no hero is set, so we choose our main
|
||||||
|
h = ai->primaryHero();
|
||||||
|
//we may need to gather big army to break!
|
||||||
if (h.h)
|
if (h.h)
|
||||||
{
|
{
|
||||||
//FIXME: it never finds anything :?
|
//FIXME: it never finds anything :?
|
||||||
int3 t = ai->explorationNewPoint(h->getSightRadious(), h, true);
|
int3 t = ai->explorationNewPoint(h->getSightRadious(), h, true);
|
||||||
if (cb->isInTheMap(t))
|
if (cb->isInTheMap(t))
|
||||||
ret.push_back (sptr(ClearWayTo(t).setisAbstract(true).sethero(h)));
|
ret.push_back (sptr(ClearWayTo(t).setisAbstract(true).sethero(h)));
|
||||||
|
else //just in case above fails - gather army if no further exploration possible
|
||||||
|
ret.push_back (sptr(GatherArmy(h->getArmyStrength() + 1).sethero(h)));
|
||||||
|
//do not set abstract to keep our hero free once he gets reinforcements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ret.empty())
|
if (ret.empty())
|
||||||
|
@ -1239,6 +1239,12 @@ bool VCAI::canRecruitAnyHero (const CGTownInstance * t) const
|
|||||||
|
|
||||||
void VCAI::wander(HeroPtr h)
|
void VCAI::wander(HeroPtr h)
|
||||||
{
|
{
|
||||||
|
//unclaim objects that are now dangerous for us
|
||||||
|
erase_if(reservedHeroesMap[h], [h](const CGObjectInstance * obj) -> bool
|
||||||
|
{
|
||||||
|
return !isSafeToVisit(h, obj->visitablePos());
|
||||||
|
});
|
||||||
|
|
||||||
TimeCheck tc("looking for wander destination");
|
TimeCheck tc("looking for wander destination");
|
||||||
|
|
||||||
while (h->movement)
|
while (h->movement)
|
||||||
@ -1907,8 +1913,7 @@ Goals::TSubgoal VCAI::striveToGoalInternal(Goals::TSubgoal ultimateGoal, bool on
|
|||||||
{
|
{
|
||||||
Goals::TSubgoal goal = ultimateGoal;
|
Goals::TSubgoal goal = ultimateGoal;
|
||||||
logAi->debugStream() << boost::format("Striving to goal of type %s") % ultimateGoal->name();
|
logAi->debugStream() << boost::format("Striving to goal of type %s") % ultimateGoal->name();
|
||||||
int maxGoals = 100; //preventing deadlock for mutually dependent goals
|
int maxGoals = 30; //preventing deadlock for mutually dependent goals
|
||||||
//FIXME: do not try to realize goal when loop didn't suceed
|
|
||||||
while(!goal->isElementar && maxGoals && (onlyAbstract || !goal->isAbstract))
|
while(!goal->isElementar && maxGoals && (onlyAbstract || !goal->isAbstract))
|
||||||
{
|
{
|
||||||
logAi->debugStream() << boost::format("Considering goal %s") % goal->name();
|
logAi->debugStream() << boost::format("Considering goal %s") % goal->name();
|
||||||
@ -1970,7 +1975,7 @@ Goals::TSubgoal VCAI::striveToGoalInternal(Goals::TSubgoal ultimateGoal, bool on
|
|||||||
catch(goalFulfilledException &e)
|
catch(goalFulfilledException &e)
|
||||||
{
|
{
|
||||||
completeGoal (goal);
|
completeGoal (goal);
|
||||||
if (ultimateGoal->fulfillsMe(goal) || maxGoals > 98) //completed goal was main goal //TODO: find better condition
|
if (ultimateGoal->fulfillsMe(goal) || maxGoals > 28) //completed goal was main goal //TODO: find better condition
|
||||||
return sptr(Goals::Invalid());
|
return sptr(Goals::Invalid());
|
||||||
}
|
}
|
||||||
catch(std::exception &e)
|
catch(std::exception &e)
|
||||||
@ -2172,7 +2177,7 @@ int3 VCAI::explorationBestNeighbour(int3 hpos, int radius, HeroPtr h)
|
|||||||
|
|
||||||
int3 VCAI::explorationNewPoint(int radius, HeroPtr h, bool breakUnsafe)
|
int3 VCAI::explorationNewPoint(int radius, HeroPtr h, bool breakUnsafe)
|
||||||
{
|
{
|
||||||
logAi->debugStream() << "Looking for an another place for exploration...";
|
//logAi->debugStream() << "Looking for an another place for exploration...";
|
||||||
cb->setSelection(h.h);
|
cb->setSelection(h.h);
|
||||||
|
|
||||||
std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
|
std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
|
||||||
@ -2184,7 +2189,7 @@ int3 VCAI::explorationNewPoint(int radius, HeroPtr h, bool breakUnsafe)
|
|||||||
tiles[0].push_back(pos);
|
tiles[0].push_back(pos);
|
||||||
});
|
});
|
||||||
|
|
||||||
int bestValue = 0;
|
float bestValue = 0; //discovered tile to node distance ratio
|
||||||
int3 bestTile(-1,-1,-1);
|
int3 bestTile(-1,-1,-1);
|
||||||
|
|
||||||
for (int i = 1; i < radius; i++)
|
for (int i = 1; i < radius; i++)
|
||||||
@ -2196,10 +2201,16 @@ int3 VCAI::explorationNewPoint(int radius, HeroPtr h, bool breakUnsafe)
|
|||||||
{
|
{
|
||||||
if (cb->getTile(tile)->blocked) //does it shorten the time?
|
if (cb->getTile(tile)->blocked) //does it shorten the time?
|
||||||
continue;
|
continue;
|
||||||
int ourValue = howManyTilesWillBeDiscovered(tile, radius);
|
if (!cb->getPathInfo(tile)->reachable())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CGPath path;
|
||||||
|
cb->getPath2(tile, path);
|
||||||
|
float ourValue = (float)howManyTilesWillBeDiscovered(tile, radius) / (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
|
||||||
{
|
{
|
||||||
if(cb->getPathInfo(tile)->reachable() && (isSafeToVisit(h, tile) || breakUnsafe) && !isBlockedBorderGate(tile))
|
if((isSafeToVisit(h, tile) || breakUnsafe) && !isBlockedBorderGate(tile))
|
||||||
{
|
{
|
||||||
bestTile = tile; //return first tile that will discover anything
|
bestTile = tile; //return first tile that will discover anything
|
||||||
bestValue = ourValue;
|
bestValue = ourValue;
|
||||||
|
Loading…
Reference in New Issue
Block a user