1
0
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:
DjWarmonger 2014-02-07 20:09:15 +00:00
parent a9b10c8099
commit d17b3a14bd
4 changed files with 40 additions and 10 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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())

View File

@ -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;