1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

- Removed slow and buggy part of exploration code

- Various tweaks and performance improvements. remove_if on long vector is a bad idea.
This commit is contained in:
DjWarmonger 2013-12-21 17:34:59 +00:00
parent 5ec3685041
commit 473250e223
5 changed files with 53 additions and 76 deletions

View File

@ -184,12 +184,12 @@ bool compareDanger(const CGObjectInstance *lhs, const CGObjectInstance *rhs)
bool isSafeToVisit(HeroPtr h, crint3 tile)
{
const ui64 heroStrength = h->getTotalStrength(),
dangerStrength = evaluateDanger(tile, *h);
dangerStrength = evaluateDanger(tile, *h);
if(dangerStrength)
{
if(heroStrength / SAFE_ATTACK_CONSTANT > dangerStrength)
{
logAi->debugStream() << boost::format("It's, safe for %s to visit tile %s") % h->name % tile;
logAi->traceStream() << boost::format("It's safe for %s to visit tile %s") % h->name % tile;
return true;
}
else
@ -240,28 +240,7 @@ int3 whereToExplore(HeroPtr h)
catch(cannotFulfillGoalException &e)
{
std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
try
{
return ai->explorationNewPoint(radius, h, tiles);
}
catch(cannotFulfillGoalException &e)
{
std::map<int, std::vector<int3> > profits;
{
TimeCheck tc("Evaluating exploration possibilities");
tiles[0].clear(); //we can't reach FoW anyway
for(auto &vt : tiles)
for(auto &tile : vt)
profits[howManyTilesWillBeDiscovered(tile, radius)].push_back(tile);
}
if(profits.empty())
return int3 (-1,-1,-1);
auto bestDest = profits.end();
bestDest--;
return bestDest->second.front(); //TODO which is the real best tile?
}
return ai->explorationNewPoint(radius, h, tiles);
}
}

View File

@ -351,7 +351,7 @@ void FuzzyHelper::initVisitTile()
helper += vt.strengthRatio, vt.heroStrength, vt.tileDistance, vt.missionImportance;
vt.strengthRatio->addTerm (new fl::ShoulderTerm("LOW", 0.3, SAFE_ATTACK_CONSTANT, true));
vt.strengthRatio->addTerm (new fl::ShoulderTerm("LOW", 0.9, SAFE_ATTACK_CONSTANT, true));
vt.strengthRatio->addTerm (new fl::ShoulderTerm("HIGH", SAFE_ATTACK_CONSTANT, SAFE_ATTACK_CONSTANT * 3, false));
vt.heroStrength->addTerm (new fl::ShoulderTerm("LOW", 1, 2500, true)); //assumed strength of new hero from tavern
@ -378,6 +378,8 @@ void FuzzyHelper::initVisitTile()
//vt.rules.addRule (new fl::MamdaniRule("if OurShooters is MANY and EnemySpeed is LOW then Threat is very LOW", engine));
//use unarmed scouts if possible
vt.rules.addRule (new fl::MamdaniRule("if strengthRatio is HIGH and heroStrength is LOW then Value is very HIGH", engine));
//don't assign targets to heroes who are too weak
vt.rules.addRule (new fl::MamdaniRule("if strengthRatio is very LOW then Value is very LOW", engine));
//if medium heroes can't scratch enemy, don't try to arm them
vt.rules.addRule (new fl::MamdaniRule("if strengthRatio is LOW and heroStrength is MEDIUM then Value is LOW", engine));
//do not cancel important goals

View File

@ -273,9 +273,13 @@ TSubgoal VisitHero::whatToDoToAchieve()
if (hero && ai->isAccessibleForHero(pos, hero, true) && isSafeToVisit(hero, pos)) //enemy heroes can get reinforcements
{
assert (hero->pos != pos); //don't try to visit yourself
settile(pos).setisElementar(true);
return sptr (*this);
if (hero->pos == pos)
logAi->errorStream() << "Hero " << hero.name << " tries to visit himself.";
else
{
settile(pos).setisElementar(true);
return sptr (*this);
}
}
return sptr (Goals::Invalid());
}
@ -395,28 +399,22 @@ TGoalVec Explore::getAllPossibleSubgoals()
});
}
auto objs = ai->visitableObjs; //try to use buildings that uncover map
erase_if(objs, [&](const CGObjectInstance *obj) -> bool
//try to use buildings that uncover map
std::vector<const CGObjectInstance *> objs;
for (auto obj : ai->visitableObjs)
{
if (vstd::contains(ai->alreadyVisited, obj))
return true;
switch (obj->ID.num)
if (!vstd::contains(ai->alreadyVisited, obj))
{
case Obj::REDWOOD_OBSERVATORY:
case Obj::PILLAR_OF_FIRE:
case Obj::CARTOGRAPHER:
case Obj::SUBTERRANEAN_GATE: //TODO: check ai->knownSubterraneanGates
//case Obj::MONOLITH1:
//case obj::MONOLITH2:
//case obj::MONOLITH3:
//case Obj::WHIRLPOOL:
return false; //do not erase
break;
default:
return true;
switch (obj->ID.num)
{
case Obj::REDWOOD_OBSERVATORY:
case Obj::PILLAR_OF_FIRE:
case Obj::CARTOGRAPHER:
case Obj::SUBTERRANEAN_GATE: //TODO: check ai->knownSubterraneanGates
objs.push_back (obj);
}
}
});
}
for (auto h : heroes)
{
for (auto obj : objs) //double loop, performance risk?
@ -428,8 +426,8 @@ TGoalVec Explore::getAllPossibleSubgoals()
}
int3 t = whereToExplore(h);
if (t.z != -1) //no safe tile to explore - we need to break!
ret.push_back (sptr (Goals::VisitTile(t).sethero(h)));
if (t.z != -1) //no valid tile was found
ret.push_back (sptr (Goals::VisitTile(t).sethero(h)));
}
if (!hero && ai->canRecruitAnyHero())//if hero is assigned to that goal, no need to buy another one yet
ret.push_back (sptr(Goals::RecruitHero()));

