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:
parent
5ec3685041
commit
473250e223
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()));
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user