View File

@ -1096,36 +1096,31 @@ std::vector<const CGObjectInstance *> VCAI::getPossibleDestinations(HeroPtr h)
std::vector<const CGObjectInstance *> possibleDestinations;
for(const CGObjectInstance *obj : visitableObjs)
{
if(isAccessibleForHero(obj->visitablePos(), h) && !obj->wasVisited(playerID) &&
(obj->tempOwner != playerID || isWeeklyRevisitable(obj))) //flag or get weekly resources / creatures
const int3 pos = obj->visitablePos();
if (isAccessibleForHero(obj->visitablePos(), h) &&
!obj->wasVisited(playerID) &&
(obj->tempOwner != playerID || isWeeklyRevisitable(obj)) && //flag or get weekly resources / creatures
isSafeToVisit(h, pos) &&
shouldVisit(h, obj) &&
!vstd::contains(alreadyVisited, obj) &&
!vstd::contains(reservedObjs, obj))
{
possibleDestinations.push_back(obj);
}
}
boost::sort(possibleDestinations, isCloser);
possibleDestinations.erase(boost::remove_if(possibleDestinations, [&](const CGObjectInstance *obj) -> bool
{
const int3 pos = obj->visitablePos();
if(vstd::contains(alreadyVisited, obj))
return true;
if(!isSafeToVisit(h, pos))
return true;
if (!shouldVisit(h, obj))
return true;
if (vstd::contains(reservedObjs, obj)) //does checking for our own reserved objects make sense? here?
return true;
const CGObjectInstance *topObj = cb->getVisitableObjs(pos).back(); //it may be hero visiting this obj
const CGObjectInstance *topObj = cb->getVisitableObjs(obj->visitablePos()).back(); //it may be hero visiting this obj
//we don't try visiting object on which allied or owned hero stands
// -> it will just trigger exchange windows and AI will be confused that obj behind doesn't get visited
if(topObj->ID == Obj::HERO && cb->getPlayerRelations(h->tempOwner, topObj->tempOwner) != PlayerRelations::ENEMIES)
return true;
return false;
}),possibleDestinations.end());
}), possibleDestinations.end());
boost::sort(possibleDestinations, isCloser);
return possibleDestinations;
}
@ -2004,12 +1999,11 @@ int3 VCAI::explorationBestNeighbour(int3 hpos, int radius, HeroPtr h)
std::map<int3, int> dstToRevealedTiles;
for(crint3 dir : dirs)
if(cb->isInTheMap(hpos+dir))
dstToRevealedTiles[hpos + dir] = howManyTilesWillBeDiscovered(radius, hpos, dir) * isSafeToVisit(h, hpos + dir);
if (isSafeToVisit(h, hpos + dir) && isAccessibleForHero (hpos + dir, h))
dstToRevealedTiles[hpos + dir] = howManyTilesWillBeDiscovered(radius, hpos, dir);
auto best = dstToRevealedTiles.begin();
best->second *= cb->getPathInfo(best->first)->reachable();
best->second *= cb->getPathInfo(best->first)->accessible == CGPathNode::ACCESSIBLE;
for(auto i = dstToRevealedTiles.begin(); i != dstToRevealedTiles.end(); i++)
for (auto i = dstToRevealedTiles.begin(); i != dstToRevealedTiles.end(); i++)
{
const CGPathNode *pn = cb->getPathInfo(i->first);
//const TerrainTile *t = cb->getTile(i->first);
@ -2042,13 +2036,17 @@ int3 VCAI::explorationNewPoint(int radius, HeroPtr h, std::vector<std::vector<in
for(const int3 &tile : tiles[i])
{
if(cb->getPathInfo(tile)->reachable() && isSafeToVisit(h, tile) && howManyTilesWillBeDiscovered(tile, radius) && !isBlockedBorderGate(tile))
if (cb->getTile(tile)->blocked) //does it shorten the time?
continue;
if(cb->getPathInfo(tile)->reachable() && howManyTilesWillBeDiscovered(tile, radius) &&
isSafeToVisit(h, tile) && !isBlockedBorderGate(tile))
{
return tile;
return tile; //return first tile that will discover anything
}
}
}
throw cannotFulfillGoalException("No accessible tile will bring discoveries!");
return int3 (-1,-1,-1);
//throw cannotFulfillGoalException("No accessible tile will bring discoveries!");
}
TResources VCAI::estimateIncome() const

View File

@ -354,7 +354,6 @@ public:
void checkForObjectives();
ui32 checksum;
/// a 3-dimensional array of terrain tiles, access is as follows: x, y, level. where level=1 is underground
std::vector<Rumor> rumors;
std::vector<DisposedHero> disposedHeroes;
std::vector<ConstTransitivePtr<CGHeroInstance> > predefinedHeroes;
@ -383,6 +382,7 @@ public:
unique_ptr<CMapEditManager> editManager;
private:
/// a 3-dimensional array of terrain tiles, access is as follows: x, y, level. where level=1 is underground
TerrainTile*** terrain;
public: